mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
Merge remote-tracking branch 'origin/master' into
3466-introduce-community-selection-logic-in-transactionlink-page
This commit is contained in:
commit
29c08babcc
20
.github/workflows/test_backend.yml
vendored
20
.github/workflows/test_backend.yml
vendored
@ -43,18 +43,20 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Backend | docker-compose mariadb
|
||||
- name: docker-compose mariadb
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb
|
||||
|
||||
- name: Backend | install and build
|
||||
run: cd database && yarn && yarn build && cd ../config && yarn && cd ../backend && yarn && yarn build
|
||||
|
||||
- name: Sleep for 30 seconds
|
||||
run: sleep 30s
|
||||
shell: bash
|
||||
- name: wait for database to be ready
|
||||
run: docker run --rm --network gradido_internal-net busybox sh -c 'until nc -z mariadb 3306; do echo waiting for db; sleep 1; done;'
|
||||
|
||||
- name: Backend | docker-compose database
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
|
||||
- name: Backend | prepare database
|
||||
run: cd database && yarn up:backend_test
|
||||
|
||||
- name: Backend | Unit tests
|
||||
run: cd database && yarn && yarn build && cd ../config && yarn install && cd ../backend && yarn && yarn test
|
||||
- name: Backend | Unit tests
|
||||
run: cd backend && yarn test
|
||||
|
||||
lint:
|
||||
if: needs.files-changed.outputs.backend == 'true'
|
||||
@ -66,7 +68,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Backend | Lint
|
||||
run: cd database && yarn && cd ../config && yarn install && cd ../backend && yarn && yarn run lint
|
||||
run: cd database && yarn && cd ../backend && yarn && yarn run lint
|
||||
|
||||
locales:
|
||||
if: needs.files-changed.outputs.backend == 'true'
|
||||
|
||||
2
.github/workflows/test_database.yml
vendored
2
.github/workflows/test_database.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Database | docker-compose
|
||||
- name: docker-compose mariadb
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach mariadb
|
||||
|
||||
- name: Database | up
|
||||
|
||||
44
.github/workflows/test_dht_node.yml
vendored
44
.github/workflows/test_dht_node.yml
vendored
@ -31,15 +31,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build 'test' image
|
||||
run: |
|
||||
docker build --target test -t "gradido/dht-node:test" -f dht-node/Dockerfile .
|
||||
docker save "gradido/dht-node:test" > /tmp/dht-node.tar
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: docker-dht-node-test
|
||||
path: /tmp/dht-node.tar
|
||||
run: docker build --target test -t "gradido/dht-node:test" -f dht-node/Dockerfile .
|
||||
|
||||
lint:
|
||||
name: Lint - DHT Node
|
||||
@ -50,8 +42,8 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Lint
|
||||
run: cd database && yarn && cd ../config && yarn install && cd ../dht-node && yarn && yarn run lint
|
||||
- name: DHT-Node | Lint
|
||||
run: cd database && yarn && cd ../dht-node && yarn && yarn run lint
|
||||
|
||||
unit_test:
|
||||
name: Unit Tests - DHT Node
|
||||
@ -62,30 +54,18 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Download Docker Image
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: docker-dht-node-test
|
||||
path: /tmp
|
||||
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/dht-node.tar
|
||||
|
||||
- name: docker-compose mariadb
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb
|
||||
|
||||
- name: Sleep for 30 seconds
|
||||
run: sleep 30s
|
||||
shell: bash
|
||||
- name: DHT-Node | install and build
|
||||
run: cd database && yarn && yarn build && cd ../config && yarn && cd ../dht-node && yarn && yarn build
|
||||
|
||||
- name: docker-compose database
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
|
||||
- name: wait for database to be ready
|
||||
run: docker run --rm --network gradido_internal-net busybox sh -c 'until nc -z mariadb 3306; do echo waiting for db; sleep 1; done;'
|
||||
|
||||
- name: Sleep for 30 seconds
|
||||
run: sleep 30s
|
||||
shell: bash
|
||||
- name: DHT-Node | prepare database
|
||||
run: cd database && yarn up:dht_test
|
||||
|
||||
- name: DHT-Node | Unit tests
|
||||
run: cd dht-node && yarn test
|
||||
|
||||
- name: Unit tests
|
||||
run: cd database && yarn && yarn build && cd ../config && yarn install && cd ../dht-node && yarn && yarn test
|
||||
#- name: Unit tests
|
||||
# run: docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net --rm gradido/dht-node:test yarn run test
|
||||
|
||||
36
.github/workflows/test_e2e.yml
vendored
36
.github/workflows/test_e2e.yml
vendored
@ -13,25 +13,12 @@ jobs:
|
||||
- name: Boot up test system | docker-compose mariadb
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach mariadb
|
||||
|
||||
- name: Sleep for 10 seconds
|
||||
run: sleep 10s
|
||||
|
||||
- name: Boot up test system | seed backend
|
||||
- name: Prepare test system
|
||||
run: |
|
||||
sudo chown runner:docker -R *
|
||||
cd database
|
||||
yarn && yarn dev_reset
|
||||
cd ../config
|
||||
yarn install
|
||||
cd ../backend
|
||||
yarn && yarn seed
|
||||
|
||||
- name: Boot up test system | docker-compose backend, frontend, admin, nginx, mailserver
|
||||
run: |
|
||||
cd backend
|
||||
cp .env.test_e2e .env
|
||||
cd ..
|
||||
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps backend frontend admin nginx mailserver
|
||||
cd database && yarn && yarn build
|
||||
cd ../config && yarn
|
||||
cd ../backend && yarn
|
||||
|
||||
- name: End-to-end tests | prepare
|
||||
run: |
|
||||
@ -41,6 +28,21 @@ jobs:
|
||||
cd e2e-tests/
|
||||
yarn
|
||||
|
||||
- name: wait for database to be ready
|
||||
run: docker run --rm --network gradido_internal-net busybox sh -c 'until nc -z mariadb 3306; do echo waiting for db; sleep 1; done;'
|
||||
|
||||
- name: Boot up test system | seed backend
|
||||
run: |
|
||||
cd database && yarn dev_reset
|
||||
cd ../backend && yarn seed
|
||||
|
||||
- name: Boot up test system | docker-compose backend, frontend, admin, nginx, mailserver
|
||||
run: |
|
||||
cd backend
|
||||
cp .env.test_e2e .env
|
||||
cd ..
|
||||
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps backend frontend admin nginx mailserver
|
||||
|
||||
- name: End-to-end tests | run tests
|
||||
id: e2e-tests
|
||||
run: |
|
||||
|
||||
23
.github/workflows/test_federation.yml
vendored
23
.github/workflows/test_federation.yml
vendored
@ -72,20 +72,15 @@ jobs:
|
||||
|
||||
- name: docker-compose mariadb
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb
|
||||
|
||||
- name: Sleep for 30 seconds
|
||||
run: sleep 30s
|
||||
shell: bash
|
||||
|
||||
- name: docker-compose database
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
|
||||
- name: Federation | install and build
|
||||
run: cd database && yarn && yarn build && cd ../config && yarn && cd ../federation && yarn && yarn build
|
||||
|
||||
- name: Sleep for 30 seconds
|
||||
run: sleep 30s
|
||||
shell: bash
|
||||
- name: wait for database to be ready
|
||||
run: docker run --rm --network gradido_internal-net busybox sh -c 'until nc -z mariadb 3306; do echo waiting for db; sleep 1; done;'
|
||||
|
||||
#- name: Unit tests
|
||||
# run: cd database && yarn && yarn build && cd ../dht-node && yarn && yarn test
|
||||
- name: Unit tests
|
||||
run: |
|
||||
docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net --rm gradido/federation:test yarn run test
|
||||
- name: Federation | prepare database
|
||||
run: cd database && yarn up:federation_test
|
||||
|
||||
- name: Federation | Unit tests
|
||||
run: docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net --rm gradido/federation:test yarn run test
|
||||
|
||||
12
.vscode/settings.json
vendored
12
.vscode/settings.json
vendored
@ -1,5 +1,17 @@
|
||||
{
|
||||
"git.ignoreLimitWarning": true,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports.biome": "explicit"
|
||||
}
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports.biome": "explicit"
|
||||
}
|
||||
},
|
||||
"sqltools.connections": [
|
||||
{
|
||||
"mysqlOptions": {
|
||||
|
||||
25
CHANGELOG.md
25
CHANGELOG.md
@ -4,8 +4,31 @@ All notable changes to this project will be documented in this file. Dates are d
|
||||
|
||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
|
||||
#### [2.5.1](https://github.com/gradido/gradido/compare/2.3.1...2.5.1)
|
||||
#### [2.5.2](https://github.com/gradido/gradido/compare/2.3.1...2.5.2)
|
||||
|
||||
- refactor(other): use biome instead of eslint [`#3472`](https://github.com/gradido/gradido/pull/3472)
|
||||
- fix(frontend): set explicit page size for admin and moderator user on information page [`#3474`](https://github.com/gradido/gradido/pull/3474)
|
||||
- fix(backend): humhub sync on edge cases [`#3471`](https://github.com/gradido/gradido/pull/3471)
|
||||
- fix(frontend): community messsages reload [`#3476`](https://github.com/gradido/gradido/pull/3476)
|
||||
- refactor(frontend): show skeleton only as long as needed [`#3477`](https://github.com/gradido/gradido/pull/3477)
|
||||
- refactor(database): faster db version check [`#3473`](https://github.com/gradido/gradido/pull/3473)
|
||||
- feat(frontend): humhub project auto register for legacy user [`#3469`](https://github.com/gradido/gradido/pull/3469)
|
||||
- fix(backend): humhub username case with initails and empty alias [`#3470`](https://github.com/gradido/gradido/pull/3470)
|
||||
- feat(frontend): gms improvements [`#3468`](https://github.com/gradido/gradido/pull/3468)
|
||||
- feat(other): x-com tx per link concept [`#3464`](https://github.com/gradido/gradido/pull/3464)
|
||||
- fix(frontend): update texte, fix minor bugs in new overview [`#3463`](https://github.com/gradido/gradido/pull/3463)
|
||||
- fix(admin): update field key according to changed graphlq request [`#3462`](https://github.com/gradido/gradido/pull/3462)
|
||||
- refactor(admin): admin contribution list [`#3460`](https://github.com/gradido/gradido/pull/3460)
|
||||
- fix(admin): date formatting, hashtag copy filter, no-select [`#3461`](https://github.com/gradido/gradido/pull/3461)
|
||||
- feat(backend): 3347 modify overview page with humhub- and usersearch-card [`#3451`](https://github.com/gradido/gradido/pull/3451)
|
||||
- feat(admin): add ai chat [`#3456`](https://github.com/gradido/gradido/pull/3456)
|
||||
- feat(backend): upgrade typescript [`#3458`](https://github.com/gradido/gradido/pull/3458)
|
||||
- build(other): increase nodejs version in deployment [`#3457`](https://github.com/gradido/gradido/pull/3457)
|
||||
- feat(frontend): use gear instead fingerprint icon, replace svg icon [`#3454`](https://github.com/gradido/gradido/pull/3454)
|
||||
- fix(frontend): auth style on mobile menu like in desktop [`#3453`](https://github.com/gradido/gradido/pull/3453)
|
||||
- feat(admin): optimize contribution list for ai usage [`#3452`](https://github.com/gradido/gradido/pull/3452)
|
||||
- chore(release): v2.5.1 beta [`#3455`](https://github.com/gradido/gradido/pull/3455)
|
||||
- feat(frontend): project branding and login forwarding to circle [`#3443`](https://github.com/gradido/gradido/pull/3443)
|
||||
- refactor(frontend): contribution form refactor [`#3442`](https://github.com/gradido/gradido/pull/3442)
|
||||
- feat(backend): correct user data transfer to gms [`#3433`](https://github.com/gradido/gradido/pull/3433)
|
||||
- feat(backend): switch marker colors of community location and user location [`#3445`](https://github.com/gradido/gradido/pull/3445)
|
||||
|
||||
@ -1 +0,0 @@
|
||||
v18.20
|
||||
@ -3,7 +3,7 @@
|
||||
"description": "Administration Interface for Gradido",
|
||||
"main": "index.js",
|
||||
"author": "Moriz Wahl",
|
||||
"version": "2.5.1",
|
||||
"version": "2.5.2",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"start": "node run/server.js",
|
||||
|
||||
@ -71,7 +71,8 @@ const defaultData = {
|
||||
const defaultUser = {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
humhubUsername: 'peter.lustig',
|
||||
uniqueUsername: 'peter.lustig',
|
||||
publicName: 'PeLu',
|
||||
createdAt: new Date().toString(),
|
||||
emailContact: {
|
||||
email: 'peter.lustig@example.com',
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
{{ $t('filter.byEmail') }}
|
||||
</BTooltip>
|
||||
|
||||
{{ contribution.user.humhubUsername }}
|
||||
{{ contribution.user.publicName }}
|
||||
|
||||
<span>
|
||||
<a
|
||||
@ -103,7 +103,7 @@ const humhubProfileLink = computed(() => {
|
||||
if (url.endsWith('/')) {
|
||||
url = url.slice(0, -1)
|
||||
}
|
||||
return `${url}/u/${props.contribution.humhubUsername}`
|
||||
return `${url}/u/${props.contribution.user.userIdentifier}`
|
||||
})
|
||||
|
||||
const messages = ref([])
|
||||
|
||||
@ -13,7 +13,8 @@ query adminListContributions(
|
||||
email
|
||||
}
|
||||
...UserCommonFields
|
||||
humhubUsername
|
||||
publicName
|
||||
userIdentifier
|
||||
createdAt
|
||||
}
|
||||
amount
|
||||
|
||||
@ -135,6 +135,7 @@ const noHashtag = ref(null)
|
||||
const hideResubmissionModel = ref(true)
|
||||
|
||||
const formatDateOrDash = (value) => (value ? new Date(value).toLocaleDateString() : '—')
|
||||
|
||||
const baseFields = {
|
||||
firstName: { key: 'user.firstName', label: t('firstname'), class: 'no-select' },
|
||||
lastName: { key: 'user.lastName', label: t('lastname'), class: 'no-select' },
|
||||
@ -181,6 +182,7 @@ const fields = computed(
|
||||
[
|
||||
baseFields.firstName,
|
||||
baseFields.lastName,
|
||||
baseFields.amount,
|
||||
baseFields.memo,
|
||||
baseFields.contributionDate,
|
||||
baseFields.createdAt,
|
||||
|
||||
@ -40,6 +40,10 @@ export default defineConfig(async ({ command }) => {
|
||||
host: CONFIG.ADMIN_MODULE_HOST, // '0.0.0.0',
|
||||
port: CONFIG.ADMIN_MODULE_PORT, // 8080,
|
||||
},
|
||||
preview: {
|
||||
host: CONFIG.ADMIN_MODULE_HOST, // '0.0.0.0',
|
||||
port: CONFIG.ADMIN_MODULE_PORT, // 8080,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
node_modules
|
||||
**/*.min.js
|
||||
build
|
||||
coverage
|
||||
@ -1,213 +0,0 @@
|
||||
// eslint-disable-next-line import/no-commonjs, import/unambiguous
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['prettier', '@typescript-eslint', 'type-graphql', 'import', 'n', 'promise'],
|
||||
extends: [
|
||||
'standard',
|
||||
'eslint:recommended',
|
||||
'plugin:prettier/recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:import/typescript',
|
||||
'plugin:security/recommended',
|
||||
'plugin:@eslint-community/eslint-comments/recommended',
|
||||
],
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
project: ['./tsconfig.json', '**/tsconfig.json'],
|
||||
},
|
||||
node: true,
|
||||
},
|
||||
// the parser cannot handle the split sodium import
|
||||
'import/ignore': ['sodium-native'],
|
||||
},
|
||||
rules: {
|
||||
'no-console': 'error',
|
||||
camelcase: ['error', { allow: ['FederationClient_*', 'crypto_*', 'randombytes_random'] }],
|
||||
'no-debugger': 'error',
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
htmlWhitespaceSensitivity: 'ignore',
|
||||
},
|
||||
],
|
||||
// import
|
||||
'import/export': 'error',
|
||||
// 'import/no-deprecated': 'error',
|
||||
'import/no-empty-named-blocks': 'error',
|
||||
'import/no-extraneous-dependencies': 'error',
|
||||
'import/no-mutable-exports': 'error',
|
||||
'import/no-unused-modules': 'error',
|
||||
'import/no-named-as-default': 'error',
|
||||
'import/no-named-as-default-member': 'error',
|
||||
'import/no-amd': 'error',
|
||||
'import/no-commonjs': 'error',
|
||||
'import/no-import-module-exports': 'error',
|
||||
'import/no-nodejs-modules': 'off',
|
||||
'import/unambiguous': 'error',
|
||||
'import/default': 'error',
|
||||
'import/namespace': 'error',
|
||||
'import/no-absolute-path': 'error',
|
||||
'import/no-cycle': 'error',
|
||||
'import/no-dynamic-require': 'error',
|
||||
'import/no-internal-modules': 'off',
|
||||
'import/no-relative-packages': 'error',
|
||||
'import/no-relative-parent-imports': [
|
||||
'error',
|
||||
{ ignore: ['@/*', 'random-bigint', 'sodium-native'] },
|
||||
],
|
||||
'import/no-self-import': 'error',
|
||||
'import/no-unresolved': 'error',
|
||||
'import/no-useless-path-segments': 'error',
|
||||
'import/no-webpack-loader-syntax': 'error',
|
||||
'import/consistent-type-specifier-style': 'error',
|
||||
'import/exports-last': 'off',
|
||||
'import/extensions': 'error',
|
||||
'import/first': 'error',
|
||||
'import/group-exports': 'off',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-anonymous-default-export': 'error',
|
||||
'import/no-default-export': 'error',
|
||||
'import/no-duplicates': 'error',
|
||||
'import/no-named-default': 'error',
|
||||
'import/no-namespace': 'error',
|
||||
'import/no-unassigned-import': 'error',
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
||||
'newlines-between': 'always',
|
||||
pathGroups: [
|
||||
{
|
||||
pattern: '@?*/**',
|
||||
group: 'external',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: '@/**',
|
||||
group: 'external',
|
||||
position: 'after',
|
||||
},
|
||||
],
|
||||
alphabetize: {
|
||||
order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */,
|
||||
caseInsensitive: true /* ignore case. Options: [true, false] */,
|
||||
},
|
||||
distinctGroup: true,
|
||||
},
|
||||
],
|
||||
'import/prefer-default-export': 'off',
|
||||
// n
|
||||
'n/handle-callback-err': 'error',
|
||||
'n/no-callback-literal': 'error',
|
||||
'n/no-exports-assign': 'error',
|
||||
'n/no-extraneous-import': 'error',
|
||||
'n/no-extraneous-require': 'error',
|
||||
'n/no-hide-core-modules': 'error',
|
||||
'n/no-missing-import': 'off', // not compatible with typescript
|
||||
'n/no-missing-require': 'error',
|
||||
'n/no-new-require': 'error',
|
||||
'n/no-path-concat': 'error',
|
||||
'n/no-process-exit': 'error',
|
||||
'n/no-unpublished-bin': 'error',
|
||||
'n/no-unpublished-import': 'off', // TODO need to exclude seeds
|
||||
'n/no-unpublished-require': 'error',
|
||||
'n/no-unsupported-features': ['error', { ignores: ['modules'] }],
|
||||
'n/no-unsupported-features/es-builtins': 'error',
|
||||
'n/no-unsupported-features/es-syntax': 'error',
|
||||
'n/no-unsupported-features/node-builtins': 'error',
|
||||
'n/process-exit-as-throw': 'error',
|
||||
'n/shebang': 'error',
|
||||
'n/callback-return': 'error',
|
||||
'n/exports-style': 'error',
|
||||
'n/file-extension-in-import': 'off',
|
||||
'n/global-require': 'error',
|
||||
'n/no-mixed-requires': 'error',
|
||||
'n/no-process-env': 'error',
|
||||
'n/no-restricted-import': 'error',
|
||||
'n/no-restricted-require': 'error',
|
||||
'n/no-sync': 'error',
|
||||
'n/prefer-global/buffer': 'error',
|
||||
'n/prefer-global/console': 'error',
|
||||
'n/prefer-global/process': 'error',
|
||||
'n/prefer-global/text-decoder': 'error',
|
||||
'n/prefer-global/text-encoder': 'error',
|
||||
'n/prefer-global/url': 'error',
|
||||
'n/prefer-global/url-search-params': 'error',
|
||||
'n/prefer-promises/dns': 'error',
|
||||
'n/prefer-promises/fs': 'error',
|
||||
// promise
|
||||
'promise/catch-or-return': 'error',
|
||||
'promise/no-return-wrap': 'error',
|
||||
'promise/param-names': 'error',
|
||||
'promise/always-return': 'error',
|
||||
'promise/no-native': 'off',
|
||||
'promise/no-nesting': 'warn',
|
||||
'promise/no-promise-in-callback': 'warn',
|
||||
'promise/no-callback-in-promise': 'warn',
|
||||
'promise/avoid-new': 'warn',
|
||||
'promise/no-new-statics': 'error',
|
||||
'promise/no-return-in-finally': 'warn',
|
||||
'promise/valid-params': 'warn',
|
||||
'promise/prefer-await-to-callbacks': 'error',
|
||||
'promise/no-multiple-resolved': 'error',
|
||||
// eslint comments
|
||||
'@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
|
||||
'@eslint-community/eslint-comments/no-restricted-disable': 'error',
|
||||
'@eslint-community/eslint-comments/no-use': 'off',
|
||||
'@eslint-community/eslint-comments/require-description': 'off',
|
||||
},
|
||||
overrides: [
|
||||
// only for ts files
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
'plugin:@typescript-eslint/strict',
|
||||
'plugin:type-graphql/recommended',
|
||||
],
|
||||
rules: {
|
||||
// allow explicitly defined dangling promises
|
||||
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
|
||||
'no-void': ['error', { allowAsStatement: true }],
|
||||
// ignore prefer-regexp-exec rule to allow string.match(regex)
|
||||
'@typescript-eslint/prefer-regexp-exec': 'off',
|
||||
// this should not run on ts files: https://github.com/import-js/eslint-plugin-import/issues/2215#issuecomment-911245486
|
||||
'import/unambiguous': 'off',
|
||||
// this is not compatible with typeorm, due to joined tables can be null, but are not defined as nullable
|
||||
'@typescript-eslint/no-unnecessary-condition': 'off',
|
||||
},
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json', '**/tsconfig.json'],
|
||||
// this is to properly reference the referenced project database without requirement of compiling it
|
||||
// eslint-disable-next-line camelcase
|
||||
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.test.ts'],
|
||||
plugins: ['jest'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
rules: {
|
||||
'jest/no-disabled-tests': 'error',
|
||||
'jest/no-focused-tests': 'error',
|
||||
'jest/no-identical-title': 'error',
|
||||
'jest/prefer-to-have-length': 'error',
|
||||
'jest/valid-expect': 'error',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'jest/unbound-method': 'error',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
module.exports = {
|
||||
printWidth: 100,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
quoteProps: "as-needed",
|
||||
jsxSingleQuote: true,
|
||||
trailingComma: "all",
|
||||
bracketSpacing: true,
|
||||
bracketSameLine: false,
|
||||
arrowParens: "always",
|
||||
endOfLine: "auto",
|
||||
};
|
||||
@ -7,7 +7,7 @@ module.exports = {
|
||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
lines: 78,
|
||||
lines: 77,
|
||||
},
|
||||
},
|
||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||
|
||||
@ -57,6 +57,20 @@
|
||||
"fileNameSep" : "_",
|
||||
"numBackups" : 30
|
||||
},
|
||||
"gms":
|
||||
{
|
||||
"type": "dateFile",
|
||||
"filename": "../logs/backend/gms.log",
|
||||
"pattern": "yyyy-MM-dd",
|
||||
"layout":
|
||||
{
|
||||
"type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m"
|
||||
},
|
||||
"compress": true,
|
||||
"keepFileExt" : true,
|
||||
"fileNameSep" : "_",
|
||||
"numBackups" : 30
|
||||
},
|
||||
"errorFile":
|
||||
{
|
||||
"type": "dateFile",
|
||||
@ -137,6 +151,16 @@
|
||||
"level": "debug",
|
||||
"enableCallStack": true
|
||||
},
|
||||
"gms":
|
||||
{
|
||||
"appenders":
|
||||
[
|
||||
"gms",
|
||||
"errors"
|
||||
],
|
||||
"level": "debug",
|
||||
"enableCallStack": true
|
||||
},
|
||||
"http":
|
||||
{
|
||||
"appenders":
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gradido-backend",
|
||||
"version": "2.5.1",
|
||||
"version": "2.5.2",
|
||||
"description": "Gradido unified backend providing an API-Service for Gradido Transactions",
|
||||
"main": "src/index.ts",
|
||||
"repository": "https://github.com/gradido/gradido/backend",
|
||||
@ -12,12 +12,12 @@
|
||||
"clean": "tsc --build --clean",
|
||||
"start": "cross-env TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js",
|
||||
"dev": "cross-env TZ=UTC nodemon -w src --ext ts,pug,json,css --exec ts-node -r tsconfig-paths/register src/index.ts",
|
||||
"lint": "eslint --max-warnings=0 .",
|
||||
"test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --forceExit --detectOpenHandles",
|
||||
"lint": "biome check --error-on-warnings .",
|
||||
"lint:fix": "biome check --error-on-warnings . --write",
|
||||
"test": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_backend jest --runInBand --forceExit --detectOpenHandles",
|
||||
"seed": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/seeds/index.ts",
|
||||
"klicktipp": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/util/executeKlicktipp.ts",
|
||||
"gmsusers": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/seeds/gmsUsers.ts",
|
||||
"gmsuserList": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/seeds/gmsUserList.ts",
|
||||
"gmsusers": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/apis/gms/ExportUsers.ts",
|
||||
"humhubUserExport": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/apis/humhub/ExportUsers.ts",
|
||||
"locales": "scripts/sort.sh"
|
||||
},
|
||||
@ -59,7 +59,7 @@
|
||||
"xregexp": "^5.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "^3.2.1",
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@types/email-templates": "^10.0.1",
|
||||
"@types/express": "^4.17.12",
|
||||
"@types/faker": "^5.5.9",
|
||||
@ -71,20 +71,7 @@
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@types/sodium-native": "^2.3.5",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"apollo-server-testing": "^2.25.2",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-standard": "^17.0.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.4",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-n": "^15.7.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-security": "^1.7.1",
|
||||
"eslint-plugin-type-graphql": "^1.0.0",
|
||||
"faker": "^5.5.3",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"jest": "^27.2.4",
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
import axios from 'axios'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
@ -1,13 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { CONFIG } from '@/config'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
// eslint-disable-next-line import/no-relative-parent-imports
|
||||
import KlicktippConnector from 'klicktipp-api'
|
||||
|
||||
const klicktippConnector = new KlicktippConnector()
|
||||
@ -18,7 +11,9 @@ export const subscribe = async (
|
||||
firstName?: string,
|
||||
lastName?: string,
|
||||
): Promise<boolean> => {
|
||||
if (!CONFIG.KLICKTIPP) return true
|
||||
if (!CONFIG.KLICKTIPP) {
|
||||
return true
|
||||
}
|
||||
const fields = {
|
||||
fieldFirstName: firstName,
|
||||
fieldLastName: lastName,
|
||||
@ -29,7 +24,9 @@ export const subscribe = async (
|
||||
}
|
||||
|
||||
export const unsubscribe = async (email: string): Promise<boolean> => {
|
||||
if (!CONFIG.KLICKTIPP) return true
|
||||
if (!CONFIG.KLICKTIPP) {
|
||||
return true
|
||||
}
|
||||
const isLogin = await loginKlicktippUser()
|
||||
if (isLogin) {
|
||||
return await klicktippConnector.unsubscribe(email)
|
||||
@ -38,12 +35,14 @@ export const unsubscribe = async (email: string): Promise<boolean> => {
|
||||
}
|
||||
|
||||
export const getKlickTippUser = async (email: string): Promise<any> => {
|
||||
if (!CONFIG.KLICKTIPP) return true
|
||||
if (!CONFIG.KLICKTIPP) {
|
||||
return true
|
||||
}
|
||||
const isLogin = await loginKlicktippUser()
|
||||
if (isLogin) {
|
||||
try {
|
||||
return klicktippConnector.subscriberGet(await klicktippConnector.subscriberSearch(email))
|
||||
} catch (e) {
|
||||
} catch (_e) {
|
||||
logger.error('Could not find subscriber', email)
|
||||
return false
|
||||
}
|
||||
@ -52,7 +51,9 @@ export const getKlickTippUser = async (email: string): Promise<any> => {
|
||||
}
|
||||
|
||||
export const loginKlicktippUser = async (): Promise<boolean> => {
|
||||
if (!CONFIG.KLICKTIPP) return true
|
||||
if (!CONFIG.KLICKTIPP) {
|
||||
return true
|
||||
}
|
||||
return await klicktippConnector.login(CONFIG.KLICKTIPP_USER, CONFIG.KLICKTIPP_PASSWORD)
|
||||
}
|
||||
|
||||
@ -62,7 +63,9 @@ export const addFieldsToSubscriber = async (
|
||||
newemail = '',
|
||||
newsmsnumber = '',
|
||||
) => {
|
||||
if (!CONFIG.KLICKTIPP) return true
|
||||
if (!CONFIG.KLICKTIPP) {
|
||||
return true
|
||||
}
|
||||
const isLogin = await loginKlicktippUser()
|
||||
if (isLogin) {
|
||||
try {
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable security/detect-object-injection */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
|
||||
import { Connection } from '@dbTools/typeorm'
|
||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||
import { gql, GraphQLClient } from 'graphql-request'
|
||||
import { GraphQLClient, gql } from 'graphql-request'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId'
|
||||
@ -34,16 +34,15 @@ function getTransactionTypeString(id: TransactionTypeId): string {
|
||||
* A Singleton class defines the `getInstance` method that lets clients access
|
||||
* the unique singleton instance.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
||||
|
||||
export class DltConnectorClient {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static instance: DltConnectorClient
|
||||
client: GraphQLClient
|
||||
/**
|
||||
* The Singleton's constructor should always be private to prevent direct
|
||||
* construction calls with the `new` operator.
|
||||
*/
|
||||
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
|
||||
|
||||
private constructor() {}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,10 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
|
||||
import { entities } from '@entity/index'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
// import { createTestClient } from 'apollo-server-testing'
|
||||
|
||||
@ -13,43 +6,29 @@ import { User as DbUser } from '@entity/User'
|
||||
import { CONFIG } from '@/config'
|
||||
import { getHomeCommunity } from '@/graphql/resolver/util/communities'
|
||||
import { sendUserToGms } from '@/graphql/resolver/util/sendUserToGms'
|
||||
import { createServer } from '@/server/createServer'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
import { checkDBVersion } from '@/typeorm/DBVersion'
|
||||
import { Connection } from '@/typeorm/connection'
|
||||
|
||||
CONFIG.EMAIL = false
|
||||
// use force to copy over all user even if gmsRegistered is set to true
|
||||
const forceMode = process.argv.includes('--force')
|
||||
|
||||
const context = {
|
||||
token: '',
|
||||
setHeaders: {
|
||||
push: (value: { key: string; value: string }): void => {
|
||||
context.token = value.value
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
forEach: (): void => {},
|
||||
},
|
||||
clientTimezoneOffset: 0,
|
||||
}
|
||||
|
||||
export const cleanDB = async () => {
|
||||
// this only works as long we do not have foreign key constraints
|
||||
for (const entity of entities) {
|
||||
await resetEntity(entity)
|
||||
async function main() {
|
||||
// open mysql connection
|
||||
const con = await Connection.getInstance()
|
||||
if (!con?.isConnected) {
|
||||
logger.fatal(`Couldn't open connection to database!`)
|
||||
throw new Error(`Fatal: Couldn't open connection to database`)
|
||||
}
|
||||
}
|
||||
|
||||
const resetEntity = async (entity: any) => {
|
||||
const items = await entity.find({ withDeleted: true })
|
||||
if (items.length > 0) {
|
||||
const ids = items.map((e: any) => e.id)
|
||||
await entity.delete(ids)
|
||||
// check for correct database version
|
||||
const dbVersion = await checkDBVersion(CONFIG.DB_VERSION)
|
||||
if (!dbVersion) {
|
||||
logger.fatal('Fatal: Database Version incorrect')
|
||||
throw new Error('Fatal: Database Version incorrect')
|
||||
}
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
const server = await createServer(context)
|
||||
// const seedClient = createTestClient(server.apollo)
|
||||
const { con } = server
|
||||
|
||||
const homeCom = await getHomeCommunity()
|
||||
if (homeCom.gmsApiKey === null) {
|
||||
@ -59,11 +38,11 @@ const run = async () => {
|
||||
const userIds = await DbUser.createQueryBuilder()
|
||||
.select('id')
|
||||
.where({ foreign: false })
|
||||
// .andWhere('deleted_at is null')
|
||||
// .andWhere({ gmsRegistered: false })
|
||||
.andWhere('deleted_at is null')
|
||||
.getRawMany()
|
||||
logger.debug('userIds:', userIds)
|
||||
|
||||
let alreadyUpdatedUserCount = 0
|
||||
for (const idStr of userIds) {
|
||||
logger.debug('Id:', idStr.id)
|
||||
const user = await DbUser.findOne({
|
||||
@ -73,11 +52,11 @@ const run = async () => {
|
||||
if (user) {
|
||||
logger.debug('found local User:', user)
|
||||
if (user.gmsAllowed) {
|
||||
await sendUserToGms(user, homeCom)
|
||||
await sendUserToGms(user, homeCom, forceMode)
|
||||
/*
|
||||
const gmsUser = new GmsUser(user)
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
|
||||
if (await createGmsUser(homeCom.gmsApiKey, gmsUser)) {
|
||||
logger.debug('GMS user published successfully:', gmsUser)
|
||||
user.gmsRegistered = true
|
||||
@ -93,10 +72,16 @@ const run = async () => {
|
||||
logger.debug('GMS-Publishing not allowed by user settings:', user)
|
||||
}
|
||||
}
|
||||
alreadyUpdatedUserCount++
|
||||
process.stdout.write(`updated user: ${alreadyUpdatedUserCount}/${userIds.length}\r`)
|
||||
}
|
||||
logger.info('##gms## publishing all local users successful...')
|
||||
|
||||
await con.close()
|
||||
await con.destroy()
|
||||
}
|
||||
|
||||
void run()
|
||||
main().catch((e) => {
|
||||
// biome-ignore lint/suspicious/noConsole: logger isn't used here
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
})
|
||||
@ -1,7 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
import axios from 'axios'
|
||||
|
||||
import { httpAgent, httpsAgent } from '@/apis/ConnectionAgents'
|
||||
@ -33,10 +29,10 @@ export async function communityList(): Promise<GmsCommunity[] | string | undefin
|
||||
throw new LogError('HTTP Status Error in community/list:', result.status, result.statusText)
|
||||
}
|
||||
logger.debug('responseData:', result.data.responseData.data)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
|
||||
// const gmsCom = JSON.parse(result.data.responseData.data)
|
||||
// logger.debug('gmsCom:', gmsCom)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
|
||||
return result.data.responseData.data
|
||||
} catch (error: any) {
|
||||
logger.error('Error in Get community/list:', error)
|
||||
@ -69,10 +65,10 @@ export async function userList(): Promise<GmsUser[] | string | undefined> {
|
||||
)
|
||||
}
|
||||
logger.debug('responseData:', result.data.responseData.data)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
|
||||
// const gmsUser = JSON.parse(result.data.responseData.data)
|
||||
// logger.debug('gmsUser:', gmsUser)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
|
||||
return result.data.responseData.data
|
||||
} catch (error: any) {
|
||||
logger.error('Error in Get community-user/list:', error)
|
||||
@ -105,10 +101,10 @@ export async function userByUuid(uuid: string): Promise<GmsUser[] | string | und
|
||||
)
|
||||
}
|
||||
logger.debug('responseData:', result.data.responseData.data)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
|
||||
// const gmsUser = JSON.parse(result.data.responseData.data)
|
||||
// logger.debug('gmsUser:', gmsUser)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
|
||||
return result.data.responseData.data
|
||||
} catch (error: any) {
|
||||
logger.error('Error in Get community-user/list:', error)
|
||||
@ -139,13 +135,16 @@ export async function createGmsUser(apiKey: string, user: GmsUser): Promise<bool
|
||||
throw new LogError('HTTP Status Error in community-user:', result.status, result.statusText)
|
||||
}
|
||||
logger.debug('responseData:', result.data.responseData)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
|
||||
// const gmsUser = JSON.parse(result.data.responseData)
|
||||
// logger.debug('gmsUser:', gmsUser)
|
||||
return true
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error in post community-user:', error)
|
||||
throw new LogError(error.message)
|
||||
if (error instanceof Error) {
|
||||
throw new LogError(error.message)
|
||||
}
|
||||
throw new LogError('Unknown error in post community-user')
|
||||
}
|
||||
} else {
|
||||
logger.info('GMS-Communication disabled per ConfigKey GMS_ACTIVE=false!')
|
||||
@ -174,13 +173,16 @@ export async function updateGmsUser(apiKey: string, user: GmsUser): Promise<bool
|
||||
throw new LogError('HTTP Status Error in community-user:', result.status, result.statusText)
|
||||
}
|
||||
logger.debug('responseData:', result.data.responseData)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
|
||||
// const gmsUser = JSON.parse(result.data.responseData)
|
||||
// logger.debug('gmsUser:', gmsUser)
|
||||
return true
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error in patch community-user:', error)
|
||||
throw new LogError(error.message)
|
||||
if (error instanceof Error) {
|
||||
throw new LogError(error.message)
|
||||
}
|
||||
throw new LogError('Unknown error in patch community-user')
|
||||
}
|
||||
} else {
|
||||
logger.info('GMS-Communication disabled per ConfigKey GMS_ACTIVE=false!')
|
||||
@ -194,6 +196,7 @@ export async function verifyAuthToken(
|
||||
token: string,
|
||||
): Promise<string> {
|
||||
const baseUrl = ensureUrlEndsWithSlash(CONFIG.GMS_API_URL)
|
||||
// TODO: NEVER pass user JWT token to another server - serious security risk! 😱⚠️
|
||||
const service = 'verify-auth-token?token='.concat(token).concat('&uuid=').concat(communityUuid)
|
||||
const config = {
|
||||
headers: {
|
||||
@ -216,12 +219,15 @@ export async function verifyAuthToken(
|
||||
)
|
||||
}
|
||||
logger.debug('responseData:', result.data.responseData)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
|
||||
const token: string = result.data.responseData.token
|
||||
logger.debug('verifyAuthToken=', token)
|
||||
return token
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error in verifyAuthToken:', error)
|
||||
throw new LogError(error.message)
|
||||
if (error instanceof Error) {
|
||||
throw new LogError(error.message)
|
||||
}
|
||||
throw new LogError('Unknown error in verifyAuthToken')
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ export class GmsCommunityProfile {
|
||||
communityId: number
|
||||
radius: number
|
||||
description: string
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
api_key: string
|
||||
communityAuthUrl: unknown
|
||||
profileImage: unknown
|
||||
|
||||
@ -2,6 +2,7 @@ import { User as dbUser } from '@entity/User'
|
||||
|
||||
import { PublishNameLogic } from '@/data/PublishName.logic'
|
||||
// import { GmsPublishLocationType } from '@/graphql/enum/GmsPublishLocationType'
|
||||
import { GmsPublishLocationType } from '@/graphql/enum/GmsPublishLocationType'
|
||||
import { GmsPublishPhoneType } from '@/graphql/enum/GmsPublishPhoneType'
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
|
||||
@ -15,13 +16,19 @@ export class GmsUser {
|
||||
this.email = this.getGmsEmail(user)
|
||||
this.countryCode = this.getGmsCountryCode(user)
|
||||
this.mobile = this.getGmsPhone(user)
|
||||
const fn = pnLogic.getFirstName(user.gmsPublishName)
|
||||
const fn = pnLogic.getFirstName(user.gmsPublishName as PublishNameType)
|
||||
this.firstName = fn !== '' ? fn : null // getGmsFirstName(user)
|
||||
const ln = pnLogic.getLastName(user.gmsPublishName)
|
||||
const ln = pnLogic.getLastName(user.gmsPublishName as PublishNameType)
|
||||
this.lastName = ln !== '' ? ln : null // getGmsLastName(user)
|
||||
this.alias = this.getGmsAlias(user)
|
||||
this.alias = pnLogic.getPublicName(user.gmsPublishName as PublishNameType)
|
||||
this.type = user.gmsPublishLocation // GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM
|
||||
this.location = user.location
|
||||
if ((this.type as GmsPublishLocationType) === GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM) {
|
||||
this.type = GmsPublishLocationType.GMS_LOCATION_TYPE_APPROXIMATE
|
||||
}
|
||||
if (!this.location) {
|
||||
this.type = GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM
|
||||
}
|
||||
}
|
||||
|
||||
id: number
|
||||
|
||||
@ -11,7 +11,7 @@ export class GmsUserAccount {
|
||||
address: string
|
||||
radius: number
|
||||
description: string
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
api_key: string
|
||||
profileImage: unknown
|
||||
}
|
||||
|
||||
@ -4,8 +4,8 @@ import { User } from '@entity/User'
|
||||
import { CONFIG } from '@/config'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
import { Connection } from '@/typeorm/connection'
|
||||
import { checkDBVersion } from '@/typeorm/DBVersion'
|
||||
import { Connection } from '@/typeorm/connection'
|
||||
|
||||
import { HumHubClient } from './HumHubClient'
|
||||
import { GetUser } from './model/GetUser'
|
||||
@ -26,7 +26,7 @@ function getUsersPage(page: number, limit: number): Promise<[User[], number]> {
|
||||
|
||||
/**
|
||||
* @param client
|
||||
* @returns user map indices with email
|
||||
* @returns user map indices with username
|
||||
*/
|
||||
async function loadUsersFromHumHub(client: HumHubClient): Promise<Map<string, GetUser>> {
|
||||
const start = new Date().getTime()
|
||||
@ -39,19 +39,20 @@ async function loadUsersFromHumHub(client: HumHubClient): Promise<Map<string, Ge
|
||||
if (!usersPage) {
|
||||
throw new LogError('error requesting next users page from humhub')
|
||||
}
|
||||
usersPage.results.forEach((user) => {
|
||||
for (const user of usersPage.results) {
|
||||
// deleted users have empty emails
|
||||
if (user.account.email) {
|
||||
humhubUsers.set(user.account.email.trim(), user)
|
||||
humhubUsers.set(user.account.username, user)
|
||||
} else {
|
||||
skippedUsersCount++
|
||||
}
|
||||
})
|
||||
}
|
||||
page++
|
||||
process.stdout.write(
|
||||
`load users from humhub: ${humhubUsers.size}/${usersPage.total}, skipped: ${skippedUsersCount}\r`,
|
||||
)
|
||||
} while (usersPage && usersPage.results.length === HUMHUB_BULK_SIZE)
|
||||
process.stdout.write('\n')
|
||||
|
||||
const elapsed = new Date().getTime() - start
|
||||
logger.info('load users from humhub', {
|
||||
@ -87,23 +88,31 @@ async function main() {
|
||||
const humhubUsers = await loadUsersFromHumHub(humHubClient)
|
||||
|
||||
let dbUserCount = 0
|
||||
const executedHumhubActionsCount = [0, 0, 0, 0]
|
||||
const executedHumhubActionsCount = [0, 0, 0, 0, 0]
|
||||
|
||||
do {
|
||||
const [users, totalUsers] = await getUsersPage(page, USER_BULK_SIZE)
|
||||
dbUserCount += users.length
|
||||
userCount = users.length
|
||||
page++
|
||||
const promises: Promise<ExecutedHumhubAction>[] = []
|
||||
users.forEach((user: User) => promises.push(syncUser(user, humhubUsers)))
|
||||
const executedActions = await Promise.all(promises)
|
||||
executedActions.forEach((executedAction: ExecutedHumhubAction) => {
|
||||
executedHumhubActionsCount[executedAction as number]++
|
||||
})
|
||||
// using process.stdout.write here so that carriage-return is working analog to c
|
||||
// printf("\rchecked user: %d/%d", dbUserCount, totalUsers);
|
||||
process.stdout.write(`checked user: ${dbUserCount}/${totalUsers}\r`)
|
||||
try {
|
||||
const [users, totalUsers] = await getUsersPage(page, USER_BULK_SIZE)
|
||||
dbUserCount += users.length
|
||||
userCount = users.length
|
||||
page++
|
||||
const promises: Promise<ExecutedHumhubAction>[] = []
|
||||
for (const user of users) {
|
||||
promises.push(syncUser(user, humhubUsers))
|
||||
}
|
||||
const executedActions = await Promise.all(promises)
|
||||
for (const executedAction of executedActions) {
|
||||
executedHumhubActionsCount[executedAction as number]++
|
||||
}
|
||||
// using process.stdout.write here so that carriage-return is working analog to c
|
||||
// printf("\rchecked user: %d/%d", dbUserCount, totalUsers);
|
||||
process.stdout.write(`checked user: ${dbUserCount}/${totalUsers}\r`)
|
||||
} catch (e) {
|
||||
process.stdout.write('\n')
|
||||
throw e
|
||||
}
|
||||
} while (userCount === USER_BULK_SIZE)
|
||||
process.stdout.write('\n')
|
||||
|
||||
await con.destroy()
|
||||
const elapsed = new Date().getTime() - start
|
||||
@ -114,12 +123,12 @@ async function main() {
|
||||
updatedCount: executedHumhubActionsCount[ExecutedHumhubAction.UPDATE],
|
||||
skippedCount: executedHumhubActionsCount[ExecutedHumhubAction.SKIP],
|
||||
deletedCount: executedHumhubActionsCount[ExecutedHumhubAction.DELETE],
|
||||
validationErrorCount: executedHumhubActionsCount[ExecutedHumhubAction.VALIDATION_ERROR],
|
||||
})
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
// eslint-disable-next-line no-console
|
||||
// biome-ignore lint/suspicious/noConsole: logger isn't used here
|
||||
console.error(e)
|
||||
// eslint-disable-next-line n/no-process-exit
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
@ -17,11 +17,9 @@ import { UsersResponse } from './model/UsersResponse'
|
||||
* HumHubClient as singleton class
|
||||
*/
|
||||
export class HumHubClient {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static instance: HumHubClient
|
||||
private restClient: RestClient
|
||||
|
||||
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
|
||||
private constructor() {
|
||||
this.restClient = new RestClient('gradido-backend', CONFIG.HUMHUB_API_URL, undefined, {
|
||||
keepAlive: true,
|
||||
|
||||
@ -10,10 +10,8 @@ import { UsersResponse } from '@/apis/humhub/model/UsersResponse'
|
||||
* HumHubClient as singleton class
|
||||
*/
|
||||
export class HumHubClient {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static instance: HumHubClient
|
||||
|
||||
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
|
||||
private constructor() {}
|
||||
|
||||
public static getInstance(): HumHubClient {
|
||||
|
||||
@ -2,6 +2,7 @@ import { User } from '@entity/User'
|
||||
|
||||
import { isHumhubUserIdenticalToDbUser } from '@/apis/humhub/compareHumhubUserDbUser'
|
||||
import { GetUser } from '@/apis/humhub/model/GetUser'
|
||||
import { PostUser } from '@/apis/humhub/model/PostUser'
|
||||
|
||||
export enum ExecutedHumhubAction {
|
||||
UPDATE,
|
||||
@ -26,7 +27,8 @@ export async function syncUser(
|
||||
user: User,
|
||||
humhubUsers: Map<string, GetUser>,
|
||||
): Promise<ExecutedHumhubAction> {
|
||||
const humhubUser = humhubUsers.get(user.emailContact.email.trim())
|
||||
const postUser = new PostUser(user)
|
||||
const humhubUser = humhubUsers.get(postUser.account.username)
|
||||
if (humhubUser) {
|
||||
if (!user.humhubAllowed) {
|
||||
return Promise.resolve(ExecutedHumhubAction.DELETE)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/* eslint-disable prettier/prettier */
|
||||
import 'reflect-metadata'
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
import { communityDbUser } from '@/util/communityUser'
|
||||
|
||||
import { isHumhubUserIdenticalToDbUser } from './compareHumhubUserDbUser'
|
||||
@ -7,58 +8,73 @@ import { GetUser } from './model/GetUser'
|
||||
const defaultUser = communityDbUser
|
||||
|
||||
describe('isHumhubUserIdenticalToDbUser', () => {
|
||||
beforeEach(() => {
|
||||
defaultUser.firstName = 'first name'
|
||||
defaultUser.lastName = 'last name'
|
||||
defaultUser.alias = 'alias'
|
||||
defaultUser.emailContact.email = 'email@gmail.com'
|
||||
defaultUser.language = 'en'
|
||||
})
|
||||
beforeEach(() => {
|
||||
defaultUser.firstName = 'first name'
|
||||
defaultUser.lastName = 'last name'
|
||||
defaultUser.alias = 'alias'
|
||||
defaultUser.emailContact.email = 'email@gmail.com'
|
||||
defaultUser.language = 'en'
|
||||
defaultUser.gradidoID = 'gradidoID'
|
||||
})
|
||||
|
||||
it('Should return true because humhubUser was created from entity user', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
it('Should return true because humhubUser was created from entity user', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
|
||||
it('Should return false because first name differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.profile.firstname = 'changed first name'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
it('Should return false because last name differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.profile.lastname = 'changed last name'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
it('Should return false because username differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.account.username = 'changed username'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
it('Should return false, because last name differ because of publish name type', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
defaultUser.humhubPublishName = PublishNameType.PUBLISH_NAME_FIRST
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it('Should return false because email differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.account.email = 'new@gmail.com'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
it('Should return true, even if alias is empty', () => {
|
||||
defaultUser.alias = ''
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
|
||||
it('Should return false because language differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.account.language = 'de'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
it('Should return false because first name differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.profile.firstname = 'changed first name'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
it('Should return false because last name differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.profile.lastname = 'changed last name'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
it('Should return false because username differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.account.username = 'changed username'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it('Should return false because gradido_address differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
// eslint-disable-next-line camelcase
|
||||
humhubUser.profile.gradido_address = 'changed gradido address'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
it('Should return false because email differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.account.email = 'new@gmail.com'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it('Should return false because language differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUser.account.language = 'de'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it('Should return false because gradido_address differ', () => {
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
|
||||
humhubUser.profile.gradido_address = 'changed gradido address'
|
||||
const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@ -6,18 +6,32 @@ import { Profile } from './model/Profile'
|
||||
|
||||
function profileIsTheSame(profile: Profile, user: User): boolean {
|
||||
const gradidoUserProfile = new Profile(user)
|
||||
if (profile.firstname !== gradidoUserProfile.firstname) return false
|
||||
if (profile.lastname !== gradidoUserProfile.lastname) return false
|
||||
if (profile.gradido_address !== gradidoUserProfile.gradido_address) return false
|
||||
if (profile.firstname !== gradidoUserProfile.firstname) {
|
||||
return false
|
||||
}
|
||||
if (profile.lastname !== gradidoUserProfile.lastname) {
|
||||
return false
|
||||
}
|
||||
if (profile.gradido_address !== gradidoUserProfile.gradido_address) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function accountIsTheSame(account: Account, user: User): boolean {
|
||||
const gradidoUserAccount = new Account(user)
|
||||
if (account.username !== gradidoUserAccount.username) return false
|
||||
if (account.email !== gradidoUserAccount.email) return false
|
||||
if (account.language !== gradidoUserAccount.language) return false
|
||||
if (account.status !== gradidoUserAccount.status) return false
|
||||
if (account.username !== gradidoUserAccount.username) {
|
||||
return false
|
||||
}
|
||||
if (account.email !== gradidoUserAccount.email) {
|
||||
return false
|
||||
}
|
||||
if (account.language !== gradidoUserAccount.language) {
|
||||
return false
|
||||
}
|
||||
if (account.status !== gradidoUserAccount.status) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ export class ProfileLoggingView extends AbstractLoggingView {
|
||||
return {
|
||||
firstname: this.self.firstname.substring(0, 3) + '...',
|
||||
lastname: this.self.lastname.substring(0, 3) + '...',
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
gradido_address:
|
||||
gradidoAddressParts[0] + '/' + gradidoAddressParts[1].substring(0, 3) + '...',
|
||||
}
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
import { User } from '@entity/User'
|
||||
|
||||
import { PublishNameLogic } from '@/data/PublishName.logic'
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
|
||||
import { Account } from './Account'
|
||||
import { Profile } from './Profile'
|
||||
|
||||
@ -10,12 +7,6 @@ export abstract class AbstractUser {
|
||||
public constructor(user: User) {
|
||||
this.account = new Account(user)
|
||||
this.profile = new Profile(user)
|
||||
// temp fix for prevent double usernames in humhub, if the username ist created from initials
|
||||
const publishNameLogic = new PublishNameLogic(user)
|
||||
if (publishNameLogic.isUsernameFromInitials(user.humhubPublishName as PublishNameType)) {
|
||||
this.profile.firstname = this.account.username
|
||||
this.account.username = user.gradidoID
|
||||
}
|
||||
}
|
||||
|
||||
account: Account
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
/* eslint-disable camelcase */
|
||||
import { User } from '@entity/User'
|
||||
|
||||
import { convertGradidoLanguageToHumhub } from '@/apis/humhub/convertLanguage'
|
||||
@ -8,7 +7,7 @@ import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
export class Account {
|
||||
public constructor(user: User) {
|
||||
const publishNameLogic = new PublishNameLogic(user)
|
||||
this.username = publishNameLogic.getUsername(user.humhubPublishName as PublishNameType)
|
||||
this.username = publishNameLogic.getUserIdentifier(user.humhubPublishName as PublishNameType)
|
||||
this.email = user.emailContact.email
|
||||
this.language = convertGradidoLanguageToHumhub(user.language)
|
||||
this.status = 1
|
||||
|
||||
@ -10,6 +10,6 @@ export class GetUser extends AbstractUser {
|
||||
|
||||
id: number
|
||||
guid: string
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
display_name: string
|
||||
}
|
||||
|
||||
139
backend/src/apis/humhub/model/PostUser.test.ts
Normal file
139
backend/src/apis/humhub/model/PostUser.test.ts
Normal file
@ -0,0 +1,139 @@
|
||||
import { User } from '@entity/User'
|
||||
import { UserContact } from '@entity/UserContact'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
|
||||
import { PostUser as HumhubUser } from './PostUser'
|
||||
|
||||
const gradidoUuid = uuidv4()
|
||||
let user: User
|
||||
|
||||
/*
|
||||
export enum PublishNameType {
|
||||
PUBLISH_NAME_ALIAS_OR_INITALS = 0,
|
||||
PUBLISH_NAME_INITIALS = 1,
|
||||
PUBLISH_NAME_FIRST = 2,
|
||||
PUBLISH_NAME_FIRST_INITIAL = 3,
|
||||
PUBLISH_NAME_FULL = 4,
|
||||
}
|
||||
*/
|
||||
|
||||
describe('test creation of a humhub user from db user', () => {
|
||||
beforeEach(() => {
|
||||
const emailContact = new UserContact()
|
||||
emailContact.email = 'john.smith@gradido.de'
|
||||
|
||||
user = new User()
|
||||
user.alias = 'alias'
|
||||
user.firstName = 'John'
|
||||
user.lastName = 'Smith'
|
||||
user.emailContact = emailContact
|
||||
user.gradidoID = gradidoUuid
|
||||
})
|
||||
|
||||
describe('for alias or initials', () => {
|
||||
it('with alias set', () => {
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe('alias')
|
||||
expect(humhubUser.profile.firstname).toBe('')
|
||||
expect(humhubUser.profile.lastname).toBe('')
|
||||
})
|
||||
|
||||
it('with empty alias', () => {
|
||||
user.alias = ''
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe(gradidoUuid)
|
||||
expect(humhubUser.profile.firstname).toBe('JoSm')
|
||||
expect(humhubUser.profile.lastname).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
describe('for initials', () => {
|
||||
it('with alias set', () => {
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_INITIALS
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe(gradidoUuid)
|
||||
expect(humhubUser.profile.firstname).toBe('JoSm')
|
||||
expect(humhubUser.profile.lastname).toBe('')
|
||||
})
|
||||
|
||||
it('with empty alias', () => {
|
||||
user.alias = ''
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_INITIALS
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe(gradidoUuid)
|
||||
expect(humhubUser.profile.firstname).toBe('JoSm')
|
||||
expect(humhubUser.profile.lastname).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
describe('for first name only', () => {
|
||||
it('with alias set', () => {
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_FIRST
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe(gradidoUuid)
|
||||
expect(humhubUser.profile.firstname).toBe('John')
|
||||
expect(humhubUser.profile.lastname).toBe('')
|
||||
})
|
||||
|
||||
it('with empty alias', () => {
|
||||
user.alias = ''
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_FIRST
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe(gradidoUuid)
|
||||
expect(humhubUser.profile.firstname).toBe('John')
|
||||
expect(humhubUser.profile.lastname).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
describe('for first name and last name initial', () => {
|
||||
it('with alias set', () => {
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_FIRST_INITIAL
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe(gradidoUuid)
|
||||
expect(humhubUser.profile.firstname).toBe('John')
|
||||
expect(humhubUser.profile.lastname).toBe('S')
|
||||
})
|
||||
|
||||
it('with empty alias', () => {
|
||||
user.alias = ''
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_FIRST_INITIAL
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe(gradidoUuid)
|
||||
expect(humhubUser.profile.firstname).toBe('John')
|
||||
expect(humhubUser.profile.lastname).toBe('S')
|
||||
})
|
||||
})
|
||||
|
||||
describe('for full name', () => {
|
||||
it('with alias set', () => {
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_FULL
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe(gradidoUuid)
|
||||
expect(humhubUser.profile.firstname).toBe('John')
|
||||
expect(humhubUser.profile.lastname).toBe('Smith')
|
||||
})
|
||||
|
||||
it('with empty alias', () => {
|
||||
user.alias = ''
|
||||
user.humhubPublishName = PublishNameType.PUBLISH_NAME_FULL
|
||||
const humhubUser = new HumhubUser(user)
|
||||
|
||||
expect(humhubUser.account.username).toBe(gradidoUuid)
|
||||
expect(humhubUser.profile.firstname).toBe('John')
|
||||
expect(humhubUser.profile.lastname).toBe('Smith')
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,4 +1,3 @@
|
||||
/* eslint-disable camelcase */
|
||||
import { User } from '@entity/User'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
@ -14,6 +13,18 @@ export class Profile {
|
||||
this.gradido_address = `${CONFIG.COMMUNITY_NAME}/${
|
||||
publishNameLogic.hasAlias() ? user.alias : user.gradidoID
|
||||
}`
|
||||
|
||||
// we need to get our public name to humhub, but the public name isn't always unique,
|
||||
// so in some cases we must cheat and put the public name into first_name, if it isn't unique,
|
||||
// to let the username to be unique either alias or gradido id
|
||||
// in humhub first name is shown if exist else username
|
||||
// if it shows first_name it will also show last_name if exist
|
||||
// if we have public name from alias, we have only 2 character for first name and 2 for last name,
|
||||
// but this isn't searchable in humhub, so we put both into first_name
|
||||
if (publishNameLogic.isUsernameFromInitials(user.humhubPublishName as PublishNameType)) {
|
||||
this.firstname = publishNameLogic.getUsernameFromInitials()
|
||||
this.lastname = ''
|
||||
}
|
||||
}
|
||||
|
||||
firstname: string
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
import { User } from '@entity/User'
|
||||
import { UserContact } from '@entity/UserContact'
|
||||
|
||||
import { GetUser } from './model/GetUser'
|
||||
import { syncUser, ExecutedHumhubAction } from './syncUser'
|
||||
import { ExecutedHumhubAction, syncUser } from './syncUser'
|
||||
|
||||
jest.mock('@/apis/humhub/HumHubClient')
|
||||
|
||||
@ -28,7 +27,8 @@ describe('syncUser function', () => {
|
||||
|
||||
it('When humhubUser exists and user.humhubAllowed is false, should return DELETE action', async () => {
|
||||
const humhubUsers = new Map<string, GetUser>()
|
||||
humhubUsers.set(defaultUser.emailContact.email, new GetUser(defaultUser, 1))
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUsers.set(humhubUser.account.username, humhubUser)
|
||||
|
||||
defaultUser.humhubAllowed = false
|
||||
const result = await syncUser(defaultUser, humhubUsers)
|
||||
@ -39,8 +39,8 @@ describe('syncUser function', () => {
|
||||
it('When humhubUser exists and user.humhubAllowed is true and there are changes in user data, should return UPDATE action', async () => {
|
||||
const humhubUsers = new Map<string, GetUser>()
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUsers.set(humhubUser.account.username, humhubUser)
|
||||
humhubUser.account.username = 'test username'
|
||||
humhubUsers.set(defaultUser.emailContact.email, humhubUser)
|
||||
|
||||
defaultUser.humhubAllowed = true
|
||||
const result = await syncUser(defaultUser, humhubUsers)
|
||||
@ -51,7 +51,7 @@ describe('syncUser function', () => {
|
||||
it('When humhubUser exists and user.humhubAllowed is true and there are no changes in user data, should return SKIP action', async () => {
|
||||
const humhubUsers = new Map<string, GetUser>()
|
||||
const humhubUser = new GetUser(defaultUser, 1)
|
||||
humhubUsers.set(defaultUser.emailContact.email, humhubUser)
|
||||
humhubUsers.set(humhubUser.account.username, humhubUser)
|
||||
|
||||
defaultUser.humhubAllowed = true
|
||||
const result = await syncUser(defaultUser, humhubUsers)
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { User } from '@entity/User'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
import { isHumhubUserIdenticalToDbUser } from './compareHumhubUserDbUser'
|
||||
import { HumHubClient } from './HumHubClient'
|
||||
import { isHumhubUserIdenticalToDbUser } from './compareHumhubUserDbUser'
|
||||
import { GetUser } from './model/GetUser'
|
||||
import { PostUser } from './model/PostUser'
|
||||
|
||||
@ -12,7 +13,22 @@ export enum ExecutedHumhubAction {
|
||||
CREATE,
|
||||
SKIP,
|
||||
DELETE,
|
||||
VALIDATION_ERROR,
|
||||
}
|
||||
|
||||
// todo: replace with full validation (schema)
|
||||
function isValid(postUser: PostUser, userId: number): boolean {
|
||||
if (postUser.profile.firstname.length > 20) {
|
||||
logger.error('firstname too long for humhub, for user with id:', userId)
|
||||
return false
|
||||
}
|
||||
if (postUser.profile.lastname.length > 20) {
|
||||
logger.error('lastname too long for humhub, for user with id:', userId)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger action according to conditions
|
||||
* | User exist on humhub | export to humhub allowed | changes in user data | ACTION
|
||||
@ -21,9 +37,8 @@ export enum ExecutedHumhubAction {
|
||||
* | true | true | false | SKIP
|
||||
* | false | false | ignored | SKIP
|
||||
* | false | true | ignored | CREATE
|
||||
* @param user
|
||||
* @param humHubClient
|
||||
* @param humhubUsers
|
||||
* @param user user entity
|
||||
* @param humhubUsers user map indices with username
|
||||
* @returns
|
||||
*/
|
||||
export async function syncUser(
|
||||
@ -31,7 +46,10 @@ export async function syncUser(
|
||||
humhubUsers: Map<string, GetUser>,
|
||||
): Promise<ExecutedHumhubAction> {
|
||||
const postUser = new PostUser(user)
|
||||
const humhubUser = humhubUsers.get(user.emailContact.email.trim())
|
||||
if (!isValid(postUser, user.id)) {
|
||||
return ExecutedHumhubAction.VALIDATION_ERROR
|
||||
}
|
||||
const humhubUser = humhubUsers.get(postUser.account.username)
|
||||
const humHubClient = HumHubClient.getInstance()
|
||||
if (!humHubClient) {
|
||||
throw new LogError('Error creating humhub client')
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
/* eslint-disable camelcase */
|
||||
import { OpenaiThreads } from '@entity/OpenaiThreads'
|
||||
import { User } from '@entity/User'
|
||||
import { OpenAI } from 'openai'
|
||||
@ -18,7 +17,7 @@ export class OpenaiClient {
|
||||
/**
|
||||
* The singleton instance of the `OpenaiClient`.
|
||||
*/
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
|
||||
private static instance: OpenaiClient
|
||||
|
||||
/**
|
||||
|
||||
@ -6,7 +6,9 @@ import { LogError } from '@/server/LogError'
|
||||
import { CustomJwtPayload } from './CustomJwtPayload'
|
||||
|
||||
export const decode = async (token: string): Promise<CustomJwtPayload | null> => {
|
||||
if (!token) throw new LogError('401 Unauthorized')
|
||||
if (!token) {
|
||||
throw new LogError('401 Unauthorized')
|
||||
}
|
||||
|
||||
try {
|
||||
const secret = new TextEncoder().encode(CONFIG.JWT_SECRET)
|
||||
@ -15,7 +17,7 @@ export const decode = async (token: string): Promise<CustomJwtPayload | null> =>
|
||||
audience: 'urn:gradido:audience',
|
||||
})
|
||||
return payload as CustomJwtPayload
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env)
|
||||
/* eslint-disable n/no-process-env */
|
||||
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { validate } from '@config/index'
|
||||
import { latestDbVersion } from '@dbTools/config/detectLastDBVersion'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
@ -90,8 +88,8 @@ const email = {
|
||||
EMAIL_PASSWORD: process.env.EMAIL_PASSWORD ?? '',
|
||||
EMAIL_SMTP_HOST: process.env.EMAIL_SMTP_HOST ?? 'mailserver',
|
||||
EMAIL_SMTP_PORT: Number(process.env.EMAIL_SMTP_PORT) || 1025,
|
||||
// eslint-disable-next-line no-unneeded-ternary
|
||||
EMAIL_TLS: process.env.EMAIL_TLS === 'false' ? false : true,
|
||||
|
||||
EMAIL_TLS: process.env.EMAIL_TLS !== 'false',
|
||||
EMAIL_LINK_VERIFICATION:
|
||||
COMMUNITY_URL + (process.env.EMAIL_LINK_VERIFICATION_PATH ?? '/checkEmail/'),
|
||||
EMAIL_LINK_SETPASSWORD:
|
||||
@ -101,11 +99,11 @@ const email = {
|
||||
EMAIL_LINK_OVERVIEW: COMMUNITY_URL + (process.env.EMAIL_LINK_OVERVIEW_PATH ?? '/overview'),
|
||||
// time in minutes a optin code is valid
|
||||
EMAIL_CODE_VALID_TIME: process.env.EMAIL_CODE_VALID_TIME
|
||||
? parseInt(process.env.EMAIL_CODE_VALID_TIME) ?? 1440
|
||||
? (parseInt(process.env.EMAIL_CODE_VALID_TIME) ?? 1440)
|
||||
: 1440,
|
||||
// time in minutes that must pass to request a new optin code
|
||||
EMAIL_CODE_REQUEST_TIME: process.env.EMAIL_CODE_REQUEST_TIME
|
||||
? parseInt(process.env.EMAIL_CODE_REQUEST_TIME) ?? 10
|
||||
? (parseInt(process.env.EMAIL_CODE_REQUEST_TIME) ?? 10)
|
||||
: 10,
|
||||
}
|
||||
|
||||
@ -139,6 +137,7 @@ const gms = {
|
||||
// koordinates of Illuminz-instance of GMS
|
||||
GMS_API_URL: process.env.GMS_API_URL ?? 'http://localhost:4044/',
|
||||
GMS_DASHBOARD_URL: process.env.GMS_DASHBOARD_URL ?? 'http://localhost:8080/',
|
||||
GMS_USER_SEARCH_FRONTEND_ROUTE: process.env.GMS_USER_SEARCH_FRONTEND_ROUTE ?? 'user-search',
|
||||
// used as secret postfix attached at the gms community-auth-url endpoint ('/hook/gms/' + 'secret')
|
||||
GMS_WEBHOOK_SECRET: process.env.GMS_WEBHOOK_SECRET ?? 'secret',
|
||||
}
|
||||
|
||||
@ -1,19 +1,17 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import {
|
||||
COMMUNITY_NAME,
|
||||
COMMUNITY_URL,
|
||||
COMMUNITY_DESCRIPTION,
|
||||
COMMUNITY_NAME,
|
||||
COMMUNITY_SUPPORT_MAIL,
|
||||
COMMUNITY_URL,
|
||||
DB_DATABASE,
|
||||
DB_HOST,
|
||||
DB_PASSWORD,
|
||||
DB_PORT,
|
||||
DB_USER,
|
||||
DB_VERSION,
|
||||
DB_DATABASE,
|
||||
DECAY_START_TIME,
|
||||
GDT_API_URL,
|
||||
GDT_ACTIVE,
|
||||
GDT_API_URL,
|
||||
GMS_ACTIVE,
|
||||
GRAPHIQL,
|
||||
HUMHUB_ACTIVE,
|
||||
@ -61,7 +59,6 @@ export const schema = Joi.object({
|
||||
.description('The url for redeeming link transactions, must start with frontend base url')
|
||||
.default('http://0.0.0.0/redeem/')
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
||||
if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) {
|
||||
return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL })
|
||||
}
|
||||
@ -72,7 +69,6 @@ export const schema = Joi.object({
|
||||
COMMUNITY_REDEEM_CONTRIBUTION_URL: Joi.string()
|
||||
.uri({ scheme: ['http', 'https'] })
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
||||
if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) {
|
||||
return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL })
|
||||
}
|
||||
@ -168,7 +164,6 @@ export const schema = Joi.object({
|
||||
EMAIL_LINK_VERIFICATION: Joi.string()
|
||||
.uri({ scheme: ['http', 'https'] })
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
||||
if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) {
|
||||
return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL })
|
||||
}
|
||||
@ -180,7 +175,6 @@ export const schema = Joi.object({
|
||||
EMAIL_LINK_SETPASSWORD: Joi.string()
|
||||
.uri({ scheme: ['http', 'https'] })
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
||||
if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) {
|
||||
return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL })
|
||||
}
|
||||
@ -192,7 +186,6 @@ export const schema = Joi.object({
|
||||
EMAIL_LINK_FORGOTPASSWORD: Joi.string()
|
||||
.uri({ scheme: ['http', 'https'] })
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
||||
if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) {
|
||||
return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL })
|
||||
}
|
||||
@ -204,7 +197,6 @@ export const schema = Joi.object({
|
||||
EMAIL_LINK_OVERVIEW: Joi.string()
|
||||
.uri({ scheme: ['http', 'https'] })
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
||||
if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) {
|
||||
return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL })
|
||||
}
|
||||
@ -279,6 +271,14 @@ export const schema = Joi.object({
|
||||
.default('http://localhost:8080/')
|
||||
.description('The URL for the GMS dashboard'),
|
||||
|
||||
GMS_USER_SEARCH_FRONTEND_ROUTE: Joi.string()
|
||||
.pattern(/^[\w_-]*$/)
|
||||
.allow('')
|
||||
.default('user-search')
|
||||
.description(
|
||||
'gms frontend playground route, user-search for standalone playground, usersearch-playground for old, empty for testing local',
|
||||
),
|
||||
|
||||
GMS_WEBHOOK_SECRET: Joi.string()
|
||||
.min(1)
|
||||
.default('secret')
|
||||
|
||||
@ -4,7 +4,6 @@ import { User } from '@entity/User'
|
||||
|
||||
import { ContributionMessageType } from '@/graphql/enum/ContributionMessageType'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
||||
export class ContributionMessageBuilder {
|
||||
private contributionMessage: ContributionMessage
|
||||
|
||||
|
||||
@ -1,23 +1,156 @@
|
||||
import { User } from '@entity/User'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
|
||||
import { PublishNameLogic } from './PublishName.logic'
|
||||
|
||||
const gradidoUuid = uuidv4()
|
||||
let user: User
|
||||
let logic: PublishNameLogic
|
||||
|
||||
/*
|
||||
export enum PublishNameType {
|
||||
PUBLISH_NAME_ALIAS_OR_INITALS = 0,
|
||||
PUBLISH_NAME_INITIALS = 1,
|
||||
PUBLISH_NAME_FIRST = 2,
|
||||
PUBLISH_NAME_FIRST_INITIAL = 3,
|
||||
PUBLISH_NAME_FULL = 4,
|
||||
}
|
||||
*/
|
||||
|
||||
describe('test publish name logic', () => {
|
||||
describe('test username', () => {
|
||||
it('alias or initials with alias set', () => {
|
||||
const user = new User()
|
||||
user.alias = 'alias'
|
||||
const logic = new PublishNameLogic(user)
|
||||
expect(logic.getUsername(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe(user.alias)
|
||||
beforeEach(() => {
|
||||
user = new User()
|
||||
user.alias = 'alias'
|
||||
user.firstName = 'John'
|
||||
user.lastName = 'Smith'
|
||||
user.gradidoID = gradidoUuid
|
||||
logic = new PublishNameLogic(user)
|
||||
})
|
||||
|
||||
describe('test hasAlias', () => {
|
||||
it('for alias set', () => {
|
||||
expect(logic.hasAlias()).toBe(true)
|
||||
})
|
||||
it('alias or initials with empty alias', () => {
|
||||
const user = new User()
|
||||
user.firstName = 'John'
|
||||
user.lastName = 'Smith'
|
||||
const logic = new PublishNameLogic(user)
|
||||
expect(logic.getUsername(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('JoSm')
|
||||
it('for alias empty string', () => {
|
||||
user.alias = ''
|
||||
expect(logic.hasAlias()).toBe(false)
|
||||
})
|
||||
it('for alias string to short 1', () => {
|
||||
user.alias = 'a'
|
||||
expect(logic.hasAlias()).toBe(false)
|
||||
})
|
||||
it('for alias string to short 2', () => {
|
||||
user.alias = 'ab'
|
||||
expect(logic.hasAlias()).toBe(false)
|
||||
})
|
||||
it('for alias string 3', () => {
|
||||
user.alias = 'abc'
|
||||
expect(logic.hasAlias()).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('test isUsernameFromInitials', () => {
|
||||
it('for publish name initials', () => {
|
||||
expect(logic.isUsernameFromInitials(PublishNameType.PUBLISH_NAME_INITIALS)).toBe(true)
|
||||
})
|
||||
it('for publish name alias or initials, with alias set', () => {
|
||||
expect(logic.isUsernameFromInitials(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
it('for publish name alias or initials, with alias not set', () => {
|
||||
user.alias = ''
|
||||
expect(logic.isUsernameFromInitials(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe(true)
|
||||
})
|
||||
it('for publish name first', () => {
|
||||
expect(logic.isUsernameFromInitials(PublishNameType.PUBLISH_NAME_FIRST)).toBe(false)
|
||||
})
|
||||
it('for publish name first initial', () => {
|
||||
expect(logic.isUsernameFromInitials(PublishNameType.PUBLISH_NAME_FIRST_INITIAL)).toBe(false)
|
||||
})
|
||||
it('for publish name full', () => {
|
||||
expect(logic.isUsernameFromInitials(PublishNameType.PUBLISH_NAME_FULL)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('test isUsernameFromAlias', () => {
|
||||
it('for publish name initials', () => {
|
||||
expect(logic.isUsernameFromAlias(PublishNameType.PUBLISH_NAME_INITIALS)).toBe(false)
|
||||
})
|
||||
it('for publish name alias or initials with alias set', () => {
|
||||
expect(logic.isUsernameFromAlias(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe(true)
|
||||
})
|
||||
it('for publish name alias or initials with alias empty', () => {
|
||||
user.alias = ''
|
||||
expect(logic.isUsernameFromAlias(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe(false)
|
||||
})
|
||||
it('for publish name first', () => {
|
||||
expect(logic.isUsernameFromAlias(PublishNameType.PUBLISH_NAME_FIRST)).toBe(false)
|
||||
})
|
||||
it('for publish name first initial', () => {
|
||||
expect(logic.isUsernameFromAlias(PublishNameType.PUBLISH_NAME_FIRST_INITIAL)).toBe(false)
|
||||
})
|
||||
it('for publish name full', () => {
|
||||
expect(logic.isUsernameFromAlias(PublishNameType.PUBLISH_NAME_FULL)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('test user identifier ', () => {
|
||||
it('for alias or initials with alias set', () => {
|
||||
expect(logic.getUserIdentifier(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('alias')
|
||||
})
|
||||
it('for alias or initials with empty alias', () => {
|
||||
user.alias = ''
|
||||
expect(logic.getUserIdentifier(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe(
|
||||
gradidoUuid,
|
||||
)
|
||||
})
|
||||
it('for publish name initials', () => {
|
||||
expect(logic.getUserIdentifier(PublishNameType.PUBLISH_NAME_INITIALS)).toBe(gradidoUuid)
|
||||
})
|
||||
it('for publish name first', () => {
|
||||
expect(logic.getUserIdentifier(PublishNameType.PUBLISH_NAME_FIRST)).toBe(gradidoUuid)
|
||||
})
|
||||
it('for publish name first initial', () => {
|
||||
expect(logic.getUserIdentifier(PublishNameType.PUBLISH_NAME_FIRST_INITIAL)).toBe(gradidoUuid)
|
||||
})
|
||||
it('for publish name full', () => {
|
||||
expect(logic.getUserIdentifier(PublishNameType.PUBLISH_NAME_FULL)).toBe(gradidoUuid)
|
||||
})
|
||||
})
|
||||
|
||||
describe('test public name', () => {
|
||||
it('for alias or initials with alias set', () => {
|
||||
expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('alias')
|
||||
})
|
||||
it('for alias or initials with empty alias', () => {
|
||||
user.alias = ''
|
||||
expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('JoSm')
|
||||
})
|
||||
it('for alias or initials with empty alias and lower case written names', () => {
|
||||
user.alias = ''
|
||||
user.firstName = 'john'
|
||||
user.lastName = 'smith'
|
||||
expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('JoSm')
|
||||
})
|
||||
it('for publish name initials', () => {
|
||||
expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_INITIALS)).toBe('JoSm')
|
||||
})
|
||||
it('for publish name initials with lower case written names', () => {
|
||||
user.firstName = 'john'
|
||||
user.lastName = 'smith'
|
||||
expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_INITIALS)).toBe('JoSm')
|
||||
})
|
||||
it('for publish name first', () => {
|
||||
expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_FIRST)).toBe('John')
|
||||
})
|
||||
it('for publish name first initial', () => {
|
||||
expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_FIRST_INITIAL)).toBe('John S')
|
||||
})
|
||||
it('for publish name full', () => {
|
||||
expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_FULL)).toBe('John Smith')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -18,7 +18,6 @@ export class PublishNameLogic {
|
||||
|
||||
// remove character which are invalid for humhub username
|
||||
private filterOutInvalidChar(name: string) {
|
||||
// eslint-disable-next-line import/no-named-as-default-member
|
||||
return XRegExp.match(name, this.usernameRegex, 'all').join('')
|
||||
}
|
||||
|
||||
@ -35,12 +34,16 @@ export class PublishNameLogic {
|
||||
* @returns user.firstName for PUBLISH_NAME_FIRST, PUBLISH_NAME_FIRST_INITIAL or PUBLISH_NAME_FULL
|
||||
*/
|
||||
public getFirstName(publishNameType: PublishNameType): string {
|
||||
let firstName = ''
|
||||
if (this.user && typeof this.user.firstName === 'string') {
|
||||
firstName = this.user.firstName
|
||||
}
|
||||
return [
|
||||
PublishNameType.PUBLISH_NAME_FIRST,
|
||||
PublishNameType.PUBLISH_NAME_FIRST_INITIAL,
|
||||
PublishNameType.PUBLISH_NAME_FULL,
|
||||
].includes(publishNameType)
|
||||
? this.user.firstName
|
||||
? firstName.slice(0, 20)
|
||||
: ''
|
||||
}
|
||||
|
||||
@ -51,31 +54,56 @@ export class PublishNameLogic {
|
||||
* first initial from user.lastName for PUBLISH_NAME_FIRST_INITIAL
|
||||
*/
|
||||
public getLastName(publishNameType: PublishNameType): string {
|
||||
let lastName = ''
|
||||
if (this.user && typeof this.user.lastName === 'string') {
|
||||
lastName = this.user.lastName
|
||||
}
|
||||
return publishNameType === PublishNameType.PUBLISH_NAME_FULL
|
||||
? this.user.lastName
|
||||
: publishNameType === PublishNameType.PUBLISH_NAME_FIRST_INITIAL
|
||||
? this.user.lastName.charAt(0)
|
||||
: ''
|
||||
? lastName.slice(0, 20)
|
||||
: publishNameType === PublishNameType.PUBLISH_NAME_FIRST_INITIAL && lastName.length > 0
|
||||
? lastName.charAt(0)
|
||||
: ''
|
||||
}
|
||||
|
||||
/**
|
||||
* get username from user.alias for PUBLISH_NAME_ALIAS_OR_INITALS and if user has alias
|
||||
* get first name first two characters and last name first two characters for PUBLISH_NAME_ALIAS_OR_INITALS
|
||||
* if no alias or PUBLISH_NAME_INITIALS
|
||||
* get unique username
|
||||
* @param publishNameType
|
||||
* @returns user.alias for publishNameType = PUBLISH_NAME_ALIAS_OR_INITALS and user has alias
|
||||
* else return user.firstName[0,2] + user.lastName[0,2] for publishNameType = [PUBLISH_NAME_ALIAS_OR_INITALS, PUBLISH_NAME_INITIALS]
|
||||
* @return when alias if exist and publishNameType = [PUBLISH_NAME_ALIAS_OR_INITALS, PUBLISH_NAME_INITIALS]
|
||||
* return alias
|
||||
* else return gradido id
|
||||
*/
|
||||
public getUsername(publishNameType: PublishNameType): string {
|
||||
if (this.isUsernameFromInitials(publishNameType)) {
|
||||
return (
|
||||
this.firstUpperCaseSecondLowerCase(this.filterOutInvalidChar(this.user.firstName)) +
|
||||
this.firstUpperCaseSecondLowerCase(this.filterOutInvalidChar(this.user.lastName))
|
||||
)
|
||||
} else if (this.isUsernameFromAlias(publishNameType)) {
|
||||
return this.filterOutInvalidChar(this.user.alias)
|
||||
}
|
||||
return this.user.gradidoID
|
||||
public getUserIdentifier(publishNameType: PublishNameType): string {
|
||||
return this.isUsernameFromAlias(publishNameType)
|
||||
? this.getUsernameFromAlias()
|
||||
: this.user.gradidoID
|
||||
}
|
||||
|
||||
/**
|
||||
* get public name based on publishNameType: PublishNameType value
|
||||
* @param publishNameType: PublishNameType
|
||||
* @return alias if exist and type = PUBLISH_NAME_ALIAS_OR_INITALS
|
||||
* initials if type = PUBLISH_NAME_INITIALS
|
||||
* full first name if type = PUBLISH_NAME_FIRST
|
||||
* full first name and last name initial if type = PUBLISH_NAME_FIRST_INITIAL
|
||||
* full first name and full last name if type = PUBLISH_NAME_FULL
|
||||
*/
|
||||
public getPublicName(publishNameType: PublishNameType): string {
|
||||
return this.isUsernameFromAlias(publishNameType)
|
||||
? this.getUsernameFromAlias()
|
||||
: this.isUsernameFromInitials(publishNameType)
|
||||
? this.getUsernameFromInitials()
|
||||
: (this.getFirstName(publishNameType) + ' ' + this.getLastName(publishNameType)).trim()
|
||||
}
|
||||
|
||||
public getUsernameFromInitials(): string {
|
||||
return (
|
||||
this.firstUpperCaseSecondLowerCase(this.user.firstName) +
|
||||
this.firstUpperCaseSecondLowerCase(this.user.lastName)
|
||||
).trim()
|
||||
}
|
||||
|
||||
public getUsernameFromAlias(): string {
|
||||
return this.filterOutInvalidChar(this.user.alias)
|
||||
}
|
||||
|
||||
public isUsernameFromInitials(publishNameType: PublishNameType): boolean {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import { createTransport } from 'nodemailer'
|
||||
|
||||
import { logger, i18n } from '@test/testSetup'
|
||||
import { i18n, logger } from '@test/testSetup'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
|
||||
@ -103,12 +102,10 @@ describe('sendEmailTranslated', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('calls "i18n.setLocale" with "en"', () => {
|
||||
expect(i18n.setLocale).toBeCalledWith('en')
|
||||
})
|
||||
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('calls "i18n.__" for translation', () => {
|
||||
expect(i18n.__).toBeCalled()
|
||||
})
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
import path from 'path'
|
||||
|
||||
import Email from 'email-templates'
|
||||
|
||||
@ -1,29 +1,24 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import { Connection } from '@dbTools/typeorm'
|
||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
|
||||
import { testEnvironment } from '@test/helpers'
|
||||
import { logger, i18n as localization } from '@test/testSetup'
|
||||
import { i18n as localization, logger } from '@test/testSetup'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
|
||||
// eslint-disable-next-line import/no-namespace
|
||||
import * as sendEmailTranslatedApi from './sendEmailTranslated'
|
||||
import {
|
||||
sendAddedContributionMessageEmail,
|
||||
sendAccountActivationEmail,
|
||||
sendAccountMultiRegistrationEmail,
|
||||
sendAddedContributionMessageEmail,
|
||||
sendContributionChangedByModeratorEmail,
|
||||
sendContributionConfirmedEmail,
|
||||
sendContributionDeniedEmail,
|
||||
sendContributionDeletedEmail,
|
||||
sendContributionDeniedEmail,
|
||||
sendResetPasswordEmail,
|
||||
sendTransactionLinkRedeemedEmail,
|
||||
sendTransactionReceivedEmail,
|
||||
sendContributionChangedByModeratorEmail,
|
||||
} from './sendEmailVariants'
|
||||
|
||||
const testMailServerHost = 'localhost'
|
||||
@ -69,7 +64,6 @@ afterAll(async () => {
|
||||
const sendEmailTranslatedSpy = jest.spyOn(sendEmailTranslatedApi, 'sendEmailTranslated')
|
||||
|
||||
describe('sendEmailVariants', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let result: any
|
||||
|
||||
describe('sendAddedContributionMessageEmail', () => {
|
||||
|
||||
@ -3,7 +3,7 @@ import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCom
|
||||
import { validate as validateUUID, version as versionUUID } from 'uuid'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/client/1_0/AuthenticationClient'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
import { ensureUrlEndsWithSlash } from '@/util/utilities'
|
||||
@ -35,7 +35,7 @@ export async function startCommunityAuthentication(
|
||||
) {
|
||||
try {
|
||||
const client = AuthenticationClientFactory.getInstance(foreignFedCom)
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
if (client instanceof V1_0_AuthenticationClient) {
|
||||
const args = new OpenConnectionArgs()
|
||||
args.publicKey = homeCom.publicKey.toString('hex')
|
||||
|
||||
@ -132,7 +132,7 @@ export class SendCoinsClient {
|
||||
{ args },
|
||||
)
|
||||
logger.debug(`X-Com: SendCoinsClient: after revertSettledSendCoins: data=`, data)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
|
||||
if (!data?.revertSettledSendCoins) {
|
||||
logger.warn(
|
||||
'X-Com: SendCoinsClient: revertSettledSendCoins without response data from endpoint',
|
||||
|
||||
@ -7,7 +7,6 @@ export class PublicCommunityInfoLoggingView extends AbstractLoggingView {
|
||||
super()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public toJSON(): any {
|
||||
return {
|
||||
name: this.self.name,
|
||||
|
||||
@ -7,7 +7,6 @@ export class SendCoinsArgsLoggingView extends AbstractLoggingView {
|
||||
super()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public toJSON(): any {
|
||||
return {
|
||||
recipientCommunityUuid: this.self.recipientCommunityUuid,
|
||||
|
||||
@ -7,7 +7,6 @@ export class SendCoinsResultLoggingView extends AbstractLoggingView {
|
||||
super()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public toJSON(): any {
|
||||
return {
|
||||
vote: this.self.vote,
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { Field, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export class GetPublicKeyResult {
|
||||
constructor(pubKey: string) {
|
||||
this.publicKey = pubKey
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
// eslint-disable-next-line camelcase
|
||||
import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/client/1_0/AuthenticationClient'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export class AuthenticationClient extends V1_0_AuthenticationClient {}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
// eslint-disable-next-line camelcase
|
||||
import { FederationClient as V1_0_FederationClient } from '@/federation/client/1_0/FederationClient'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export class FederationClient extends V1_0_FederationClient {}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
// eslint-disable-next-line camelcase
|
||||
import { SendCoinsClient as V1_0_SendCoinsClient } from '@/federation/client/1_0/SendCoinsClient'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export class SendCoinsClient extends V1_0_SendCoinsClient {}
|
||||
|
||||
@ -1,21 +1,18 @@
|
||||
import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/client/1_0/AuthenticationClient'
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
import { AuthenticationClient as V1_1_AuthenticationClient } from '@/federation/client/1_1/AuthenticationClient'
|
||||
import { ApiVersionType } from '@/federation/enum/apiVersionType'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
type AuthenticationClient = V1_0_AuthenticationClient | V1_1_AuthenticationClient
|
||||
|
||||
interface AuthenticationClientInstance {
|
||||
id: number
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
|
||||
client: AuthenticationClient
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
||||
export class AuthenticationClientFactory {
|
||||
private static instanceArray: AuthenticationClientInstance[] = []
|
||||
|
||||
@ -23,7 +20,7 @@ export class AuthenticationClientFactory {
|
||||
* The Singleton's constructor should always be private to prevent direct
|
||||
* construction calls with the `new` operator.
|
||||
*/
|
||||
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
|
||||
|
||||
private constructor() {}
|
||||
|
||||
private static createAuthenticationClient = (dbCom: DbFederatedCommunity) => {
|
||||
|
||||
@ -1,22 +1,19 @@
|
||||
import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
import { FederationClient as V1_0_FederationClient } from '@/federation/client/1_0/FederationClient'
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
import { FederationClient as V1_1_FederationClient } from '@/federation/client/1_1/FederationClient'
|
||||
import { ApiVersionType } from '@/federation/enum/apiVersionType'
|
||||
import { ensureUrlEndsWithSlash } from '@/util/utilities'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
type FederationClient = V1_0_FederationClient | V1_1_FederationClient
|
||||
|
||||
interface FederationClientInstance {
|
||||
id: number
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
|
||||
client: FederationClient
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
||||
export class FederationClientFactory {
|
||||
private static instanceArray: FederationClientInstance[] = []
|
||||
|
||||
@ -24,7 +21,7 @@ export class FederationClientFactory {
|
||||
* The Singleton's constructor should always be private to prevent direct
|
||||
* construction calls with the `new` operator.
|
||||
*/
|
||||
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
|
||||
|
||||
private constructor() {}
|
||||
|
||||
private static createFederationClient = (dbCom: DbFederatedCommunity) => {
|
||||
|
||||
@ -1,21 +1,18 @@
|
||||
import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
import { SendCoinsClient as V1_0_SendCoinsClient } from '@/federation/client/1_0/SendCoinsClient'
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
import { SendCoinsClient as V1_1_SendCoinsClient } from '@/federation/client/1_1/SendCoinsClient'
|
||||
import { ApiVersionType } from '@/federation/enum/apiVersionType'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
type SendCoinsClient = V1_0_SendCoinsClient | V1_1_SendCoinsClient
|
||||
|
||||
interface SendCoinsClientInstance {
|
||||
id: number
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
|
||||
client: SendCoinsClient
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
||||
export class SendCoinsClientFactory {
|
||||
private static instanceArray: SendCoinsClientInstance[] = []
|
||||
|
||||
@ -23,7 +20,7 @@ export class SendCoinsClientFactory {
|
||||
* The Singleton's constructor should always be private to prevent direct
|
||||
* construction calls with the `new` operator.
|
||||
*/
|
||||
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
|
||||
|
||||
private constructor() {}
|
||||
|
||||
private static createSendCoinsClient = (dbCom: DbFederatedCommunity) => {
|
||||
|
||||
@ -1,17 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { Connection } from '@dbTools/typeorm'
|
||||
import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity'
|
||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||
import { GraphQLClient } from 'graphql-request'
|
||||
import { Response } from 'graphql-request/dist/types'
|
||||
|
||||
import { testEnvironment, cleanDB } from '@test/helpers'
|
||||
import { cleanDB, testEnvironment } from '@test/helpers'
|
||||
import { logger } from '@test/testSetup'
|
||||
|
||||
import { validateCommunities } from './validateCommunities'
|
||||
@ -62,9 +55,8 @@ describe('validate Communities', () => {
|
||||
describe('with one Community of api 1_0 but missing pubKey response', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
|
||||
jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return { data: {} } as Response<unknown>
|
||||
})
|
||||
const variables1 = {
|
||||
@ -78,7 +70,6 @@ describe('validate Communities', () => {
|
||||
.into(DbFederatedCommunity)
|
||||
.values(variables1)
|
||||
.orUpdate({
|
||||
// eslint-disable-next-line camelcase
|
||||
conflict_target: ['id', 'publicKey', 'apiVersion'],
|
||||
overwrite: ['end_point', 'last_announced_at'],
|
||||
})
|
||||
@ -101,9 +92,8 @@ describe('validate Communities', () => {
|
||||
describe('with one Community of api 1_0 and not matching pubKey', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
|
||||
jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return {
|
||||
data: {
|
||||
getPublicKey: {
|
||||
@ -123,15 +113,14 @@ describe('validate Communities', () => {
|
||||
.into(DbFederatedCommunity)
|
||||
.values(variables1)
|
||||
.orUpdate({
|
||||
// eslint-disable-next-line camelcase
|
||||
conflict_target: ['id', 'publicKey', 'apiVersion'],
|
||||
overwrite: ['end_point', 'last_announced_at'],
|
||||
})
|
||||
.execute()
|
||||
/*
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
|
||||
jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
|
||||
return {
|
||||
data: {
|
||||
getPublicCommunityInfo: {
|
||||
@ -183,9 +172,8 @@ describe('validate Communities', () => {
|
||||
describe('with one Community of api 1_0 and matching pubKey', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
|
||||
jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return {
|
||||
data: {
|
||||
getPublicKey: {
|
||||
@ -205,7 +193,6 @@ describe('validate Communities', () => {
|
||||
.into(DbFederatedCommunity)
|
||||
.values(variables1)
|
||||
.orUpdate({
|
||||
// eslint-disable-next-line camelcase
|
||||
conflict_target: ['id', 'publicKey', 'apiVersion'],
|
||||
overwrite: ['end_point', 'last_announced_at'],
|
||||
})
|
||||
@ -251,9 +238,8 @@ describe('validate Communities', () => {
|
||||
describe('with two Communities of api 1_0 and 1_1', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
|
||||
jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return {
|
||||
data: {
|
||||
getPublicKey: {
|
||||
@ -273,7 +259,6 @@ describe('validate Communities', () => {
|
||||
.into(DbFederatedCommunity)
|
||||
.values(variables2)
|
||||
.orUpdate({
|
||||
// eslint-disable-next-line camelcase
|
||||
conflict_target: ['id', 'publicKey', 'apiVersion'],
|
||||
overwrite: ['end_point', 'last_announced_at'],
|
||||
})
|
||||
@ -303,9 +288,8 @@ describe('validate Communities', () => {
|
||||
let dbCom: DbFederatedCommunity
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
|
||||
jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return {
|
||||
data: {
|
||||
getPublicKey: {
|
||||
@ -325,7 +309,6 @@ describe('validate Communities', () => {
|
||||
.into(DbFederatedCommunity)
|
||||
.values(variables3)
|
||||
.orUpdate({
|
||||
// eslint-disable-next-line camelcase
|
||||
conflict_target: ['id', 'publicKey', 'apiVersion'],
|
||||
overwrite: ['end_point', 'last_announced_at'],
|
||||
})
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
/** eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/** eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
import { IsNull } from '@dbTools/typeorm'
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity'
|
||||
@ -27,8 +25,8 @@ export async function startValidateCommunities(timerInterval: number): Promise<v
|
||||
|
||||
// TODO: replace the timer-loop by an event-based communication to verify announced foreign communities
|
||||
// better to use setTimeout twice than setInterval once -> see https://javascript.info/settimeout-setinterval
|
||||
setTimeout(function run() {
|
||||
void validateCommunities()
|
||||
setTimeout(async function run() {
|
||||
await validateCommunities()
|
||||
setTimeout(run, timerInterval)
|
||||
}, timerInterval)
|
||||
}
|
||||
@ -55,7 +53,7 @@ export async function validateCommunities(): Promise<void> {
|
||||
}
|
||||
try {
|
||||
const client = FederationClientFactory.getInstance(dbCom)
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
if (client instanceof V1_0_FederationClient) {
|
||||
const pubKey = await client.getPublicKey()
|
||||
if (pubKey && pubKey === dbCom.publicKey.toString('hex')) {
|
||||
|
||||
@ -3,10 +3,10 @@ import { Decimal } from 'decimal.js-light'
|
||||
import { ArgsType, Field, Int } from 'type-graphql'
|
||||
|
||||
import {
|
||||
CONTRIBUTIONLINK_NAME_MAX_CHARS,
|
||||
CONTRIBUTIONLINK_NAME_MIN_CHARS,
|
||||
MEMO_MAX_CHARS,
|
||||
MEMO_MIN_CHARS,
|
||||
CONTRIBUTIONLINK_NAME_MIN_CHARS,
|
||||
CONTRIBUTIONLINK_NAME_MAX_CHARS,
|
||||
} from '@/graphql/resolver/const/const'
|
||||
import { isValidDateString } from '@/graphql/validator/DateString'
|
||||
import { IsPositiveDecimal } from '@/graphql/validator/Decimal'
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { IsInt, IsString, IsEnum } from 'class-validator'
|
||||
import { ArgsType, Field, Int, InputType } from 'type-graphql'
|
||||
import { IsEnum, IsInt, IsString } from 'class-validator'
|
||||
import { ArgsType, Field, InputType, Int } from 'type-graphql'
|
||||
|
||||
import { ContributionMessageType } from '@enum/ContributionMessageType'
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
/* eslint-disable type-graphql/invalid-nullable-input-type */
|
||||
import { IsPositive, IsEnum } from 'class-validator'
|
||||
import { ArgsType, Field, Int, InputType } from 'type-graphql'
|
||||
import { IsEnum, IsPositive } from 'class-validator'
|
||||
import { ArgsType, Field, InputType, Int } from 'type-graphql'
|
||||
|
||||
import { Order } from '@enum/Order'
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { IsBoolean, IsPositive, IsString } from 'class-validator'
|
||||
import { Field, ArgsType, Int, InputType } from 'type-graphql'
|
||||
import { ArgsType, Field, InputType, Int } from 'type-graphql'
|
||||
|
||||
import { ContributionStatus } from '@enum/ContributionStatus'
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { IsPositive, IsEnum } from 'class-validator'
|
||||
import { ArgsType, Field, Int, InputType } from 'type-graphql'
|
||||
import { IsEnum, IsPositive } from 'class-validator'
|
||||
import { ArgsType, Field, InputType, Int } from 'type-graphql'
|
||||
|
||||
import { RoleNames } from '@enum/RoleNames'
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
/* eslint-disable type-graphql/invalid-nullable-input-type */
|
||||
import { IsBoolean } from 'class-validator'
|
||||
import { Field, InputType } from 'type-graphql'
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { MaxLength, MinLength, IsString } from 'class-validator'
|
||||
import { IsString, MaxLength, MinLength } from 'class-validator'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ArgsType, Field } from 'type-graphql'
|
||||
|
||||
|
||||
@ -7,22 +7,25 @@ import { INALIENABLE_RIGHTS } from '@/auth/INALIENABLE_RIGHTS'
|
||||
import { decode, encode } from '@/auth/JWT'
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import {
|
||||
ROLE_UNAUTHORIZED,
|
||||
ROLE_USER,
|
||||
ROLE_ADMIN,
|
||||
ROLE_DLT_CONNECTOR,
|
||||
ROLE_MODERATOR,
|
||||
ROLE_MODERATOR_AI,
|
||||
ROLE_DLT_CONNECTOR,
|
||||
ROLE_UNAUTHORIZED,
|
||||
ROLE_USER,
|
||||
} from '@/auth/ROLES'
|
||||
import { Context } from '@/server/context'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { Context } from '@/server/context'
|
||||
|
||||
export const isAuthorized: AuthChecker<Context> = async ({ context }, rights) => {
|
||||
context.role = ROLE_UNAUTHORIZED // unauthorized user
|
||||
|
||||
// is rights an inalienable right?
|
||||
if ((rights as RIGHTS[]).reduce((acc, right) => acc && INALIENABLE_RIGHTS.includes(right), true))
|
||||
if (
|
||||
(rights as RIGHTS[]).reduce((acc, right) => acc && INALIENABLE_RIGHTS.includes(right), true)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Do we have a token?
|
||||
if (!context.token) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { IsString, IsOptional, MaxLength, IsNumber, IsBoolean, IsUrl } from 'class-validator'
|
||||
import { InputType, Field, Int } from 'type-graphql'
|
||||
import { IsBoolean, IsNumber, IsOptional, IsString, IsUrl, MaxLength } from 'class-validator'
|
||||
import { Field, InputType, Int } from 'type-graphql'
|
||||
|
||||
@InputType()
|
||||
export class ProjectBrandingInput {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Point } from '@dbTools/typeorm'
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity'
|
||||
import { ObjectType, Field } from 'type-graphql'
|
||||
import { Field, ObjectType } from 'type-graphql'
|
||||
|
||||
import { Point2Location } from '@/graphql/resolver/util/Location2Point'
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field } from 'type-graphql'
|
||||
import { Field, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class AdminUpdateContribution {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field, Int, Float } from 'type-graphql'
|
||||
import { Field, Float, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class Balance {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ObjectType, Field } from 'type-graphql'
|
||||
import { Field, ObjectType } from 'type-graphql'
|
||||
|
||||
import { Message } from '@/apis/openai/model/Message'
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class Community {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class DynamicStatisticsFields {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Contribution as dbContribution } from '@entity/Contribution'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { User } from './User'
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { ContributionLink as dbContributionLink } from '@entity/ContributionLink'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { ContributionLink } from '@model/ContributionLink'
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
interface DecayInterface {
|
||||
balance: Decimal
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { ensureUrlEndsWithSlash } from '@/util/utilities'
|
||||
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { ObjectType, Field, Float, Int } from 'type-graphql'
|
||||
import { Field, Float, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { GdtEntryType } from '@enum/GdtEntryType'
|
||||
|
||||
@ -12,9 +10,9 @@ export class GdtEntry {
|
||||
date,
|
||||
email,
|
||||
comment,
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
coupon_code,
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
gdt_entry_type_id,
|
||||
factor,
|
||||
amount2,
|
||||
@ -26,9 +24,9 @@ export class GdtEntry {
|
||||
this.date = date
|
||||
this.email = email
|
||||
this.comment = comment
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
this.couponCode = coupon_code
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
this.gdtEntryType = gdt_entry_type_id
|
||||
this.factor = factor
|
||||
this.amount2 = amount2
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ObjectType, Field, Int, Float } from 'type-graphql'
|
||||
import { Field, Float, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { GdtEntry } from './GdtEntry'
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ObjectType, Field } from 'type-graphql'
|
||||
import { Field, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class KlickTipp {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class OpenCreation {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class Pagination {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ProjectBranding as dbProjectBranding } from '@entity/ProjectBranding'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class ProjectBranding {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { Space as HumhubSpace } from '@/apis/humhub/model/Space'
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ObjectType, Field } from 'type-graphql'
|
||||
import { Field, ObjectType } from 'type-graphql'
|
||||
|
||||
import { SpacesResponse } from '@/apis/humhub/model/SpacesResponse'
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Transaction as dbTransaction } from '@entity/Transaction'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { TransactionTypeId } from '@enum/TransactionTypeId'
|
||||
|
||||
@ -46,7 +46,7 @@ export class Transaction {
|
||||
this.linkedTransactionId = transaction.linkedTransactionId ?? null
|
||||
this.linkId = transaction.contribution
|
||||
? transaction.contribution.contributionLinkId
|
||||
: transaction.transactionLinkId ?? null
|
||||
: (transaction.transactionLinkId ?? null)
|
||||
this.previousBalance =
|
||||
transaction.previousTransaction?.balance.toDecimalPlaces(2, Decimal.ROUND_DOWN) ??
|
||||
new Decimal(0)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ObjectType, Field } from 'type-graphql'
|
||||
import { Field, ObjectType } from 'type-graphql'
|
||||
|
||||
import { Balance } from './Balance'
|
||||
import { Transaction } from './Transaction'
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Contribution } from '@entity/Contribution'
|
||||
import { User } from '@entity/User'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class UnconfirmedContribution {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user