mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into 2803-open-contribution-edit-button
This commit is contained in:
commit
2ac94e1b47
3
.github/file-filters.yml
vendored
3
.github/file-filters.yml
vendored
@ -41,3 +41,6 @@ federation: &federation
|
||||
|
||||
frontend: &frontend
|
||||
- 'frontend/**/*'
|
||||
|
||||
nginx: &nginx
|
||||
- 'nginx/**/*'
|
||||
32
.github/workflows/test-nginx.yml
vendored
Normal file
32
.github/workflows/test-nginx.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: Gradido Nginx Test CI
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Detect File Changes - Nginx
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
nginx: ${{ steps.changes.outputs.nginx }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
|
||||
- name: Check for nginx file changes
|
||||
uses: dorny/paths-filter@v2.11.1
|
||||
id: changes
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-filters.yml
|
||||
list-files: shell
|
||||
|
||||
build_test_nginx:
|
||||
name: Docker Build Test - Nginx
|
||||
if: needs.files-changed.outputs.nginx == 'true'
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: nginx | Build 'test' image
|
||||
run: docker build -t "gradido/nginx:test" nginx/
|
||||
25
.github/workflows/test.yml
vendored
25
.github/workflows/test.yml
vendored
@ -81,31 +81,6 @@ jobs:
|
||||
name: docker-mariadb-test
|
||||
path: /tmp/mariadb.tar
|
||||
|
||||
##############################################################################
|
||||
# JOB: DOCKER BUILD TEST NGINX ###############################################
|
||||
##############################################################################
|
||||
build_test_nginx:
|
||||
name: Docker Build Test - Nginx
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# BUILD NGINX DOCKER IMAGE ###############################################
|
||||
##########################################################################
|
||||
- name: nginx | Build `test` image
|
||||
run: |
|
||||
docker build -t "gradido/nginx:test" nginx/
|
||||
docker save "gradido/nginx:test" > /tmp/nginx.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-nginx-test
|
||||
path: /tmp/nginx.tar
|
||||
|
||||
##############################################################################
|
||||
# JOB: LINT BACKEND ##########################################################
|
||||
##############################################################################
|
||||
|
||||
@ -76,7 +76,11 @@ git clone git@github.com:gradido/gradido.git
|
||||
git submodule update --recursive --init
|
||||
```
|
||||
|
||||
### 2. Run docker-compose
|
||||
### 2. Install modules
|
||||
|
||||
You can go in each under folder (admin, frontend, database, backend, ...) and call ``yarn`` in each folder or you can call ``yarn installAll``.
|
||||
|
||||
### 3. Run docker-compose
|
||||
|
||||
Run docker-compose to bring up the development environment
|
||||
|
||||
|
||||
@ -1,43 +1,75 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import CreationTransactionList from './CreationTransactionList'
|
||||
import { toastErrorSpy } from '../../test/testSetup'
|
||||
import VueApollo from 'vue-apollo'
|
||||
import { createMockClient } from 'mock-apollo-client'
|
||||
import { adminListContributions } from '../graphql/adminListContributions'
|
||||
|
||||
const mockClient = createMockClient()
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: mockClient,
|
||||
})
|
||||
|
||||
const localVue = global.localVue
|
||||
localVue.use(VueApollo)
|
||||
|
||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
creationTransactionList: {
|
||||
const defaultData = () => {
|
||||
return {
|
||||
adminListContributions: {
|
||||
contributionCount: 2,
|
||||
contributionList: [
|
||||
{
|
||||
id: 1,
|
||||
amount: 5.8,
|
||||
createdAt: '2022-09-21T11:09:51.000Z',
|
||||
confirmedAt: null,
|
||||
contributionDate: '2022-08-01T00:00:00.000Z',
|
||||
memo: 'für deine Hilfe, Fräulein Rottenmeier',
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
userId: 99,
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 500,
|
||||
memo: 'Danke für alles',
|
||||
date: new Date(),
|
||||
moderator: 1,
|
||||
state: 'PENDING',
|
||||
creation: [500, 500, 500],
|
||||
messagesCount: 0,
|
||||
deniedBy: null,
|
||||
deniedAt: null,
|
||||
confirmedBy: null,
|
||||
confirmedAt: null,
|
||||
contributionDate: new Date(),
|
||||
deletedBy: null,
|
||||
deletedAt: null,
|
||||
createdAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
amount: '47',
|
||||
createdAt: '2022-09-21T11:09:28.000Z',
|
||||
confirmedAt: '2022-09-21T11:09:28.000Z',
|
||||
contributionDate: '2022-08-01T00:00:00.000Z',
|
||||
memo: 'für deine Hilfe, Frau Holle',
|
||||
state: 'CONFIRMED',
|
||||
firstName: 'Räuber',
|
||||
lastName: 'Hotzenplotz',
|
||||
userId: 100,
|
||||
email: 'raeuber@hotzenplotz.de',
|
||||
amount: 1000000,
|
||||
memo: 'Gut Ergattert',
|
||||
date: new Date(),
|
||||
moderator: 1,
|
||||
state: 'PENDING',
|
||||
creation: [500, 500, 500],
|
||||
messagesCount: 0,
|
||||
deniedBy: null,
|
||||
deniedAt: null,
|
||||
confirmedBy: null,
|
||||
confirmedAt: new Date(),
|
||||
contributionDate: new Date(),
|
||||
deletedBy: null,
|
||||
deletedAt: null,
|
||||
createdAt: new Date(),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const mocks = {
|
||||
$d: jest.fn((t) => t),
|
||||
$t: jest.fn((t) => t),
|
||||
$apollo: {
|
||||
query: apolloQueryMock,
|
||||
},
|
||||
}
|
||||
|
||||
const propsData = {
|
||||
@ -48,47 +80,44 @@ const propsData = {
|
||||
describe('CreationTransactionList', () => {
|
||||
let wrapper
|
||||
|
||||
const adminListContributionsMock = jest.fn()
|
||||
mockClient.setRequestHandler(
|
||||
adminListContributions,
|
||||
adminListContributionsMock
|
||||
.mockRejectedValueOnce({ message: 'Ouch!' })
|
||||
.mockResolvedValue({ data: defaultData() }),
|
||||
)
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(CreationTransactionList, { localVue, mocks, propsData })
|
||||
return mount(CreationTransactionList, { localVue, mocks, propsData, apolloProvider })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
describe('server error', () => {
|
||||
it('toast error', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('Ouch!')
|
||||
})
|
||||
})
|
||||
|
||||
describe('sever success', () => {
|
||||
it('sends query to Apollo when created', () => {
|
||||
expect(apolloQueryMock).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
expect(adminListContributionsMock).toBeCalledWith({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
order: 'DESC',
|
||||
userId: 1,
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('has two values for the transaction', () => {
|
||||
expect(wrapper.find('tbody').findAll('tr').length).toBe(2)
|
||||
})
|
||||
|
||||
describe('query transaction with error', () => {
|
||||
beforeEach(() => {
|
||||
apolloQueryMock.mockRejectedValue({ message: 'OUCH!' })
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('calls the API', () => {
|
||||
expect(apolloQueryMock).toBeCalled()
|
||||
})
|
||||
|
||||
it('toast error', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('OUCH!')
|
||||
})
|
||||
})
|
||||
|
||||
describe('watch currentPage', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
@ -100,4 +129,5 @@ describe('CreationTransactionList', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { creationTransactionList } from '../graphql/creationTransactionList'
|
||||
import { adminListContributions } from '../graphql/adminListContributions'
|
||||
export default {
|
||||
name: 'CreationTransactionList',
|
||||
props: {
|
||||
@ -92,33 +92,26 @@ export default {
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTransactions() {
|
||||
this.$apollo
|
||||
.query({
|
||||
query: creationTransactionList,
|
||||
variables: {
|
||||
apollo: {
|
||||
AdminListContributions: {
|
||||
query() {
|
||||
return adminListContributions
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
currentPage: this.currentPage,
|
||||
pageSize: this.perPage,
|
||||
order: 'DESC',
|
||||
userId: parseInt(this.userId),
|
||||
}
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
this.rows = result.data.creationTransactionList.contributionCount
|
||||
this.items = result.data.creationTransactionList.contributionList
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastError(error.message)
|
||||
})
|
||||
update({ adminListContributions }) {
|
||||
this.rows = adminListContributions.contributionCount
|
||||
this.items = adminListContributions.contributionList
|
||||
},
|
||||
error({ message }) {
|
||||
this.toastError(message)
|
||||
},
|
||||
created() {
|
||||
this.getTransactions()
|
||||
},
|
||||
watch: {
|
||||
currentPage() {
|
||||
this.getTransactions()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,17 +1,19 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const adminListAllContributions = gql`
|
||||
export const adminListContributions = gql`
|
||||
query (
|
||||
$currentPage: Int = 1
|
||||
$pageSize: Int = 25
|
||||
$order: Order = DESC
|
||||
$statusFilter: [ContributionStatus!]
|
||||
$userId: Int
|
||||
) {
|
||||
adminListAllContributions(
|
||||
adminListContributions(
|
||||
currentPage: $currentPage
|
||||
pageSize: $pageSize
|
||||
order: $order
|
||||
statusFilter: $statusFilter
|
||||
userId: $userId
|
||||
) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
@ -1,23 +0,0 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const creationTransactionList = gql`
|
||||
query ($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC, $userId: Int!) {
|
||||
creationTransactionList(
|
||||
currentPage: $currentPage
|
||||
pageSize: $pageSize
|
||||
order: $order
|
||||
userId: $userId
|
||||
) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
id
|
||||
amount
|
||||
createdAt
|
||||
confirmedAt
|
||||
contributionDate
|
||||
memo
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -2,7 +2,7 @@ import { mount } from '@vue/test-utils'
|
||||
import CreationConfirm from './CreationConfirm'
|
||||
import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
|
||||
import { denyContribution } from '../graphql/denyContribution'
|
||||
import { adminListAllContributions } from '../graphql/adminListAllContributions'
|
||||
import { adminListContributions } from '../graphql/adminListContributions'
|
||||
import { confirmContribution } from '../graphql/confirmContribution'
|
||||
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
||||
import VueApollo from 'vue-apollo'
|
||||
@ -38,7 +38,7 @@ const mocks = {
|
||||
|
||||
const defaultData = () => {
|
||||
return {
|
||||
adminListAllContributions: {
|
||||
adminListContributions: {
|
||||
contributionCount: 2,
|
||||
contributionList: [
|
||||
{
|
||||
@ -92,14 +92,14 @@ const defaultData = () => {
|
||||
|
||||
describe('CreationConfirm', () => {
|
||||
let wrapper
|
||||
const adminListAllContributionsMock = jest.fn()
|
||||
const adminListContributionsMock = jest.fn()
|
||||
const adminDeleteContributionMock = jest.fn()
|
||||
const adminDenyContributionMock = jest.fn()
|
||||
const confirmContributionMock = jest.fn()
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
adminListAllContributions,
|
||||
adminListAllContributionsMock
|
||||
adminListContributions,
|
||||
adminListContributionsMock
|
||||
.mockRejectedValueOnce({ message: 'Ouch!' })
|
||||
.mockResolvedValue({ data: defaultData() }),
|
||||
)
|
||||
@ -337,7 +337,7 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
|
||||
it('refetches contributions with proper filter', () => {
|
||||
expect(adminListAllContributionsMock).toBeCalledWith({
|
||||
expect(adminListContributionsMock).toBeCalledWith({
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
@ -352,7 +352,7 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
|
||||
it('refetches contributions with proper filter', () => {
|
||||
expect(adminListAllContributionsMock).toBeCalledWith({
|
||||
expect(adminListContributionsMock).toBeCalledWith({
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
@ -368,7 +368,7 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
|
||||
it('refetches contributions with proper filter', () => {
|
||||
expect(adminListAllContributionsMock).toBeCalledWith({
|
||||
expect(adminListContributionsMock).toBeCalledWith({
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
@ -384,7 +384,7 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
|
||||
it('refetches contributions with proper filter', () => {
|
||||
expect(adminListAllContributionsMock).toBeCalledWith({
|
||||
expect(adminListContributionsMock).toBeCalledWith({
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
@ -400,7 +400,7 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
|
||||
it('refetches contributions with proper filter', () => {
|
||||
expect(adminListAllContributionsMock).toBeCalledWith({
|
||||
expect(adminListContributionsMock).toBeCalledWith({
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
|
||||
@ -85,7 +85,7 @@
|
||||
<script>
|
||||
import Overlay from '../components/Overlay'
|
||||
import OpenCreationsTable from '../components/Tables/OpenCreationsTable'
|
||||
import { adminListAllContributions } from '../graphql/adminListAllContributions'
|
||||
import { adminListContributions } from '../graphql/adminListContributions'
|
||||
import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
|
||||
import { confirmContribution } from '../graphql/confirmContribution'
|
||||
import { denyContribution } from '../graphql/denyContribution'
|
||||
@ -397,7 +397,7 @@ export default {
|
||||
apollo: {
|
||||
ListAllContributions: {
|
||||
query() {
|
||||
return adminListAllContributions
|
||||
return adminListContributions
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
@ -407,11 +407,11 @@ export default {
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
update({ adminListAllContributions }) {
|
||||
this.rows = adminListAllContributions.contributionCount
|
||||
this.items = adminListAllContributions.contributionList
|
||||
update({ adminListContributions }) {
|
||||
this.rows = adminListContributions.contributionCount
|
||||
this.items = adminListContributions.contributionList
|
||||
if (this.statusFilter === FILTER_TAB_MAP[0]) {
|
||||
this.$store.commit('setOpenCreations', adminListAllContributions.contributionCount)
|
||||
this.$store.commit('setOpenCreations', adminListContributions.contributionCount)
|
||||
}
|
||||
},
|
||||
error({ message }) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Overview from './Overview'
|
||||
import { adminListAllContributions } from '../graphql/adminListAllContributions'
|
||||
import { adminListContributions } from '../graphql/adminListContributions'
|
||||
import VueApollo from 'vue-apollo'
|
||||
import { createMockClient } from 'mock-apollo-client'
|
||||
import { toastErrorSpy } from '../../test/testSetup'
|
||||
@ -30,7 +30,7 @@ const mocks = {
|
||||
|
||||
const defaultData = () => {
|
||||
return {
|
||||
adminListAllContributions: {
|
||||
adminListContributions: {
|
||||
contributionCount: 2,
|
||||
contributionList: [
|
||||
{
|
||||
@ -84,11 +84,11 @@ const defaultData = () => {
|
||||
|
||||
describe('Overview', () => {
|
||||
let wrapper
|
||||
const adminListAllContributionsMock = jest.fn()
|
||||
const adminListContributionsMock = jest.fn()
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
adminListAllContributions,
|
||||
adminListAllContributionsMock
|
||||
adminListContributions,
|
||||
adminListContributionsMock
|
||||
.mockRejectedValueOnce({ message: 'Ouch!' })
|
||||
.mockResolvedValue({ data: defaultData() }),
|
||||
)
|
||||
@ -109,8 +109,8 @@ describe('Overview', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('calls the adminListAllContributions query', () => {
|
||||
expect(adminListAllContributionsMock).toBeCalledWith({
|
||||
it('calls the adminListContributions query', () => {
|
||||
expect(adminListContributionsMock).toBeCalledWith({
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { adminListAllContributions } from '../graphql/adminListAllContributions'
|
||||
import { adminListContributions } from '../graphql/adminListContributions'
|
||||
|
||||
export default {
|
||||
name: 'overview',
|
||||
@ -43,7 +43,7 @@ export default {
|
||||
apollo: {
|
||||
AllContributions: {
|
||||
query() {
|
||||
return adminListAllContributions
|
||||
return adminListContributions
|
||||
},
|
||||
variables() {
|
||||
// may be at some point we need a pagination here
|
||||
@ -51,8 +51,8 @@ export default {
|
||||
statusFilter: this.statusFilter,
|
||||
}
|
||||
},
|
||||
update({ adminListAllContributions }) {
|
||||
this.$store.commit('setOpenCreations', adminListAllContributions.contributionCount)
|
||||
update({ adminListContributions }) {
|
||||
this.$store.commit('setOpenCreations', adminListContributions.contributionCount)
|
||||
},
|
||||
error({ message }) {
|
||||
this.toastError(message)
|
||||
|
||||
@ -6,7 +6,7 @@ module.exports = {
|
||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
lines: 80,
|
||||
lines: 81,
|
||||
},
|
||||
},
|
||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||
|
||||
@ -2,7 +2,6 @@ import { RIGHTS } from './RIGHTS'
|
||||
|
||||
export const INALIENABLE_RIGHTS = [
|
||||
RIGHTS.LOGIN,
|
||||
RIGHTS.GET_COMMUNITY_INFO,
|
||||
RIGHTS.COMMUNITIES,
|
||||
RIGHTS.CREATE_USER,
|
||||
RIGHTS.SEND_RESET_PASSWORD_EMAIL,
|
||||
|
||||
@ -2,7 +2,6 @@ export enum RIGHTS {
|
||||
LOGIN = 'LOGIN',
|
||||
VERIFY_LOGIN = 'VERIFY_LOGIN',
|
||||
BALANCE = 'BALANCE',
|
||||
GET_COMMUNITY_INFO = 'GET_COMMUNITY_INFO',
|
||||
COMMUNITIES = 'COMMUNITIES',
|
||||
LIST_GDT_ENTRIES = 'LIST_GDT_ENTRIES',
|
||||
EXIST_PID = 'EXIST_PID',
|
||||
@ -44,10 +43,9 @@ export enum RIGHTS {
|
||||
ADMIN_CREATE_CONTRIBUTION = 'ADMIN_CREATE_CONTRIBUTION',
|
||||
ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION',
|
||||
ADMIN_DELETE_CONTRIBUTION = 'ADMIN_DELETE_CONTRIBUTION',
|
||||
LIST_UNCONFIRMED_CONTRIBUTIONS = 'LIST_UNCONFIRMED_CONTRIBUTIONS',
|
||||
ADMIN_LIST_CONTRIBUTIONS = 'ADMIN_LIST_CONTRIBUTIONS',
|
||||
CONFIRM_CONTRIBUTION = 'CONFIRM_CONTRIBUTION',
|
||||
SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
|
||||
CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST',
|
||||
LIST_TRANSACTION_LINKS_ADMIN = 'LIST_TRANSACTION_LINKS_ADMIN',
|
||||
CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK',
|
||||
DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK',
|
||||
|
||||
@ -10,7 +10,7 @@ Decimal.set({
|
||||
})
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0061-event_refactoring',
|
||||
DB_VERSION: '0062-event_contribution_confirm',
|
||||
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
|
||||
6
backend/src/event/EVENT_ACTIVATE_ACCOUNT.ts
Normal file
6
backend/src/event/EVENT_ACTIVATE_ACCOUNT.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_ACTIVATE_ACCOUNT = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventType.ACTIVATE_ACCOUNT, user, user).save()
|
||||
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_CONFIRM.ts
Normal file
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_CONFIRM.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_ADMIN_CONTRIBUTION_CONFIRM = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventType.ADMIN_CONTRIBUTION_CONFIRM,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_CREATE.ts
Normal file
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_CREATE.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_ADMIN_CONTRIBUTION_CREATE = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventType.ADMIN_CONTRIBUTION_CREATE,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_DELETE.ts
Normal file
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_DELETE.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_ADMIN_CONTRIBUTION_DELETE = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventType.ADMIN_CONTRIBUTION_DELETE,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_DENY.ts
Normal file
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_DENY.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_ADMIN_CONTRIBUTION_DENY = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventType.ADMIN_CONTRIBUTION_DENY,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_UPDATE.ts
Normal file
22
backend/src/event/EVENT_ADMIN_CONTRIBUTION_UPDATE.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_ADMIN_CONTRIBUTION_UPDATE = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventType.ADMIN_CONTRIBUTION_UPDATE,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
8
backend/src/event/EVENT_ADMIN_SEND_CONFIRMATION_EMAIL.ts
Normal file
8
backend/src/event/EVENT_ADMIN_SEND_CONFIRMATION_EMAIL.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_ADMIN_SEND_CONFIRMATION_EMAIL = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
): Promise<DbEvent> => Event(EventType.ADMIN_SEND_CONFIRMATION_EMAIL, user, moderator).save()
|
||||
12
backend/src/event/EVENT_CONTRIBUTION_CREATE.ts
Normal file
12
backend/src/event/EVENT_CONTRIBUTION_CREATE.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_CONTRIBUTION_CREATE = async (
|
||||
user: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(EventType.CONTRIBUTION_CREATE, user, user, null, null, contribution, null, amount).save()
|
||||
12
backend/src/event/EVENT_CONTRIBUTION_DELETE.ts
Normal file
12
backend/src/event/EVENT_CONTRIBUTION_DELETE.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_CONTRIBUTION_DELETE = async (
|
||||
user: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(EventType.CONTRIBUTION_DELETE, user, user, null, null, contribution, null, amount).save()
|
||||
12
backend/src/event/EVENT_CONTRIBUTION_UPDATE.ts
Normal file
12
backend/src/event/EVENT_CONTRIBUTION_UPDATE.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_CONTRIBUTION_UPDATE = async (
|
||||
user: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(EventType.CONTRIBUTION_UPDATE, user, user, null, null, contribution, null, amount).save()
|
||||
6
backend/src/event/EVENT_LOGIN.ts
Normal file
6
backend/src/event/EVENT_LOGIN.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_LOGIN = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventType.LOGIN, user, user).save()
|
||||
6
backend/src/event/EVENT_REGISTER.ts
Normal file
6
backend/src/event/EVENT_REGISTER.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_REGISTER = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventType.REGISTER, user, user).save()
|
||||
@ -0,0 +1,6 @@
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, user, { id: 0 } as DbUser).save()
|
||||
6
backend/src/event/EVENT_SEND_CONFIRMATION_EMAIL.ts
Normal file
6
backend/src/event/EVENT_SEND_CONFIRMATION_EMAIL.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_SEND_CONFIRMATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventType.SEND_CONFIRMATION_EMAIL, user, user).save()
|
||||
22
backend/src/event/EVENT_TRANSACTION_RECEIVE.ts
Normal file
22
backend/src/event/EVENT_TRANSACTION_RECEIVE.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_TRANSACTION_RECEIVE = async (
|
||||
user: DbUser,
|
||||
involvedUser: DbUser,
|
||||
transaction: DbTransaction,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventType.TRANSACTION_RECEIVE,
|
||||
user,
|
||||
involvedUser,
|
||||
involvedUser,
|
||||
transaction,
|
||||
null,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
22
backend/src/event/EVENT_TRANSACTION_SEND.ts
Normal file
22
backend/src/event/EVENT_TRANSACTION_SEND.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { Event, EventType } from './Event'
|
||||
|
||||
export const EVENT_TRANSACTION_SEND = async (
|
||||
user: DbUser,
|
||||
involvedUser: DbUser,
|
||||
transaction: DbTransaction,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventType.TRANSACTION_SEND,
|
||||
user,
|
||||
user,
|
||||
involvedUser,
|
||||
transaction,
|
||||
null,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
@ -4,10 +4,10 @@ import { ContributionMessage as DbContributionMessage } from '@entity/Contributi
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { EventProtocolType } from './EventProtocolType'
|
||||
import { EventType } from './Event'
|
||||
|
||||
export const Event = (
|
||||
type: EventProtocolType,
|
||||
type: EventType,
|
||||
affectedUser: DbUser,
|
||||
actingUser: DbUser,
|
||||
involvedUser: DbUser | null = null,
|
||||
@ -28,190 +28,21 @@ export const Event = (
|
||||
return event
|
||||
}
|
||||
|
||||
export const EVENT_CONTRIBUTION_CREATE = async (
|
||||
user: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.CONTRIBUTION_CREATE,
|
||||
user,
|
||||
user,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
export { EventType } from './EventType'
|
||||
|
||||
export const EVENT_CONTRIBUTION_DELETE = async (
|
||||
user: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.CONTRIBUTION_DELETE,
|
||||
user,
|
||||
user,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
|
||||
export const EVENT_CONTRIBUTION_UPDATE = async (
|
||||
user: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.CONTRIBUTION_UPDATE,
|
||||
user,
|
||||
user,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
|
||||
export const EVENT_ADMIN_CONTRIBUTION_CREATE = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
|
||||
export const EVENT_ADMIN_CONTRIBUTION_UPDATE = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
|
||||
export const EVENT_ADMIN_CONTRIBUTION_DELETE = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
|
||||
export const EVENT_CONTRIBUTION_CONFIRM = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.CONTRIBUTION_CONFIRM,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
|
||||
export const EVENT_ADMIN_CONTRIBUTION_DENY = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
contribution: DbContribution,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.ADMIN_CONTRIBUTION_DENY,
|
||||
user,
|
||||
moderator,
|
||||
null,
|
||||
null,
|
||||
contribution,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
|
||||
export const EVENT_TRANSACTION_SEND = async (
|
||||
user: DbUser,
|
||||
involvedUser: DbUser,
|
||||
transaction: DbTransaction,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.TRANSACTION_SEND,
|
||||
user,
|
||||
user,
|
||||
involvedUser,
|
||||
transaction,
|
||||
null,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
|
||||
export const EVENT_TRANSACTION_RECEIVE = async (
|
||||
user: DbUser,
|
||||
involvedUser: DbUser,
|
||||
transaction: DbTransaction,
|
||||
amount: Decimal,
|
||||
): Promise<DbEvent> =>
|
||||
Event(
|
||||
EventProtocolType.TRANSACTION_RECEIVE,
|
||||
user,
|
||||
involvedUser,
|
||||
involvedUser,
|
||||
transaction,
|
||||
null,
|
||||
null,
|
||||
amount,
|
||||
).save()
|
||||
|
||||
export const EVENT_LOGIN = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventProtocolType.LOGIN, user, user).save()
|
||||
|
||||
export const EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, user, { id: 0 } as DbUser).save()
|
||||
|
||||
export const EVENT_SEND_CONFIRMATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventProtocolType.SEND_CONFIRMATION_EMAIL, user, user).save()
|
||||
|
||||
export const EVENT_ADMIN_SEND_CONFIRMATION_EMAIL = async (
|
||||
user: DbUser,
|
||||
moderator: DbUser,
|
||||
): Promise<DbEvent> =>
|
||||
Event(EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL, user, moderator).save()
|
||||
|
||||
export const EVENT_REGISTER = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventProtocolType.REGISTER, user, user).save()
|
||||
|
||||
export const EVENT_ACTIVATE_ACCOUNT = async (user: DbUser): Promise<DbEvent> =>
|
||||
Event(EventProtocolType.ACTIVATE_ACCOUNT, user, user).save()
|
||||
export { EVENT_ACTIVATE_ACCOUNT } from './EVENT_ACTIVATE_ACCOUNT'
|
||||
export { EVENT_ADMIN_CONTRIBUTION_CONFIRM } from './EVENT_ADMIN_CONTRIBUTION_CONFIRM'
|
||||
export { EVENT_ADMIN_CONTRIBUTION_CREATE } from './EVENT_ADMIN_CONTRIBUTION_CREATE'
|
||||
export { EVENT_ADMIN_CONTRIBUTION_DELETE } from './EVENT_ADMIN_CONTRIBUTION_DELETE'
|
||||
export { EVENT_ADMIN_CONTRIBUTION_DENY } from './EVENT_ADMIN_CONTRIBUTION_DENY'
|
||||
export { EVENT_ADMIN_CONTRIBUTION_UPDATE } from './EVENT_ADMIN_CONTRIBUTION_UPDATE'
|
||||
export { EVENT_ADMIN_SEND_CONFIRMATION_EMAIL } from './EVENT_ADMIN_SEND_CONFIRMATION_EMAIL'
|
||||
export { EVENT_CONTRIBUTION_CREATE } from './EVENT_CONTRIBUTION_CREATE'
|
||||
export { EVENT_CONTRIBUTION_DELETE } from './EVENT_CONTRIBUTION_DELETE'
|
||||
export { EVENT_CONTRIBUTION_UPDATE } from './EVENT_CONTRIBUTION_UPDATE'
|
||||
export { EVENT_LOGIN } from './EVENT_LOGIN'
|
||||
export { EVENT_REGISTER } from './EVENT_REGISTER'
|
||||
export { EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL } from './EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL'
|
||||
export { EVENT_SEND_CONFIRMATION_EMAIL } from './EVENT_SEND_CONFIRMATION_EMAIL'
|
||||
export { EVENT_TRANSACTION_SEND } from './EVENT_TRANSACTION_SEND'
|
||||
export { EVENT_TRANSACTION_RECEIVE } from './EVENT_TRANSACTION_RECEIVE'
|
||||
|
||||
@ -1,42 +1,48 @@
|
||||
export enum EventProtocolType {
|
||||
// VISIT_GRADIDO = 'VISIT_GRADIDO',
|
||||
REGISTER = 'REGISTER',
|
||||
REDEEM_REGISTER = 'REDEEM_REGISTER',
|
||||
// VERIFY_REDEEM = 'VERIFY_REDEEM',
|
||||
// INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT',
|
||||
SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL',
|
||||
ADMIN_SEND_CONFIRMATION_EMAIL = 'ADMIN_SEND_CONFIRMATION_EMAIL',
|
||||
SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTIREGISTRATION_EMAIL',
|
||||
// CONFIRM_EMAIL = 'CONFIRM_EMAIL',
|
||||
// REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP',
|
||||
LOGIN = 'LOGIN',
|
||||
// LOGOUT = 'LOGOUT',
|
||||
// REDEEM_LOGIN = 'REDEEM_LOGIN',
|
||||
export { EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL } from './EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL'
|
||||
export { EVENT_SEND_CONFIRMATION_EMAIL } from './EVENT_SEND_CONFIRMATION_EMAIL'
|
||||
export { EVENT_TRANSACTION_SEND } from './EVENT_TRANSACTION_SEND'
|
||||
export { EVENT_TRANSACTION_RECEIVE } from './EVENT_TRANSACTION_RECEIVE'
|
||||
|
||||
export enum EventType {
|
||||
ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT',
|
||||
// SEND_FORGOT_PASSWORD_EMAIL = 'SEND_FORGOT_PASSWORD_EMAIL',
|
||||
// PASSWORD_CHANGE = 'PASSWORD_CHANGE',
|
||||
// SEND_TRANSACTION_SEND_EMAIL = 'SEND_TRANSACTION_SEND_EMAIL',
|
||||
// SEND_TRANSACTION_RECEIVE_EMAIL = 'SEND_TRANSACTION_RECEIVE_EMAIL',
|
||||
TRANSACTION_SEND = 'TRANSACTION_SEND',
|
||||
// TRANSACTION_SEND_REDEEM = 'TRANSACTION_SEND_REDEEM',
|
||||
// TRANSACTION_REPEATE_REDEEM = 'TRANSACTION_REPEATE_REDEEM',
|
||||
// TRANSACTION_CREATION = 'TRANSACTION_CREATION',
|
||||
TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE',
|
||||
// TRANSACTION_RECEIVE_REDEEM = 'TRANSACTION_RECEIVE_REDEEM',
|
||||
// SEND_TRANSACTION_LINK_REDEEM_EMAIL = 'SEND_TRANSACTION_LINK_REDEEM_EMAIL',
|
||||
// SEND_ADDED_CONTRIBUTION_EMAIL = 'SEND_ADDED_CONTRIBUTION_EMAIL',
|
||||
// SEND_CONTRIBUTION_CONFIRM_EMAIL = 'SEND_CONTRIBUTION_CONFIRM_EMAIL',
|
||||
CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE',
|
||||
CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM',
|
||||
// CONTRIBUTION_DENY = 'CONTRIBUTION_DENY',
|
||||
// CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE',
|
||||
// CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM',
|
||||
CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE',
|
||||
CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE',
|
||||
// TODO CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM',
|
||||
ADMIN_CONTRIBUTION_CONFIRM = 'ADMIN_CONTRIBUTION_CONFIRM',
|
||||
ADMIN_CONTRIBUTION_CREATE = 'ADMIN_CONTRIBUTION_CREATE',
|
||||
ADMIN_CONTRIBUTION_DELETE = 'ADMIN_CONTRIBUTION_DELETE',
|
||||
ADMIN_CONTRIBUTION_DENY = 'ADMIN_CONTRIBUTION_DENY',
|
||||
ADMIN_CONTRIBUTION_UPDATE = 'ADMIN_CONTRIBUTION_UPDATE',
|
||||
ADMIN_SEND_CONFIRMATION_EMAIL = 'ADMIN_SEND_CONFIRMATION_EMAIL',
|
||||
CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE',
|
||||
CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE',
|
||||
CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE',
|
||||
LOGIN = 'LOGIN',
|
||||
REGISTER = 'REGISTER',
|
||||
REDEEM_REGISTER = 'REDEEM_REGISTER',
|
||||
SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTIREGISTRATION_EMAIL',
|
||||
SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL',
|
||||
TRANSACTION_SEND = 'TRANSACTION_SEND',
|
||||
TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE',
|
||||
// VISIT_GRADIDO = 'VISIT_GRADIDO',
|
||||
// VERIFY_REDEEM = 'VERIFY_REDEEM',
|
||||
// INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT',
|
||||
// CONFIRM_EMAIL = 'CONFIRM_EMAIL',
|
||||
// REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP',
|
||||
// LOGOUT = 'LOGOUT',
|
||||
// REDEEM_LOGIN = 'REDEEM_LOGIN',
|
||||
// SEND_FORGOT_PASSWORD_EMAIL = 'SEND_FORGOT_PASSWORD_EMAIL',
|
||||
// PASSWORD_CHANGE = 'PASSWORD_CHANGE',
|
||||
// SEND_TRANSACTION_SEND_EMAIL = 'SEND_TRANSACTION_SEND_EMAIL',
|
||||
// SEND_TRANSACTION_RECEIVE_EMAIL = 'SEND_TRANSACTION_RECEIVE_EMAIL',
|
||||
// TRANSACTION_SEND_REDEEM = 'TRANSACTION_SEND_REDEEM',
|
||||
// TRANSACTION_REPEATE_REDEEM = 'TRANSACTION_REPEATE_REDEEM',
|
||||
// TRANSACTION_CREATION = 'TRANSACTION_CREATION',
|
||||
// TRANSACTION_RECEIVE_REDEEM = 'TRANSACTION_RECEIVE_REDEEM',
|
||||
// SEND_TRANSACTION_LINK_REDEEM_EMAIL = 'SEND_TRANSACTION_LINK_REDEEM_EMAIL',
|
||||
// SEND_ADDED_CONTRIBUTION_EMAIL = 'SEND_ADDED_CONTRIBUTION_EMAIL',
|
||||
// SEND_CONTRIBUTION_CONFIRM_EMAIL = 'SEND_CONTRIBUTION_CONFIRM_EMAIL',
|
||||
// CONTRIBUTION_DENY = 'CONTRIBUTION_DENY',
|
||||
// CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE',
|
||||
// CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM',
|
||||
// USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE',
|
||||
// ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE',
|
||||
// DELETE_USER = 'DELETE_USER',
|
||||
@ -1,33 +1,47 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
|
||||
@ObjectType()
|
||||
export class Community {
|
||||
constructor(json?: any) {
|
||||
if (json) {
|
||||
this.id = Number(json.id)
|
||||
this.name = json.name
|
||||
this.url = json.url
|
||||
this.description = json.description
|
||||
this.registerUrl = json.registerUrl
|
||||
}
|
||||
constructor(dbCom: DbCommunity) {
|
||||
this.id = dbCom.id
|
||||
this.foreign = dbCom.foreign
|
||||
this.publicKey = dbCom.publicKey.toString()
|
||||
this.url =
|
||||
(dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/') +
|
||||
'api/' +
|
||||
dbCom.apiVersion
|
||||
this.lastAnnouncedAt = dbCom.lastAnnouncedAt
|
||||
this.verifiedAt = dbCom.verifiedAt
|
||||
this.lastErrorAt = dbCom.lastErrorAt
|
||||
this.createdAt = dbCom.createdAt
|
||||
this.updatedAt = dbCom.updatedAt
|
||||
}
|
||||
|
||||
@Field(() => Int)
|
||||
id: number
|
||||
|
||||
@Field(() => Boolean)
|
||||
foreign: boolean
|
||||
|
||||
@Field(() => String)
|
||||
name: string
|
||||
publicKey: string
|
||||
|
||||
@Field(() => String)
|
||||
url: string
|
||||
|
||||
@Field(() => String)
|
||||
description: string
|
||||
@Field(() => Date, { nullable: true })
|
||||
lastAnnouncedAt: Date | null
|
||||
|
||||
@Field(() => String)
|
||||
registerUrl: string
|
||||
@Field(() => Date, { nullable: true })
|
||||
verifiedAt: Date | null
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
lastErrorAt: Date | null
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
createdAt: Date | null
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
updatedAt: Date | null
|
||||
}
|
||||
|
||||
@ -1,24 +1,25 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '@/server/createServer'
|
||||
import CONFIG from '@/config'
|
||||
|
||||
jest.mock('@/config')
|
||||
import { getCommunities } from '@/seeds/graphql/queries'
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
import { testEnvironment } from '@test/helpers'
|
||||
|
||||
let query: any
|
||||
|
||||
// to do: We need a setup for the tests that closes the connection
|
||||
let con: any
|
||||
let testEnv: any
|
||||
|
||||
beforeAll(async () => {
|
||||
const server = await createServer({})
|
||||
con = server.con
|
||||
query = createTestClient(server.apollo).query
|
||||
testEnv = await testEnvironment()
|
||||
query = testEnv.query
|
||||
con = testEnv.con
|
||||
await DbCommunity.clear()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
@ -26,74 +27,90 @@ afterAll(async () => {
|
||||
})
|
||||
|
||||
describe('CommunityResolver', () => {
|
||||
const getCommunityInfoQuery = `
|
||||
query {
|
||||
getCommunityInfo {
|
||||
name
|
||||
description
|
||||
url
|
||||
registerUrl
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const communities = `
|
||||
query {
|
||||
communities {
|
||||
id
|
||||
name
|
||||
url
|
||||
description
|
||||
registerUrl
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
describe('getCommunityInfo', () => {
|
||||
it('returns the default values', async () => {
|
||||
await expect(query({ query: getCommunityInfoQuery })).resolves.toMatchObject({
|
||||
describe('getCommunities', () => {
|
||||
let homeCom1: DbCommunity
|
||||
let homeCom2: DbCommunity
|
||||
let homeCom3: DbCommunity
|
||||
let foreignCom1: DbCommunity
|
||||
let foreignCom2: DbCommunity
|
||||
let foreignCom3: DbCommunity
|
||||
describe('with empty list', () => {
|
||||
it('returns no community entry', async () => {
|
||||
// const result: Community[] = await query({ query: getCommunities })
|
||||
// expect(result.length).toEqual(0)
|
||||
await expect(query({ query: getCommunities })).resolves.toMatchObject({
|
||||
data: {
|
||||
getCommunityInfo: {
|
||||
name: 'Gradido Entwicklung',
|
||||
description: 'Die lokale Entwicklungsumgebung von Gradido.',
|
||||
url: 'http://localhost/',
|
||||
registerUrl: 'http://localhost/register',
|
||||
},
|
||||
getCommunities: [],
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('communities', () => {
|
||||
describe('PRODUCTION = false', () => {
|
||||
beforeEach(() => {
|
||||
CONFIG.PRODUCTION = false
|
||||
describe('only home-communities entries', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
|
||||
homeCom1 = DbCommunity.create()
|
||||
homeCom1.foreign = false
|
||||
homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity')
|
||||
homeCom1.apiVersion = '1_0'
|
||||
homeCom1.endPoint = 'http://localhost'
|
||||
homeCom1.createdAt = new Date()
|
||||
await DbCommunity.insert(homeCom1)
|
||||
|
||||
homeCom2 = DbCommunity.create()
|
||||
homeCom2.foreign = false
|
||||
homeCom2.publicKey = Buffer.from('publicKey-HomeCommunity')
|
||||
homeCom2.apiVersion = '1_1'
|
||||
homeCom2.endPoint = 'http://localhost'
|
||||
homeCom2.createdAt = new Date()
|
||||
await DbCommunity.insert(homeCom2)
|
||||
|
||||
homeCom3 = DbCommunity.create()
|
||||
homeCom3.foreign = false
|
||||
homeCom3.publicKey = Buffer.from('publicKey-HomeCommunity')
|
||||
homeCom3.apiVersion = '2_0'
|
||||
homeCom3.endPoint = 'http://localhost'
|
||||
homeCom3.createdAt = new Date()
|
||||
await DbCommunity.insert(homeCom3)
|
||||
})
|
||||
|
||||
it('returns three communities', async () => {
|
||||
await expect(query({ query: communities })).resolves.toMatchObject({
|
||||
it('returns three home-community entries', async () => {
|
||||
await expect(query({ query: getCommunities })).resolves.toMatchObject({
|
||||
data: {
|
||||
communities: [
|
||||
getCommunities: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Gradido Entwicklung',
|
||||
description: 'Die lokale Entwicklungsumgebung von Gradido.',
|
||||
url: 'http://localhost/',
|
||||
registerUrl: 'http://localhost/register-community',
|
||||
foreign: homeCom1.foreign,
|
||||
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||
url: expect.stringMatching('http://localhost/api/1_0'),
|
||||
lastAnnouncedAt: null,
|
||||
verifiedAt: null,
|
||||
lastErrorAt: null,
|
||||
createdAt: homeCom1.createdAt.toISOString(),
|
||||
updatedAt: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Gradido Staging',
|
||||
description: 'Der Testserver der Gradido-Akademie.',
|
||||
url: 'https://stage1.gradido.net/',
|
||||
registerUrl: 'https://stage1.gradido.net/register-community',
|
||||
foreign: homeCom2.foreign,
|
||||
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||
url: expect.stringMatching('http://localhost/api/1_1'),
|
||||
lastAnnouncedAt: null,
|
||||
verifiedAt: null,
|
||||
lastErrorAt: null,
|
||||
createdAt: homeCom2.createdAt.toISOString(),
|
||||
updatedAt: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Gradido-Akademie',
|
||||
description: 'Freies Institut für Wirtschaftsbionik.',
|
||||
url: 'https://gradido.net',
|
||||
registerUrl: 'https://gdd1.gradido.com/register-community',
|
||||
foreign: homeCom3.foreign,
|
||||
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||
url: expect.stringMatching('http://localhost/api/2_0'),
|
||||
lastAnnouncedAt: null,
|
||||
verifiedAt: null,
|
||||
lastErrorAt: null,
|
||||
createdAt: homeCom3.createdAt.toISOString(),
|
||||
updatedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -101,21 +118,104 @@ describe('CommunityResolver', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('PRODUCTION = true', () => {
|
||||
beforeEach(() => {
|
||||
CONFIG.PRODUCTION = true
|
||||
describe('plus foreign-communities entries', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
|
||||
foreignCom1 = DbCommunity.create()
|
||||
foreignCom1.foreign = true
|
||||
foreignCom1.publicKey = Buffer.from('publicKey-ForeignCommunity')
|
||||
foreignCom1.apiVersion = '1_0'
|
||||
foreignCom1.endPoint = 'http://remotehost'
|
||||
foreignCom1.createdAt = new Date()
|
||||
await DbCommunity.insert(foreignCom1)
|
||||
|
||||
foreignCom2 = DbCommunity.create()
|
||||
foreignCom2.foreign = true
|
||||
foreignCom2.publicKey = Buffer.from('publicKey-ForeignCommunity')
|
||||
foreignCom2.apiVersion = '1_1'
|
||||
foreignCom2.endPoint = 'http://remotehost'
|
||||
foreignCom2.createdAt = new Date()
|
||||
await DbCommunity.insert(foreignCom2)
|
||||
|
||||
foreignCom3 = DbCommunity.create()
|
||||
foreignCom3.foreign = true
|
||||
foreignCom3.publicKey = Buffer.from('publicKey-ForeignCommunity')
|
||||
foreignCom3.apiVersion = '1_2'
|
||||
foreignCom3.endPoint = 'http://remotehost'
|
||||
foreignCom3.createdAt = new Date()
|
||||
await DbCommunity.insert(foreignCom3)
|
||||
})
|
||||
|
||||
it('returns one community', async () => {
|
||||
await expect(query({ query: communities })).resolves.toMatchObject({
|
||||
it('returns 3x home and 3x foreign-community entries', async () => {
|
||||
await expect(query({ query: getCommunities })).resolves.toMatchObject({
|
||||
data: {
|
||||
communities: [
|
||||
getCommunities: [
|
||||
{
|
||||
id: 1,
|
||||
foreign: homeCom1.foreign,
|
||||
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||
url: expect.stringMatching('http://localhost/api/1_0'),
|
||||
lastAnnouncedAt: null,
|
||||
verifiedAt: null,
|
||||
lastErrorAt: null,
|
||||
createdAt: homeCom1.createdAt.toISOString(),
|
||||
updatedAt: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
foreign: homeCom2.foreign,
|
||||
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||
url: expect.stringMatching('http://localhost/api/1_1'),
|
||||
lastAnnouncedAt: null,
|
||||
verifiedAt: null,
|
||||
lastErrorAt: null,
|
||||
createdAt: homeCom2.createdAt.toISOString(),
|
||||
updatedAt: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Gradido-Akademie',
|
||||
description: 'Freies Institut für Wirtschaftsbionik.',
|
||||
url: 'https://gradido.net',
|
||||
registerUrl: 'https://gdd1.gradido.com/register-community',
|
||||
foreign: homeCom3.foreign,
|
||||
publicKey: expect.stringMatching('publicKey-HomeCommunity'),
|
||||
url: expect.stringMatching('http://localhost/api/2_0'),
|
||||
lastAnnouncedAt: null,
|
||||
verifiedAt: null,
|
||||
lastErrorAt: null,
|
||||
createdAt: homeCom3.createdAt.toISOString(),
|
||||
updatedAt: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
foreign: foreignCom1.foreign,
|
||||
publicKey: expect.stringMatching('publicKey-ForeignCommunity'),
|
||||
url: expect.stringMatching('http://remotehost/api/1_0'),
|
||||
lastAnnouncedAt: null,
|
||||
verifiedAt: null,
|
||||
lastErrorAt: null,
|
||||
createdAt: foreignCom1.createdAt.toISOString(),
|
||||
updatedAt: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
foreign: foreignCom2.foreign,
|
||||
publicKey: expect.stringMatching('publicKey-ForeignCommunity'),
|
||||
url: expect.stringMatching('http://remotehost/api/1_1'),
|
||||
lastAnnouncedAt: null,
|
||||
verifiedAt: null,
|
||||
lastErrorAt: null,
|
||||
createdAt: foreignCom2.createdAt.toISOString(),
|
||||
updatedAt: null,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
foreign: foreignCom3.foreign,
|
||||
publicKey: expect.stringMatching('publicKey-ForeignCommunity'),
|
||||
url: expect.stringMatching('http://remotehost/api/1_2'),
|
||||
lastAnnouncedAt: null,
|
||||
verifiedAt: null,
|
||||
lastErrorAt: null,
|
||||
createdAt: foreignCom3.createdAt.toISOString(),
|
||||
updatedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -1,58 +1,18 @@
|
||||
import { Resolver, Query, Authorized } from 'type-graphql'
|
||||
|
||||
import { Community } from '@model/Community'
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import CONFIG from '@/config'
|
||||
|
||||
@Resolver()
|
||||
export class CommunityResolver {
|
||||
@Authorized([RIGHTS.GET_COMMUNITY_INFO])
|
||||
@Query(() => Community)
|
||||
getCommunityInfo(): Community {
|
||||
return new Community({
|
||||
name: CONFIG.COMMUNITY_NAME,
|
||||
description: CONFIG.COMMUNITY_DESCRIPTION,
|
||||
url: CONFIG.COMMUNITY_URL,
|
||||
registerUrl: CONFIG.COMMUNITY_REGISTER_URL,
|
||||
})
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.COMMUNITIES])
|
||||
@Query(() => [Community])
|
||||
communities(): Community[] {
|
||||
if (CONFIG.PRODUCTION)
|
||||
return [
|
||||
new Community({
|
||||
id: 3,
|
||||
name: 'Gradido-Akademie',
|
||||
description: 'Freies Institut für Wirtschaftsbionik.',
|
||||
url: 'https://gradido.net',
|
||||
registerUrl: 'https://gdd1.gradido.com/register-community',
|
||||
}),
|
||||
]
|
||||
return [
|
||||
new Community({
|
||||
id: 1,
|
||||
name: 'Gradido Entwicklung',
|
||||
description: 'Die lokale Entwicklungsumgebung von Gradido.',
|
||||
url: 'http://localhost/',
|
||||
registerUrl: 'http://localhost/register-community',
|
||||
}),
|
||||
new Community({
|
||||
id: 2,
|
||||
name: 'Gradido Staging',
|
||||
description: 'Der Testserver der Gradido-Akademie.',
|
||||
url: 'https://stage1.gradido.net/',
|
||||
registerUrl: 'https://stage1.gradido.net/register-community',
|
||||
}),
|
||||
new Community({
|
||||
id: 3,
|
||||
name: 'Gradido-Akademie',
|
||||
description: 'Freies Institut für Wirtschaftsbionik.',
|
||||
url: 'https://gradido.net',
|
||||
registerUrl: 'https://gdd1.gradido.com/register-community',
|
||||
}),
|
||||
]
|
||||
async getCommunities(): Promise<Community[]> {
|
||||
const dbCommunities: DbCommunity[] = await DbCommunity.find({
|
||||
order: { foreign: 'ASC', publicKey: 'ASC', apiVersion: 'ASC' },
|
||||
})
|
||||
return dbCommunities.map((dbCom: DbCommunity) => new Community(dbCom))
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ import {
|
||||
import {
|
||||
listAllContributions,
|
||||
listContributions,
|
||||
adminListAllContributions,
|
||||
adminListContributions,
|
||||
} from '@/seeds/graphql/queries'
|
||||
import {
|
||||
sendContributionConfirmedEmail,
|
||||
@ -50,7 +50,7 @@ import { Event as DbEvent } from '@entity/Event'
|
||||
import { Contribution } from '@entity/Contribution'
|
||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||
import { User } from '@entity/User'
|
||||
import { EventProtocolType } from '@/event/EventProtocolType'
|
||||
import { EventType } from '@/event/Event'
|
||||
import { logger, i18n as localization } from '@test/testSetup'
|
||||
import { UserInputError } from 'apollo-server-express'
|
||||
import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz'
|
||||
@ -281,7 +281,7 @@ describe('ContributionResolver', () => {
|
||||
it('stores the CONTRIBUTION_CREATE event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.CONTRIBUTION_CREATE,
|
||||
type: EventType.CONTRIBUTION_CREATE,
|
||||
affectedUserId: bibi.id,
|
||||
actingUserId: bibi.id,
|
||||
involvedContributionId: pendingContribution.data.createContribution.id,
|
||||
@ -586,7 +586,7 @@ describe('ContributionResolver', () => {
|
||||
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.CONTRIBUTION_UPDATE,
|
||||
type: EventType.CONTRIBUTION_UPDATE,
|
||||
affectedUserId: bibi.id,
|
||||
actingUserId: bibi.id,
|
||||
involvedContributionId: pendingContribution.data.createContribution.id,
|
||||
@ -817,7 +817,7 @@ describe('ContributionResolver', () => {
|
||||
it('stores the ADMIN_CONTRIBUTION_DENY event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.ADMIN_CONTRIBUTION_DENY,
|
||||
type: EventType.ADMIN_CONTRIBUTION_DENY,
|
||||
affectedUserId: bibi.id,
|
||||
actingUserId: admin.id,
|
||||
involvedContributionId: contributionToDeny.data.createContribution.id,
|
||||
@ -945,7 +945,7 @@ describe('ContributionResolver', () => {
|
||||
it('stores the CONTRIBUTION_DELETE event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.CONTRIBUTION_DELETE,
|
||||
type: EventType.CONTRIBUTION_DELETE,
|
||||
affectedUserId: bibi.id,
|
||||
actingUserId: bibi.id,
|
||||
involvedContributionId: contributionToDelete.data.createContribution.id,
|
||||
@ -2033,7 +2033,7 @@ describe('ContributionResolver', () => {
|
||||
it('stores the ADMIN_CONTRIBUTION_CREATE event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
|
||||
type: EventType.ADMIN_CONTRIBUTION_CREATE,
|
||||
affectedUserId: bibi.id,
|
||||
actingUserId: admin.id,
|
||||
amount: expect.decimalEqual(200),
|
||||
@ -2252,7 +2252,7 @@ describe('ContributionResolver', () => {
|
||||
it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
|
||||
type: EventType.ADMIN_CONTRIBUTION_UPDATE,
|
||||
affectedUserId: creation?.userId,
|
||||
actingUserId: admin.id,
|
||||
amount: 300,
|
||||
@ -2292,7 +2292,7 @@ describe('ContributionResolver', () => {
|
||||
it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
|
||||
type: EventType.ADMIN_CONTRIBUTION_UPDATE,
|
||||
affectedUserId: creation?.userId,
|
||||
actingUserId: admin.id,
|
||||
amount: expect.decimalEqual(200),
|
||||
@ -2378,7 +2378,7 @@ describe('ContributionResolver', () => {
|
||||
it('stores the ADMIN_CONTRIBUTION_DELETE event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
|
||||
type: EventType.ADMIN_CONTRIBUTION_DELETE,
|
||||
affectedUserId: creation?.userId,
|
||||
actingUserId: admin.id,
|
||||
involvedContributionId: creation?.id,
|
||||
@ -2536,7 +2536,7 @@ describe('ContributionResolver', () => {
|
||||
it('stores the CONTRIBUTION_CONFIRM event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.CONTRIBUTION_CONFIRM,
|
||||
type: EventType.ADMIN_CONTRIBUTION_CONFIRM,
|
||||
}),
|
||||
)
|
||||
})
|
||||
@ -2568,7 +2568,7 @@ describe('ContributionResolver', () => {
|
||||
it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.SEND_CONFIRMATION_EMAIL,
|
||||
type: EventType.SEND_CONFIRMATION_EMAIL,
|
||||
}),
|
||||
)
|
||||
})
|
||||
@ -2657,12 +2657,12 @@ describe('ContributionResolver', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('adminListAllContribution', () => {
|
||||
describe('adminListContributions', () => {
|
||||
describe('unauthenticated', () => {
|
||||
it('returns an error', async () => {
|
||||
await expect(
|
||||
query({
|
||||
query: adminListAllContributions,
|
||||
query: adminListContributions,
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
@ -2687,7 +2687,7 @@ describe('ContributionResolver', () => {
|
||||
it('returns an error', async () => {
|
||||
await expect(
|
||||
query({
|
||||
query: adminListAllContributions,
|
||||
query: adminListContributions,
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
@ -2711,9 +2711,9 @@ describe('ContributionResolver', () => {
|
||||
|
||||
it('returns 17 creations in total', async () => {
|
||||
const {
|
||||
data: { adminListAllContributions: contributionListObject },
|
||||
}: { data: { adminListAllContributions: ContributionListResult } } = await query({
|
||||
query: adminListAllContributions,
|
||||
data: { adminListContributions: contributionListObject },
|
||||
}: { data: { adminListContributions: ContributionListResult } } = await query({
|
||||
query: adminListContributions,
|
||||
})
|
||||
expect(contributionListObject.contributionList).toHaveLength(17)
|
||||
expect(contributionListObject).toMatchObject({
|
||||
@ -2878,9 +2878,9 @@ describe('ContributionResolver', () => {
|
||||
|
||||
it('returns two pending creations with page size set to 2', async () => {
|
||||
const {
|
||||
data: { adminListAllContributions: contributionListObject },
|
||||
}: { data: { adminListAllContributions: ContributionListResult } } = await query({
|
||||
query: adminListAllContributions,
|
||||
data: { adminListContributions: contributionListObject },
|
||||
}: { data: { adminListContributions: ContributionListResult } } = await query({
|
||||
query: adminListContributions,
|
||||
variables: {
|
||||
currentPage: 1,
|
||||
pageSize: 2,
|
||||
|
||||
@ -42,7 +42,7 @@ import {
|
||||
EVENT_ADMIN_CONTRIBUTION_CREATE,
|
||||
EVENT_ADMIN_CONTRIBUTION_UPDATE,
|
||||
EVENT_ADMIN_CONTRIBUTION_DELETE,
|
||||
EVENT_CONTRIBUTION_CONFIRM,
|
||||
EVENT_ADMIN_CONTRIBUTION_CONFIRM,
|
||||
EVENT_ADMIN_CONTRIBUTION_DENY,
|
||||
} from '@/event/Event'
|
||||
import { calculateDecay } from '@/util/decay'
|
||||
@ -136,15 +136,15 @@ export class ContributionResolver {
|
||||
): Promise<ContributionListResult> {
|
||||
const user = getUser(context)
|
||||
|
||||
const [dbContributions, count] = await findContributions(
|
||||
const [dbContributions, count] = await findContributions({
|
||||
order,
|
||||
currentPage,
|
||||
pageSize,
|
||||
true,
|
||||
['messages'],
|
||||
user.id,
|
||||
withDeleted: true,
|
||||
relations: ['messages'],
|
||||
userId: user.id,
|
||||
statusFilter,
|
||||
)
|
||||
})
|
||||
return new ContributionListResult(
|
||||
count,
|
||||
dbContributions.map((contribution) => new Contribution(contribution, user)),
|
||||
@ -159,15 +159,13 @@ export class ContributionResolver {
|
||||
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
|
||||
statusFilter?: ContributionStatus[] | null,
|
||||
): Promise<ContributionListResult> {
|
||||
const [dbContributions, count] = await findContributions(
|
||||
const [dbContributions, count] = await findContributions({
|
||||
order,
|
||||
currentPage,
|
||||
pageSize,
|
||||
false,
|
||||
['user'],
|
||||
undefined,
|
||||
relations: ['user'],
|
||||
statusFilter,
|
||||
)
|
||||
})
|
||||
|
||||
return new ContributionListResult(
|
||||
count,
|
||||
@ -369,23 +367,25 @@ export class ContributionResolver {
|
||||
return result
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.LIST_UNCONFIRMED_CONTRIBUTIONS])
|
||||
@Query(() => ContributionListResult) // [UnconfirmedContribution]
|
||||
async adminListAllContributions(
|
||||
@Authorized([RIGHTS.ADMIN_LIST_CONTRIBUTIONS])
|
||||
@Query(() => ContributionListResult)
|
||||
async adminListContributions(
|
||||
@Args()
|
||||
{ currentPage = 1, pageSize = 3, order = Order.DESC }: Paginated,
|
||||
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
|
||||
statusFilter?: ContributionStatus[] | null,
|
||||
@Arg('userId', () => Int, { nullable: true })
|
||||
userId?: number | null,
|
||||
): Promise<ContributionListResult> {
|
||||
const [dbContributions, count] = await findContributions(
|
||||
const [dbContributions, count] = await findContributions({
|
||||
order,
|
||||
currentPage,
|
||||
pageSize,
|
||||
true,
|
||||
['user', 'messages'],
|
||||
undefined,
|
||||
withDeleted: true,
|
||||
userId,
|
||||
relations: ['user', 'messages'],
|
||||
statusFilter,
|
||||
)
|
||||
})
|
||||
|
||||
return new ContributionListResult(
|
||||
count,
|
||||
@ -540,40 +540,13 @@ export class ContributionResolver {
|
||||
await queryRunner.release()
|
||||
}
|
||||
|
||||
await EVENT_CONTRIBUTION_CONFIRM(user, moderatorUser, contribution, contribution.amount)
|
||||
await EVENT_ADMIN_CONTRIBUTION_CONFIRM(user, moderatorUser, contribution, contribution.amount)
|
||||
} finally {
|
||||
releaseLock()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.CREATION_TRANSACTION_LIST])
|
||||
@Query(() => ContributionListResult)
|
||||
async creationTransactionList(
|
||||
@Args()
|
||||
{ currentPage = 1, pageSize = 25, order = Order.DESC }: Paginated,
|
||||
@Arg('userId', () => Int) userId: number,
|
||||
): Promise<ContributionListResult> {
|
||||
const offset = (currentPage - 1) * pageSize
|
||||
const [contributionResult, count] = await getConnection()
|
||||
.createQueryBuilder()
|
||||
.select('c')
|
||||
.from(DbContribution, 'c')
|
||||
.leftJoinAndSelect('c.user', 'u')
|
||||
.where(`user_id = ${userId}`)
|
||||
.withDeleted()
|
||||
.limit(pageSize)
|
||||
.offset(offset)
|
||||
.orderBy('c.created_at', order)
|
||||
.getManyAndCount()
|
||||
|
||||
return new ContributionListResult(
|
||||
count,
|
||||
contributionResult.map((contribution) => new Contribution(contribution, contribution.user)),
|
||||
)
|
||||
// return userTransactions.map((t) => new Transaction(t, new User(user), communityUser))
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.OPEN_CREATIONS])
|
||||
@Query(() => [OpenCreation])
|
||||
async openCreations(@Ctx() context: Context): Promise<OpenCreation[]> {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { EventProtocolType } from '@/event/EventProtocolType'
|
||||
import { EventType } from '@/event/Event'
|
||||
import { userFactory } from '@/seeds/factory/user'
|
||||
import {
|
||||
confirmContribution,
|
||||
@ -343,7 +343,7 @@ describe('send coins', () => {
|
||||
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.TRANSACTION_SEND,
|
||||
type: EventType.TRANSACTION_SEND,
|
||||
affectedUserId: user[1].id,
|
||||
actingUserId: user[1].id,
|
||||
involvedUserId: user[0].id,
|
||||
@ -361,7 +361,7 @@ describe('send coins', () => {
|
||||
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.TRANSACTION_RECEIVE,
|
||||
type: EventType.TRANSACTION_RECEIVE,
|
||||
affectedUserId: user[0].id,
|
||||
actingUserId: user[1].id,
|
||||
involvedUserId: user[1].id,
|
||||
|
||||
@ -39,7 +39,7 @@ import { contributionLinkFactory } from '@/seeds/factory/contributionLink'
|
||||
import { transactionLinkFactory } from '@/seeds/factory/transactionLink'
|
||||
import { ContributionLink } from '@model/ContributionLink'
|
||||
import { TransactionLink } from '@entity/TransactionLink'
|
||||
import { EventProtocolType } from '@/event/EventProtocolType'
|
||||
import { EventType } from '@/event/Event'
|
||||
import { Event as DbEvent } from '@entity/Event'
|
||||
import { validate as validateUUID, version as versionUUID } from 'uuid'
|
||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||
@ -189,7 +189,7 @@ describe('UserResolver', () => {
|
||||
)
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.REGISTER,
|
||||
type: EventType.REGISTER,
|
||||
affectedUserId: userConatct.user.id,
|
||||
actingUserId: userConatct.user.id,
|
||||
}),
|
||||
@ -219,7 +219,7 @@ describe('UserResolver', () => {
|
||||
it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.SEND_CONFIRMATION_EMAIL,
|
||||
type: EventType.SEND_CONFIRMATION_EMAIL,
|
||||
affectedUserId: user[0].id,
|
||||
actingUserId: user[0].id,
|
||||
}),
|
||||
@ -265,7 +265,7 @@ describe('UserResolver', () => {
|
||||
)
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL,
|
||||
type: EventType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL,
|
||||
affectedUserId: userConatct.user.id,
|
||||
actingUserId: 0,
|
||||
}),
|
||||
@ -366,7 +366,7 @@ describe('UserResolver', () => {
|
||||
it('stores the ACTIVATE_ACCOUNT event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.ACTIVATE_ACCOUNT,
|
||||
type: EventType.ACTIVATE_ACCOUNT,
|
||||
affectedUserId: user[0].id,
|
||||
actingUserId: user[0].id,
|
||||
}),
|
||||
@ -376,7 +376,7 @@ describe('UserResolver', () => {
|
||||
it('stores the REDEEM_REGISTER event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.REDEEM_REGISTER,
|
||||
type: EventType.REDEEM_REGISTER,
|
||||
affectedUserId: result.data.createUser.id,
|
||||
actingUserId: result.data.createUser.id,
|
||||
involvedContributionId: link.id,
|
||||
@ -461,7 +461,7 @@ describe('UserResolver', () => {
|
||||
it('stores the REDEEM_REGISTER event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.REDEEM_REGISTER,
|
||||
type: EventType.REDEEM_REGISTER,
|
||||
affectedUserId: newUser.data.createUser.id,
|
||||
actingUserId: newUser.data.createUser.id,
|
||||
involvedTransactionId: transactionLink.id,
|
||||
@ -694,7 +694,7 @@ describe('UserResolver', () => {
|
||||
)
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.LOGIN,
|
||||
type: EventType.LOGIN,
|
||||
affectedUserId: userConatct.user.id,
|
||||
actingUserId: userConatct.user.id,
|
||||
}),
|
||||
@ -943,7 +943,7 @@ describe('UserResolver', () => {
|
||||
it('stores the LOGIN event in the database', async () => {
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.LOGIN,
|
||||
type: EventType.LOGIN,
|
||||
affectedUserId: user[0].id,
|
||||
actingUserId: user[0].id,
|
||||
}),
|
||||
@ -1863,7 +1863,7 @@ describe('UserResolver', () => {
|
||||
)
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL,
|
||||
type: EventType.ADMIN_SEND_CONFIRMATION_EMAIL,
|
||||
affectedUserId: userConatct.user.id,
|
||||
actingUserId: admin.id,
|
||||
}),
|
||||
|
||||
@ -56,6 +56,7 @@ import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import { hasElopageBuys } from '@/util/hasElopageBuys'
|
||||
import {
|
||||
Event,
|
||||
EventType,
|
||||
EVENT_LOGIN,
|
||||
EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL,
|
||||
EVENT_SEND_CONFIRMATION_EMAIL,
|
||||
@ -69,7 +70,6 @@ import { FULL_CREATION_AVAILABLE } from './const/const'
|
||||
import { encryptPassword, verifyPassword } from '@/password/PasswordEncryptor'
|
||||
import { PasswordEncryptionType } from '../enum/PasswordEncryptionType'
|
||||
import LogError from '@/server/LogError'
|
||||
import { EventProtocolType } from '@/event/EventProtocolType'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const sodium = require('sodium-native')
|
||||
@ -273,7 +273,7 @@ export class UserResolver {
|
||||
const gradidoID = await newGradidoID()
|
||||
|
||||
const eventRegisterRedeem = Event(
|
||||
EventProtocolType.REDEEM_REGISTER,
|
||||
EventType.REDEEM_REGISTER,
|
||||
{ id: 0 } as DbUser,
|
||||
{ id: 0 } as DbUser,
|
||||
)
|
||||
|
||||
@ -3,21 +3,30 @@ import { Order } from '@enum/Order'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { In } from '@dbTools/typeorm'
|
||||
|
||||
interface FindContributionsOptions {
|
||||
order: Order
|
||||
currentPage: number
|
||||
pageSize: number
|
||||
withDeleted?: boolean
|
||||
relations?: string[]
|
||||
userId?: number | null
|
||||
statusFilter?: ContributionStatus[] | null
|
||||
}
|
||||
|
||||
export const findContributions = async (
|
||||
order: Order,
|
||||
currentPage: number,
|
||||
pageSize: number,
|
||||
withDeleted: boolean,
|
||||
relations: string[],
|
||||
userId?: number,
|
||||
statusFilter?: ContributionStatus[] | null,
|
||||
): Promise<[DbContribution[], number]> =>
|
||||
DbContribution.findAndCount({
|
||||
options: FindContributionsOptions,
|
||||
): Promise<[DbContribution[], number]> => {
|
||||
const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter } = {
|
||||
withDeleted: false,
|
||||
relations: [],
|
||||
...options,
|
||||
}
|
||||
return DbContribution.findAndCount({
|
||||
where: {
|
||||
...(statusFilter && statusFilter.length && { contributionStatus: In(statusFilter) }),
|
||||
...(userId && { userId }),
|
||||
},
|
||||
withDeleted: withDeleted,
|
||||
withDeleted,
|
||||
order: {
|
||||
createdAt: order,
|
||||
id: order,
|
||||
@ -26,3 +35,4 @@ export const findContributions = async (
|
||||
skip: (currentPage - 1) * pageSize,
|
||||
take: pageSize,
|
||||
})
|
||||
}
|
||||
|
||||
@ -133,6 +133,22 @@ export const communities = gql`
|
||||
}
|
||||
`
|
||||
|
||||
export const getCommunities = gql`
|
||||
query {
|
||||
getCommunities {
|
||||
id
|
||||
foreign
|
||||
publicKey
|
||||
url
|
||||
lastAnnouncedAt
|
||||
verifiedAt
|
||||
lastErrorAt
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const queryTransactionLink = gql`
|
||||
query ($code: String!) {
|
||||
queryTransactionLink(code: $code) {
|
||||
@ -204,18 +220,20 @@ query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC, $statusF
|
||||
`
|
||||
// from admin interface
|
||||
|
||||
export const adminListAllContributions = gql`
|
||||
export const adminListContributions = gql`
|
||||
query (
|
||||
$currentPage: Int = 1
|
||||
$pageSize: Int = 25
|
||||
$order: Order = DESC
|
||||
$statusFilter: [ContributionStatus!]
|
||||
$userId: Int
|
||||
) {
|
||||
adminListAllContributions(
|
||||
adminListContributions(
|
||||
currentPage: $currentPage
|
||||
pageSize: $pageSize
|
||||
order: $order
|
||||
statusFilter: $statusFilter
|
||||
userId: $userId
|
||||
) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
|
||||
@ -25,13 +25,13 @@ export class Community extends BaseEntity {
|
||||
endPoint: string
|
||||
|
||||
@Column({ name: 'last_announced_at', type: 'datetime', nullable: true })
|
||||
lastAnnouncedAt: Date
|
||||
lastAnnouncedAt: Date | null
|
||||
|
||||
@Column({ name: 'verified_at', type: 'datetime', nullable: true })
|
||||
verifiedAt: Date
|
||||
verifiedAt: Date | null
|
||||
|
||||
@Column({ name: 'last_error_at', type: 'datetime', nullable: true })
|
||||
lastErrorAt: Date
|
||||
lastErrorAt: Date | null
|
||||
|
||||
@CreateDateColumn({
|
||||
name: 'created_at',
|
||||
|
||||
20
database/migrations/0062-event_contribution_confirm.ts
Normal file
20
database/migrations/0062-event_contribution_confirm.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/* MIGRATION TO RENAME CONTRIBUTION_CONFIRM EVENT
|
||||
*
|
||||
* This migration renames the CONTRIBUTION_CONFIRM Event
|
||||
* to ADMIN_CONTRIBUTION_CONFIRM
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(
|
||||
'UPDATE `events` SET `type` = "ADMIN_CONTRIBUTION_CONFIRM" WHERE `type` = "CONTRIBUTION_CONFIRM";',
|
||||
)
|
||||
}
|
||||
|
||||
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(
|
||||
'UPDATE `events` SET `type` = "CONTRIBUTION_CONFIRM" WHERE `type` = "ADMIN_CONTRIBUTION_CONFIRM";',
|
||||
)
|
||||
}
|
||||
@ -3,7 +3,7 @@ import dotenv from 'dotenv'
|
||||
dotenv.config()
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0061-event_refactoring',
|
||||
DB_VERSION: '0062-event_contribution_confirm',
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
|
||||
|
||||
@ -4,29 +4,6 @@ This document contains the concept and technical details for the *federation* of
|
||||
|
||||
But meanwhile the usage of a DHT like HyperSwarm promises more coverage of the gradido requirements out of the box. More details about HyperSwarm can be found here [@hyperswarm/dht](https://github.com/hyperswarm/dht).
|
||||
|
||||
## ActivityPub (deprecated)
|
||||
|
||||
The activity pub defines a server-to-server federation protocol to share information between decentralized instances and will be the main komponent for the gradido community federation.
|
||||
|
||||
At first we asume a *gradido community* as an *ActivityPub user*. A user is represented by "*actors*" via the users's accounts on servers. User's accounts on different servers corrsponds to different actors, which means community accounts on different servers corrsponds to different communities.
|
||||
|
||||
Every community (actor) has an:
|
||||
|
||||
* inbox: to get messages from the world
|
||||
* outbox: to send messages to others
|
||||
|
||||
and are simple endpoints or just URLs, which are described in the *ActivityStream* of each *ActivityPub community*.
|
||||
|
||||
### Open Decision:
|
||||
|
||||
It has to be decided, if the Federation will work with an internal or with external ActivityPub-Server, as shown in the picture below:
|
||||
|
||||

|
||||
|
||||
The Variant A with an internal server contains the benefit to be as independent as possible from third party service providers and will not cause additional hosting costs. But this solution will cause the additional efforts of impementing an ActivityPub-Server in the gradido application and the responsibility for this component.
|
||||
|
||||
The Varaint B with an external server contains the benefit to reduce the implementation efforts and the responsibility for an own ActivitPub-Server. But it will cause an additional dependency to a third party service provider and the growing hosting costs.
|
||||
|
||||
## HyperSwarm
|
||||
|
||||
The decision to switch from ActivityPub to HyperSwarm base on the arguments, that the *hyperswarm/dht* library will satify the most federation requirements out of the box. It is now to design the business requirements of the [gradido community communication](../BusinessRequirements/CommunityVerwaltung.md#UC-createCommunity) in a technical conception.
|
||||
@ -41,12 +18,30 @@ To enable such a relationship between an existing community and a new community
|
||||
2. Authentication
|
||||
3. Autorized Communication
|
||||
|
||||
### Overview
|
||||
### Overview of Federation-Handshake
|
||||
|
||||
At first the following diagramm gives an overview of the three stages and shows the handshake between an existing community-A and a new created community-B including the data exchange for buildup such a federated, authenticated and autorized relationship.
|
||||
|
||||

|
||||
|
||||
### Technical Architecture
|
||||
|
||||
The previous described handshake will be done by several technical modules of the gradido system. The following picture gives an overview about the modules and how the communicate with each other.
|
||||
|
||||

|
||||
|
||||
As soon as a Gradido Community is up and running the DHT-Modul first writes the home-community-entries in the database and starts with the federation via HyperSwarm. Each community, which is configured with the configuration key GRADIDO_HUB to listen on the correct topic of the DHT will be part of the Gradido-Net-Federation. That means each DHT-Modul of each community will receive the publicKey of all connected communities. The DHT-Modul will open for each received publicKey a communication-socket with the associated community DHT-Modul. Over this open socket the connected communities exchange the data "api-version" and "url" for later direct communication between both communities. The exchanged api-version info and urls will be written in the own database.
|
||||
|
||||
The background of this exchanged data base on the supported api-versions a community will support with its own federation-modules. Each running federation-module in a community will support exact one graphql api-version of a cross-community-communication. To reach a dedicated federation-module with the correct api-version during a cross-community-communication the url for this federation-module must be known by both communities. As shown in the picture above the graphql-client with api-version V1_0 in the left community will interact with the federation-module with api-version V1_0 on the right community. During the lifecycle of the gradido-application it will be necessary to extent the features and interfaces for the cross-community-communication. To keep a backwards compatibilty and not to force each community to always upgrade their running software version on the last api-version at the same time, it will be necessary to support several api-versions in parallel. The different running api-version modules are responsible to convert and treat the exchanged data in a correct way to ensure konsistent data in the local database of the community.
|
||||
|
||||
The up and running Backend-Module contains a validation logic to verify the community entries from the own DHT-Module. For each announced but unverified community-entry the GraphQL-Client is used to invoke a getPublicKey-Request. Depending on the containing api-version the matching GraphQL-Client is used and the getPublicKey-Request will be send to the given URL.
|
||||
|
||||
As soon as the federation-module of the associated community received the getPublicKey-request the own publicKey is read from database and send back in the response.
|
||||
|
||||
The GraphQL-Client will read the publicKey of the other community from the returned response data and compare it with the data of the community-entry, which caused the getPublicKey-Request. If they match the community-entry will be updated by inserting the current timestamp in the verifiedAt-field of this community-entry.
|
||||
|
||||
This federation and verification logic will work the whole time and can be monitored by observing the communities-table changes. The Admin-UI will contain a Page to have a look on the current state of the communities table content.
|
||||
|
||||
### Prerequisits
|
||||
|
||||
Before starting in describing the details of the federation handshake, some prerequisits have to be defined.
|
||||
@ -235,7 +230,6 @@ For the first federation release the *DHT-Node* will be part of the *apollo serv
|
||||
| communityApiVersion.apiversion | keep existing value |
|
||||
| communityApiVersion.validFrom | exchangedData.API.validFrom |
|
||||
| communityApiVersion.verifiedAt | keep existing value |
|
||||
*
|
||||
3. After all received data is stored successfully, the *DHT-Node* starts the *stage2 - Authentication* of the federation handshake
|
||||
|
||||
### Stage2 - Authentication
|
||||
@ -284,8 +278,6 @@ As soon the *openConnection* request is invoked:
|
||||
3. check if the decrypted `parameter.signedAndEncryptedURL` is equals the selected url from the previous selected CommunityFederationEntry
|
||||
1. if not then break the further processing of this request by only writing an error-log event. There will be no answer to the invoker community, because this community will only go on with a `openConnectionRedirect`-request from this community.
|
||||
2. if yes then verify the signature of `parameter.signedAndEncryptedURL` with the `cf.pubKey` read in step 2 before
|
||||
3.
|
||||
4.
|
||||
|
||||
### Stage3 - Autorized Business Communication
|
||||
|
||||
|
||||
@ -0,0 +1,282 @@
|
||||
<mxfile host="65bd71144e">
|
||||
<diagram id="RqE3izjX3TYt3HTUOB95" name="Seite-1">
|
||||
<mxGraphModel dx="3343" dy="773" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2336" pageHeight="1654" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="2" value="Community&nbsp; "Gradido-Akademie"" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;fontSize=16;fontStyle=1;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-158.26" y="80" width="870" height="800" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="3" value="Gradido - technical Infrastructure-Overview<br><font style="font-size: 12px">State of 02.2023</font>" style="text;html=1;strokeColor=#82b366;fillColor=#d5e8d4;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;labelBorderColor=none;gradientColor=#97d077;" parent="1" vertex="1">
|
||||
<mxGeometry x="-1160" y="20" width="1880" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="4" value="<b>Backend-Modul</b><br>GraphQL-API" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="-118.25999999999999" y="269" width="540" height="101" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="7" value="CommunityServer DB" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=15;fontStyle=1;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="211.74" y="760" width="150" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="8" value="" style="endArrow=classic;startArrow=classic;html=1;fontSize=15;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;fillColor=#dae8fc;gradientColor=#7ea6e0;strokeColor=#6c8ebf;" parent="1" source="7" target="4" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="191.74" y="590" as="sourcePoint"/>
|
||||
<mxPoint x="241.74" y="540" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="15" value="<b>Layer 1:</b>" style="text;html=1;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;glass=0;labelBackgroundColor=none;fontSize=15;opacity=0;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-148.26" y="735" width="70" height="20" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="16" value="" style="endArrow=none;dashed=1;html=1;fontSize=15;fontColor=#000000;entryX=1.002;entryY=0.801;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" target="2" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="-158.26" y="720" as="sourcePoint"/>
|
||||
<mxPoint x="603.74" y="720" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="17" value="<b>Layer 2:</b>" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;glass=0;labelBackgroundColor=none;fontSize=15;fontColor=#000000;opacity=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-148.26" y="240" width="70" height="20" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="21" value=""<b>GDT-Server</b>" <br>base on cakephp + mySQL" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#fff2cc;strokeColor=#d6b656;gradientColor=#ffd966;" parent="1" vertex="1">
|
||||
<mxGeometry x="491.74" y="269" width="210" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="22" value="GDT-Server DB" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=15;fontStyle=1;gradientColor=#ffd966;" parent="1" vertex="1">
|
||||
<mxGeometry x="521.74" y="760" width="150" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="23" value="" style="endArrow=classic;startArrow=classic;html=1;fontSize=15;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="22" target="21" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="381.74" y="590" as="sourcePoint"/>
|
||||
<mxPoint x="586.6200000000001" y="370" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="24" value="" style="endArrow=classic;startArrow=classic;html=1;fontSize=15;fontColor=#000000;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" target="21" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="421.74" y="299" as="sourcePoint"/>
|
||||
<mxPoint x="401.74" y="479" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="25" value="<font style="font-size: 12px">json-<br>ajax-<br>request</font>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=15;fontColor=#000000;labelBackgroundColor=none;" parent="24" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.3429" relative="1" as="geometry">
|
||||
<mxPoint x="10" y="-28" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="30" value="" style="endArrow=none;dashed=1;html=1;fontSize=15;fontColor=#000000;entryX=1.002;entryY=0.401;entryDx=0;entryDy=0;entryPerimeter=0;exitX=0;exitY=0.4;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="-159.9999999999999" y="230" as="sourcePoint"/>
|
||||
<mxPoint x="711.7399999999999" y="230.79999999999995" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="31" value="<b>Layer 3:</b>" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;glass=0;labelBackgroundColor=none;fontSize=15;fontColor=#000000;opacity=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-148.26" y="90" width="70" height="20" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="32" value=""<b>Elopage</b>" <br>external Service-Portal" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="471.74" y="120" width="210" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="33" value=""<b>User-UI</b>"" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-48.25999999999999" y="120" width="200" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="34" value="" style="endArrow=classic;startArrow=classic;html=1;fontSize=15;fontColor=#000000;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.315;exitY=-0.05;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="4" target="33" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="351.74" y="420" as="sourcePoint"/>
|
||||
<mxPoint x="401.74" y="370" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="35" value="" style="endArrow=classic;startArrow=classic;html=1;fontSize=15;fontColor=#000000;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.395;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="21" target="32" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="576.24" y="310" as="sourcePoint"/>
|
||||
<mxPoint x="576.24" y="180" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="36" value="<span style="font-size: 12px">graphql</span>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=15;fontColor=#000000;labelBackgroundColor=none;" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="191.74" y="216" as="geometry">
|
||||
<mxPoint x="-169" y="-4" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="37" value="<font style="font-size: 12px">json-<br>request</font>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=15;fontColor=#000000;labelBackgroundColor=none;" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="551.74" y="216" as="geometry">
|
||||
<mxPoint x="-2" y="-15" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="39" style="edgeStyle=none;html=1;entryX=0.767;entryY=-0.017;entryDx=0;entryDy=0;startArrow=classic;startFill=1;entryPerimeter=0;" parent="1" source="38" target="4" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="40" value="graphql" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;" parent="39" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.4305" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="23" y="-1" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="38" value=""<b>Admin-UI</b>"" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="191.74" y="120" width="210" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="42" style="edgeStyle=none;html=1;entryX=0.145;entryY=0;entryDx=0;entryDy=4.35;entryPerimeter=0;startArrow=classic;startFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;fillColor=#dae8fc;gradientColor=#7ea6e0;strokeColor=#6c8ebf;" parent="1" source="41" target="7" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="41" value="<b>DHT-Modul</b><br>HyperSwarm" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-118.25999999999999" y="640" width="190" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="102" style="edgeStyle=none;html=1;fontSize=16;startArrow=classic;startFill=1;fillColor=#dae8fc;gradientColor=#7ea6e0;strokeColor=#6c8ebf;" parent="1" source="43" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="260" y="760" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="43" value="<b>Federation-Modul</b><br>GraphQL-API V2_0" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;dashed=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="-118.25999999999999" y="380" width="190" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="101" style="edgeStyle=none;html=1;fontSize=16;startArrow=classic;startFill=1;fillColor=#dae8fc;gradientColor=#7ea6e0;strokeColor=#6c8ebf;" parent="1" source="44" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="260" y="760" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="44" value="<b>Federation-Modul</b><br>GraphQL-API V1_x" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;dashed=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="-88.25999999999999" y="430" width="190" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="100" style="edgeStyle=none;html=1;entryX=0.335;entryY=0.013;entryDx=0;entryDy=0;entryPerimeter=0;fontSize=16;startArrow=classic;startFill=1;exitX=0.78;exitY=0.667;exitDx=0;exitDy=0;exitPerimeter=0;fillColor=#dae8fc;gradientColor=#7ea6e0;strokeColor=#6c8ebf;" parent="1" source="45" target="7" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="45" value="<b>Federation-Modul</b><br>GraphQL-API V1_1" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;dashed=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="-58.25999999999999" y="480" width="190" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="47" style="edgeStyle=none;html=1;entryX=0.333;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;exitX=0.996;exitY=0.633;exitDx=0;exitDy=0;exitPerimeter=0;fillColor=#dae8fc;gradientColor=#7ea6e0;strokeColor=#6c8ebf;" parent="1" source="46" target="7" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="46" value="<b>Federation-Modul</b><br>GraphQL-API V1_0" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-28.25999999999999" y="530" width="190" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="48" value="GraphQL-Client V1_0" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-108.25999999999999" y="289" width="180" height="31" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="49" value="GraphQL-Client V1_0" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-98.25999999999999" y="299" width="180" height="31" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="50" value="GraphQL-Client V1_0" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-88.25999999999999" y="309" width="180" height="31" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="51" value="GraphQL-Client V1_0" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#dae8fc;strokeColor=#6c8ebf;gradientColor=#7ea6e0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-78.25999999999999" y="319" width="180" height="31" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="52" value="Community "GallischesDorf-TBB"" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;verticalAlign=top;fontStyle=1;fontSize=16;gradientColor=#97d077;" parent="1" vertex="1">
|
||||
<mxGeometry x="-1148.26" y="80" width="628.26" height="800" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="54" value="<b>Backend-Modul</b><br>GraphQL-API" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#d5e8d4;strokeColor=#82b366;gradientColor=#97d077;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="-1108.26" y="269" width="568.26" height="101" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="55" value="CommunityServer DB" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=15;fontStyle=1;gradientColor=#97d077;" parent="1" vertex="1">
|
||||
<mxGeometry x="-1048.26" y="770" width="150" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="56" value="" style="endArrow=classic;startArrow=classic;html=1;fontSize=15;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;" parent="1" source="55" target="54" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="-798.26" y="590" as="sourcePoint"/>
|
||||
<mxPoint x="-748.26" y="540" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="57" value="<b>Layer 1:</b>" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;glass=0;labelBackgroundColor=none;fontSize=15;fontColor=#000000;opacity=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-1138.26" y="735" width="70" height="20" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="58" value="" style="endArrow=none;dashed=1;html=1;fontSize=15;fontColor=#000000;entryX=1.002;entryY=0.801;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" target="52" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="-1148.26" y="720" as="sourcePoint"/>
|
||||
<mxPoint x="-386.26" y="720" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="59" value="<b>Layer 2:</b>" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;glass=0;labelBackgroundColor=none;fontSize=15;fontColor=#000000;opacity=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-1138.26" y="240" width="70" height="20" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="65" value="" style="endArrow=none;dashed=1;html=1;fontSize=15;fontColor=#000000;exitX=0;exitY=0.4;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="-1149.9999999999998" y="230" as="sourcePoint"/>
|
||||
<mxPoint x="-520" y="231" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="66" value="<b>Layer 3:</b>" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;glass=0;labelBackgroundColor=none;fontSize=15;fontColor=#000000;opacity=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="-1138.26" y="90" width="70" height="20" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="68" value=""<b>User-UI</b>"" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#d5e8d4;strokeColor=#82b366;gradientColor=#97d077;" parent="1" vertex="1">
|
||||
<mxGeometry x="-1030" y="120" width="200" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="69" value="" style="endArrow=classic;startArrow=classic;html=1;fontSize=15;fontColor=#000000;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.315;exitY=-0.05;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="54" target="68" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="-638.26" y="420" as="sourcePoint"/>
|
||||
<mxPoint x="-588.26" y="370" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="71" value="<span style="font-size: 12px">graphql</span>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=15;fontColor=#000000;labelBackgroundColor=none;" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="-798.26" y="216" as="geometry">
|
||||
<mxPoint x="-169" y="-4" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="73" style="edgeStyle=none;html=1;entryX=0.767;entryY=-0.017;entryDx=0;entryDy=0;startArrow=classic;startFill=1;entryPerimeter=0;" parent="1" source="75" target="54" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="74" value="graphql" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;" parent="73" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.4305" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="23" y="-1" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="75" value=""<b>Admin-UI</b>"" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#d5e8d4;strokeColor=#82b366;gradientColor=#97d077;" parent="1" vertex="1">
|
||||
<mxGeometry x="-775" y="120" width="210" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="76" style="edgeStyle=none;html=1;entryX=0.855;entryY=0;entryDx=0;entryDy=4.35;entryPerimeter=0;startArrow=classic;startFill=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;" parent="1" source="77" target="55" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="90" style="edgeStyle=none;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="77" target="41" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="91" value="&nbsp;DHT-Socket Communication&nbsp;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=16;" parent="90" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.1307" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="77" value="<b>DHT-Modul</b><br>HyperSwarm" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#d5e8d4;strokeColor=#82b366;gradientColor=#97d077;" parent="1" vertex="1">
|
||||
<mxGeometry x="-745" y="640" width="190" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="87" style="edgeStyle=none;html=1;entryX=0.655;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;" parent="1" source="80" target="55" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="80" value="<b>Federation-Modul</b><br>GraphQL-API V1_1" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#d5e8d4;strokeColor=#82b366;gradientColor=#97d077;dashed=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="-760" y="500" width="190" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="81" style="edgeStyle=none;html=1;entryX=0.655;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;" parent="1" source="82" target="55" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="82" value="<b>Federation-Modul</b><br>GraphQL-API V1_0" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#d5e8d4;strokeColor=#82b366;gradientColor=#97d077;" parent="1" vertex="1">
|
||||
<mxGeometry x="-730" y="550" width="190" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="98" style="edgeStyle=none;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=16;startArrow=classic;startFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="85" target="45" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="99" value="graphQL-Handshake" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=16;" parent="98" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.5775" relative="1" as="geometry">
|
||||
<mxPoint x="28" y="-14" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="85" value="GraphQL-Client V1_1" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#d5e8d4;strokeColor=#82b366;gradientColor=#97d077;" parent="1" vertex="1">
|
||||
<mxGeometry x="-745" y="289" width="180" height="31" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="96" style="edgeStyle=none;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=16;startArrow=classic;startFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="86" target="46" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="97" value="graphQL-Handshake" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=16;" parent="96" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.5322" y="-1" relative="1" as="geometry">
|
||||
<mxPoint x="-11" y="16" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="86" value="GraphQL-Client V1_0" style="rounded=1;whiteSpace=wrap;html=1;fontSize=16;align=center;fillColor=#d5e8d4;strokeColor=#82b366;gradientColor=#97d077;" parent="1" vertex="1">
|
||||
<mxGeometry x="-730" y="314" width="180" height="31" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="92" style="edgeStyle=none;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fontSize=16;startArrow=classic;startFill=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="51" target="82" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="94" value="graphQL-Handshake" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=16;" parent="92" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.1267" y="2" relative="1" as="geometry">
|
||||
<mxPoint x="-93" y="56" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="93" style="edgeStyle=none;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fontSize=16;startArrow=classic;startFill=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="50" target="80" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="95" value="graphQL-Handshake" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=16;" parent="93" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.0706" relative="1" as="geometry">
|
||||
<mxPoint x="63" y="-60" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 61 KiB |
@ -11,7 +11,7 @@ Decimal.set({
|
||||
*/
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0061-event_refactoring',
|
||||
DB_VERSION: '0062-event_contribution_confirm',
|
||||
// DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '@/server/createServer'
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
|
||||
let query: any
|
||||
|
||||
// to do: We need a setup for the tests that closes the connection
|
||||
let con: any
|
||||
|
||||
beforeAll(async () => {
|
||||
const server = await createServer()
|
||||
con = server.con
|
||||
query = createTestClient(server.apollo).query
|
||||
DbCommunity.clear()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await con.close()
|
||||
})
|
||||
|
||||
describe('PublicKeyResolver', () => {
|
||||
const getPublicKeyQuery = `
|
||||
query {
|
||||
getPublicKey
|
||||
{
|
||||
publicKey
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
describe('getPublicKey', () => {
|
||||
beforeEach(async () => {
|
||||
const homeCom = new DbCommunity()
|
||||
homeCom.foreign = false
|
||||
homeCom.apiVersion = '1_0'
|
||||
homeCom.endPoint = 'endpoint-url'
|
||||
homeCom.publicKey = Buffer.from('homeCommunity-publicKey')
|
||||
await DbCommunity.insert(homeCom)
|
||||
})
|
||||
|
||||
it('returns homeCommunity-publicKey', async () => {
|
||||
await expect(query({ query: getPublicKeyQuery })).resolves.toMatchObject({
|
||||
data: {
|
||||
getPublicKey: {
|
||||
publicKey: expect.stringMatching('homeCommunity-publicKey'),
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -9,12 +9,12 @@ import { GetPublicKeyResult } from '../model/GetPublicKeyResult'
|
||||
export class PublicKeyResolver {
|
||||
@Query(() => GetPublicKeyResult)
|
||||
async getPublicKey(): Promise<GetPublicKeyResult> {
|
||||
logger.info(`getPublicKey()...`)
|
||||
logger.debug(`getPublicKey() via apiVersion=1_0 ...`)
|
||||
const homeCom = await DbCommunity.findOneOrFail({
|
||||
foreign: false,
|
||||
apiVersion: '1_0',
|
||||
})
|
||||
logger.info(`getPublicKey()... with publicKey=${homeCom.publicKey}`)
|
||||
logger.info(`getPublicKey()-1_0... return publicKey=${homeCom.publicKey}`)
|
||||
return new GetPublicKeyResult(homeCom.publicKey.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
"author": "Ulf Gebhardt <ulf.gebhardt@webcraft-media.de>",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"release": "scripts/release.sh"
|
||||
"release": "scripts/release.sh",
|
||||
"installAll": "yarn && cd database && yarn && cd ../frontend && yarn && cd ../admin && yarn && cd ../backend && yarn && cd ../e2e-tests && yarn && cd ../federation && yarn && cd ../dht-node && yarn && cd .."
|
||||
},
|
||||
"dependencies": {
|
||||
"auto-changelog": "^2.4.0",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user