mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into 2803-open-contribution-edit-button
This commit is contained in:
commit
8f56be790b
43
.github/file-filters.yml
vendored
Normal file
43
.github/file-filters.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# These file filter patterns are used by the action https://github.com/dorny/paths-filter
|
||||||
|
|
||||||
|
# more differentiated filters for admin interface, which might be used later
|
||||||
|
# admin_locales: &admin_locales
|
||||||
|
# - 'admin/src/locales/**'
|
||||||
|
# - 'admin/scripts/sort*'
|
||||||
|
|
||||||
|
# admin_stylelinting: &admin_stylelinting
|
||||||
|
# - 'admin/{components,layouts,pages}/**/*.{scss,vue}'
|
||||||
|
# - 'admin/.stylelintrc.js'
|
||||||
|
|
||||||
|
# admin_linting: &admin_linting
|
||||||
|
# - 'admin/.eslint*'
|
||||||
|
# - 'admin/babel.config.js'
|
||||||
|
# - 'admin/package.json'
|
||||||
|
# - 'admin/**/*.{js,vue}'
|
||||||
|
# - *admin_locales
|
||||||
|
|
||||||
|
# admin_unit_testing: &admin_unit_testing
|
||||||
|
# - 'admin/package.json'
|
||||||
|
# - 'admin/{jest,vue}.config.js'
|
||||||
|
# - 'admin/{public,run,test}/**/*'
|
||||||
|
# - 'admin/src/!(locales)/**/*'
|
||||||
|
|
||||||
|
# admin_docker_building: &admin_docker_building
|
||||||
|
# - 'admin/.dockerignore'
|
||||||
|
# - 'admin/Dockerfile'
|
||||||
|
# - *admin_unit_testing
|
||||||
|
|
||||||
|
admin: &admin
|
||||||
|
- 'admin/**/*'
|
||||||
|
|
||||||
|
dht_node: &dht_node
|
||||||
|
- 'dht-node/**/*'
|
||||||
|
|
||||||
|
docker: &docker
|
||||||
|
- 'docker-compose.*'
|
||||||
|
|
||||||
|
federation: &federation
|
||||||
|
- 'federation/**/*'
|
||||||
|
|
||||||
|
frontend: &frontend
|
||||||
|
- 'frontend/**/*'
|
||||||
58
.github/workflows/e2e-test.yml
vendored
Normal file
58
.github/workflows/e2e-test.yml
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
name: Gradido End-to-End Test CI
|
||||||
|
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
end-to-end-tests:
|
||||||
|
name: End-to-End Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Boot up test system | docker-compose mariadb
|
||||||
|
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach mariadb
|
||||||
|
|
||||||
|
- name: Boot up test system | docker-compose database
|
||||||
|
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
|
||||||
|
|
||||||
|
- name: Boot up test system | docker-compose backend
|
||||||
|
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
|
||||||
|
|
||||||
|
- name: Sleep for 10 seconds
|
||||||
|
run: sleep 10s
|
||||||
|
|
||||||
|
- name: Boot up test system | seed backend
|
||||||
|
run: |
|
||||||
|
sudo chown runner:docker -R *
|
||||||
|
cd database
|
||||||
|
yarn && yarn dev_reset
|
||||||
|
cd ../backend
|
||||||
|
yarn && yarn seed
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
- name: Boot up test system | docker-compose frontends
|
||||||
|
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps frontend admin nginx
|
||||||
|
|
||||||
|
- name: Boot up test system | docker-compose mailserver
|
||||||
|
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mailserver
|
||||||
|
|
||||||
|
- name: Sleep for 15 seconds
|
||||||
|
run: sleep 15s
|
||||||
|
|
||||||
|
- name: End-to-end tests | run tests
|
||||||
|
id: e2e-tests
|
||||||
|
run: |
|
||||||
|
cd e2e-tests/
|
||||||
|
yarn
|
||||||
|
yarn run cypress run
|
||||||
|
- name: End-to-end tests | if tests failed, upload screenshots
|
||||||
|
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: cypress-screenshots
|
||||||
|
path: /home/runner/work/gradido/gradido/e2e-tests/cypress/screenshots/
|
||||||
84
.github/workflows/test-admin-interface.yml
vendored
Normal file
84
.github/workflows/test-admin-interface.yml
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
name: Gradido Admin Interface Test CI
|
||||||
|
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# only (but most important) job from this workflow required for pull requests
|
||||||
|
# check results serve as run conditions for all other jobs here
|
||||||
|
files-changed:
|
||||||
|
name: Detect File Changes - Admin Interface
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
admin: ${{ steps.changes.outputs.admin }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3.3.0
|
||||||
|
|
||||||
|
- name: Check for admin interface file changes
|
||||||
|
uses: dorny/paths-filter@v2.11.1
|
||||||
|
id: changes
|
||||||
|
with:
|
||||||
|
token: ${{ github.token }}
|
||||||
|
filters: .github/file-filters.yml
|
||||||
|
list-files: shell
|
||||||
|
|
||||||
|
|
||||||
|
build_test:
|
||||||
|
if: needs.files-changed.outputs.admin == 'true'
|
||||||
|
name: Docker Build Test - Admin Interface
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Admin Interface | Build 'test' image
|
||||||
|
run: docker build --target test -t "gradido/admin:test" admin/ --build-arg NODE_ENV="test"
|
||||||
|
|
||||||
|
unit_test:
|
||||||
|
if: needs.files-changed.outputs.admin == 'true'
|
||||||
|
name: Unit Tests - Admin Interface
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Admin Interface | Unit tests
|
||||||
|
run: cd admin && yarn && yarn run test
|
||||||
|
|
||||||
|
lint:
|
||||||
|
if: needs.files-changed.outputs.admin == 'true'
|
||||||
|
name: Lint - Admin Interface
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Admin Interface | Lint
|
||||||
|
run: cd admin && yarn && yarn run lint
|
||||||
|
|
||||||
|
stylelint:
|
||||||
|
if: needs.files-changed.outputs.admin == 'true'
|
||||||
|
name: Stylelint - Admin Interface
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Admin Interface | Stylelint
|
||||||
|
run: cd admin && yarn && yarn run stylelint
|
||||||
|
|
||||||
|
locales:
|
||||||
|
if: needs.files-changed.outputs.admin == 'true'
|
||||||
|
name: Locales - Admin Interface
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Admin Interface | Locales
|
||||||
|
run: cd admin && yarn && yarn run locales
|
||||||
341
.github/workflows/test.yml
vendored
341
.github/workflows/test.yml
vendored
@ -3,57 +3,6 @@ name: gradido test CI
|
|||||||
on: push
|
on: push
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
##############################################################################
|
|
||||||
# JOB: DOCKER BUILD TEST FRONTEND ############################################
|
|
||||||
##############################################################################
|
|
||||||
build_test_frontend:
|
|
||||||
name: Docker Build Test - Frontend
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
#needs: [nothing]
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# FRONTEND ###############################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Frontend | Build `test` image
|
|
||||||
run: |
|
|
||||||
docker build --target test -t "gradido/frontend:test" frontend/
|
|
||||||
docker save "gradido/frontend:test" > /tmp/frontend.tar
|
|
||||||
- name: Upload Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: docker-frontend-test
|
|
||||||
path: /tmp/frontend.tar
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: DOCKER BUILD TEST ADMIN INTERFACE #####################################
|
|
||||||
##############################################################################
|
|
||||||
build_test_admin:
|
|
||||||
name: Docker Build Test - Admin Interface
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# ADMIN INTERFACE ########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Admin | Build `test` image
|
|
||||||
run: |
|
|
||||||
docker build --target test -t "gradido/admin:test" admin/ --build-arg NODE_ENV="test"
|
|
||||||
docker save "gradido/admin:test" > /tmp/admin.tar
|
|
||||||
- name: Upload Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: docker-admin-test
|
|
||||||
path: /tmp/admin.tar
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# JOB: DOCKER BUILD TEST BACKEND #############################################
|
# JOB: DOCKER BUILD TEST BACKEND #############################################
|
||||||
##############################################################################
|
##############################################################################
|
||||||
@ -157,114 +106,6 @@ jobs:
|
|||||||
name: docker-nginx-test
|
name: docker-nginx-test
|
||||||
path: /tmp/nginx.tar
|
path: /tmp/nginx.tar
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: LOCALES FRONTEND ######################################################
|
|
||||||
##############################################################################
|
|
||||||
locales_frontend:
|
|
||||||
name: Locales - Frontend
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# LOCALES FRONTEND #######################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Frontend | Locales
|
|
||||||
run: cd frontend && yarn && yarn run locales
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: LINT FRONTEND #########################################################
|
|
||||||
##############################################################################
|
|
||||||
lint_frontend:
|
|
||||||
name: Lint - Frontend
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# LINT FRONTEND ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Frontend | Lint
|
|
||||||
run: cd frontend && yarn && yarn run lint
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: STYLELINT FRONTEND ####################################################
|
|
||||||
##############################################################################
|
|
||||||
stylelint_frontend:
|
|
||||||
name: Stylelint - Frontend
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# STYLELINT FRONTEND #####################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Frontend | Stylelint
|
|
||||||
run: cd frontend && yarn && yarn run stylelint
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: LINT ADMIN INTERFACE ##################################################
|
|
||||||
##############################################################################
|
|
||||||
lint_admin:
|
|
||||||
name: Lint - Admin Interface
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# LINT ADMIN INTERFACE ###################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Admin Interface | Lint
|
|
||||||
run: cd admin && yarn && yarn run lint
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: STYLELINT ADMIN INTERFACE #############################################
|
|
||||||
##############################################################################
|
|
||||||
stylelint_admin:
|
|
||||||
name: Stylelint - Admin Interface
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# STYLELINT ADMIN INTERFACE ##############################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Admin Interface | Stylelint
|
|
||||||
run: cd admin && yarn && yarn run stylelint
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: LOCALES ADMIN #########################################################
|
|
||||||
##############################################################################
|
|
||||||
locales_admin:
|
|
||||||
name: Locales - Admin Interface
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# LOCALES FRONTEND #######################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Admin | Locales
|
|
||||||
run: cd admin && yarn && yarn run locales
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# JOB: LINT BACKEND ##########################################################
|
# JOB: LINT BACKEND ##########################################################
|
||||||
##############################################################################
|
##############################################################################
|
||||||
@ -319,68 +160,6 @@ jobs:
|
|||||||
- name: Database | Lint
|
- name: Database | Lint
|
||||||
run: cd database && yarn && yarn run lint
|
run: cd database && yarn && yarn run lint
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: UNIT TEST FRONTEND ###################################################
|
|
||||||
##############################################################################
|
|
||||||
unit_test_frontend:
|
|
||||||
name: Unit tests - Frontend
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# UNIT TESTS FRONTEND ####################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Frontend | Unit tests
|
|
||||||
run: |
|
|
||||||
cd frontend && yarn && yarn run test
|
|
||||||
cp -r ./coverage ../
|
|
||||||
##########################################################################
|
|
||||||
# COVERAGE CHECK FRONTEND ################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: frontend | Coverage check
|
|
||||||
uses: webcraftmedia/coverage-check-action@master
|
|
||||||
with:
|
|
||||||
report_name: Coverage Frontend
|
|
||||||
type: lcov
|
|
||||||
result_path: ./frontend/coverage/lcov.info
|
|
||||||
min_coverage: 95
|
|
||||||
token: ${{ github.token }}
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: UNIT TEST ADMIN INTERFACE #############################################
|
|
||||||
##############################################################################
|
|
||||||
unit_test_admin:
|
|
||||||
name: Unit tests - Admin Interface
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# UNIT TESTS ADMIN INTERFACE #############################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Admin Interface | Unit tests
|
|
||||||
run: |
|
|
||||||
cd admin && yarn && yarn run test
|
|
||||||
cp -r ./coverage ../
|
|
||||||
##########################################################################
|
|
||||||
# COVERAGE CHECK ADMIN INTERFACE #########################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Admin Interface | Coverage check
|
|
||||||
uses: webcraftmedia/coverage-check-action@master
|
|
||||||
with:
|
|
||||||
report_name: Coverage Admin Interface
|
|
||||||
type: lcov
|
|
||||||
result_path: ./admin/coverage/lcov.info
|
|
||||||
min_coverage: 97
|
|
||||||
token: ${{ github.token }}
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# JOB: UNIT TEST BACKEND ####################################################
|
# JOB: UNIT TEST BACKEND ####################################################
|
||||||
##############################################################################
|
##############################################################################
|
||||||
@ -415,20 +194,7 @@ jobs:
|
|||||||
- name: backend | docker-compose database
|
- name: backend | docker-compose database
|
||||||
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
|
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
|
||||||
- name: backend Unit tests | test
|
- name: backend Unit tests | test
|
||||||
run: |
|
run: cd database && yarn && yarn build && cd ../backend && yarn && yarn test
|
||||||
cd database && yarn && yarn build && cd ../backend && yarn && yarn test
|
|
||||||
cp -r ./coverage ../
|
|
||||||
##########################################################################
|
|
||||||
# COVERAGE CHECK BACKEND #################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: backend | Coverage check
|
|
||||||
uses: webcraftmedia/coverage-check-action@master
|
|
||||||
with:
|
|
||||||
report_name: Coverage Backend
|
|
||||||
type: lcov
|
|
||||||
result_path: ./backend/coverage/lcov.info
|
|
||||||
min_coverage: 80
|
|
||||||
token: ${{ github.token }}
|
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# DATABASE MIGRATION TEST UP + RESET #####################################
|
# DATABASE MIGRATION TEST UP + RESET #####################################
|
||||||
@ -452,108 +218,3 @@ jobs:
|
|||||||
run: docker-compose -f docker-compose.yml run -T database yarn up
|
run: docker-compose -f docker-compose.yml run -T database yarn up
|
||||||
- name: database | reset
|
- name: database | reset
|
||||||
run: docker-compose -f docker-compose.yml run -T database yarn reset
|
run: docker-compose -f docker-compose.yml run -T database yarn reset
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# JOB: END-TO-END TESTS #####################################################
|
|
||||||
##############################################################################
|
|
||||||
end-to-end-tests:
|
|
||||||
name: End-to-End Tests
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [build_test_mariadb, build_test_database_up, build_test_admin, build_test_frontend, build_test_nginx]
|
|
||||||
steps:
|
|
||||||
##########################################################################
|
|
||||||
# CHECKOUT CODE ##########################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
##########################################################################
|
|
||||||
# DOWNLOAD DOCKER IMAGES #################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Download Docker Image (Mariadb)
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: docker-mariadb-test
|
|
||||||
path: /tmp
|
|
||||||
- name: Load Docker Image (Mariadb)
|
|
||||||
run: docker load < /tmp/mariadb.tar
|
|
||||||
- name: Download Docker Image (Database Up)
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: docker-database-test_up
|
|
||||||
path: /tmp
|
|
||||||
- name: Load Docker Image (Database Up)
|
|
||||||
run: docker load < /tmp/database_up.tar
|
|
||||||
- name: Download Docker Image (Frontend)
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: docker-frontend-test
|
|
||||||
path: /tmp
|
|
||||||
- name: Load Docker Image (Frontend)
|
|
||||||
run: docker load < /tmp/frontend.tar
|
|
||||||
- name: Download Docker Image (Admin Interface)
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: docker-admin-test
|
|
||||||
path: /tmp
|
|
||||||
- name: Load Docker Image (Admin Interface)
|
|
||||||
run: docker load < /tmp/admin.tar
|
|
||||||
- name: Download Docker Image (Nginx)
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: docker-nginx-test
|
|
||||||
path: /tmp
|
|
||||||
- name: Load Docker Image (Nginx)
|
|
||||||
run: docker load < /tmp/nginx.tar
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# BOOT UP THE TEST SYSTEM ################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Boot up test system | docker-compose mariadb
|
|
||||||
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach mariadb
|
|
||||||
|
|
||||||
- name: Boot up test system | docker-compose database
|
|
||||||
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
|
|
||||||
|
|
||||||
- name: Boot up test system | docker-compose backend
|
|
||||||
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
|
|
||||||
|
|
||||||
- name: Sleep for 10 seconds
|
|
||||||
run: sleep 10s
|
|
||||||
|
|
||||||
- name: Boot up test system | seed backend
|
|
||||||
run: |
|
|
||||||
sudo chown runner:docker -R *
|
|
||||||
cd database
|
|
||||||
yarn && yarn dev_reset
|
|
||||||
cd ../backend
|
|
||||||
yarn && yarn seed
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
- name: Boot up test system | docker-compose frontends
|
|
||||||
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps frontend admin nginx
|
|
||||||
|
|
||||||
- name: Boot up test system | docker-compose mailserver
|
|
||||||
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mailserver
|
|
||||||
|
|
||||||
- name: Sleep for 15 seconds
|
|
||||||
run: sleep 15s
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# END-TO-END TESTS #######################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: End-to-end tests | run tests
|
|
||||||
id: e2e-tests
|
|
||||||
run: |
|
|
||||||
cd e2e-tests/
|
|
||||||
yarn
|
|
||||||
yarn run cypress run --spec cypress/e2e/User.Authentication.feature,cypress/e2e/User.Authentication.ResetPassword.feature,cypress/e2e/User.Registration.feature
|
|
||||||
- name: End-to-end tests | if tests failed, upload screenshots
|
|
||||||
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: cypress-screenshots
|
|
||||||
path: /home/runner/work/gradido/gradido/e2e-tests/cypress/screenshots/
|
|
||||||
|
|||||||
53
.github/workflows/test_dht-node.yml
vendored
53
.github/workflows/test_dht-node.yml
vendored
@ -3,17 +3,38 @@ name: Gradido DHT Node Test CI
|
|||||||
on: push
|
on: push
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
# only (but most important) job from this workflow required for pull requests
|
||||||
|
# check results serve as run conditions for all other jobs here
|
||||||
|
files-changed:
|
||||||
|
name: Detect File Changes - DHT Node
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
dht_node: ${{ steps.changes.outputs.dht_node }}
|
||||||
|
docker: ${{ steps.changes.outputs.docker }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3.3.0
|
||||||
|
|
||||||
|
- name: Check for frontend file changes
|
||||||
|
uses: dorny/paths-filter@v2.11.1
|
||||||
|
id: changes
|
||||||
|
with:
|
||||||
|
token: ${{ github.token }}
|
||||||
|
filters: .github/file-filters.yml
|
||||||
|
list-files: shell
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# JOB: DOCKER BUILD TEST #####################################################
|
# JOB: DOCKER BUILD TEST #####################################################
|
||||||
##############################################################################
|
##############################################################################
|
||||||
build:
|
build:
|
||||||
name: Docker Build Test - DHT Node
|
name: Docker Build Test - DHT Node
|
||||||
|
if: needs.files-changed.outputs.dht_node == 'true' || needs.files-changed.outputs.docker == 'true'
|
||||||
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Build `test` image
|
- name: Build 'test' image
|
||||||
run: |
|
run: |
|
||||||
docker build --target test -t "gradido/dht-node:test" -f dht-node/Dockerfile .
|
docker build --target test -t "gradido/dht-node:test" -f dht-node/Dockerfile .
|
||||||
docker save "gradido/dht-node:test" > /tmp/dht-node.tar
|
docker save "gradido/dht-node:test" > /tmp/dht-node.tar
|
||||||
@ -29,30 +50,24 @@ jobs:
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
lint:
|
lint:
|
||||||
name: Lint - DHT Node
|
name: Lint - DHT Node
|
||||||
|
if: needs.files-changed.outputs.dht_node == 'true'
|
||||||
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [build]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Download Docker Image
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: docker-dht-node-test
|
|
||||||
path: /tmp
|
|
||||||
- name: Load Docker Image
|
|
||||||
run: docker load < /tmp/dht-node.tar
|
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: docker run --rm gradido/dht-node:test yarn run lint
|
run: cd dht-node && yarn && yarn run lint
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# JOB: UNIT TEST #############################################################
|
# JOB: UNIT TEST #############################################################
|
||||||
##############################################################################
|
##############################################################################
|
||||||
unit_test:
|
unit_test:
|
||||||
name: Unit Tests - DHT Node
|
name: Unit Tests - DHT Node
|
||||||
|
if: needs.files-changed.outputs.dht_node == 'true' || needs.files-changed.outputs.docker == 'true'
|
||||||
|
needs: [files-changed, build]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [build]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@ -83,16 +98,4 @@ jobs:
|
|||||||
#- name: Unit tests
|
#- name: Unit tests
|
||||||
# run: cd database && yarn && yarn build && cd ../dht-node && yarn && yarn test
|
# run: cd database && yarn && yarn build && cd ../dht-node && yarn && yarn test
|
||||||
- name: Unit tests
|
- name: Unit tests
|
||||||
run: |
|
run: docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net --rm gradido/dht-node:test yarn run test
|
||||||
docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net -v ~/coverage:/app/coverage --rm gradido/dht-node:test yarn run test
|
|
||||||
cp -r ~/coverage ./coverage
|
|
||||||
|
|
||||||
- name: Coverage check
|
|
||||||
uses: webcraftmedia/coverage-check-action@master
|
|
||||||
with:
|
|
||||||
report_name: Coverage DHT Node
|
|
||||||
type: lcov
|
|
||||||
#result_path: ./dht-node/coverage/lcov.info
|
|
||||||
result_path: ./coverage/lcov.info
|
|
||||||
min_coverage: 79
|
|
||||||
token: ${{ github.token }}
|
|
||||||
|
|||||||
50
.github/workflows/test_federation.yml
vendored
50
.github/workflows/test_federation.yml
vendored
@ -3,11 +3,32 @@ name: Gradido Federation Test CI
|
|||||||
on: push
|
on: push
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
# only (but most important) job from this workflow required for pull requests
|
||||||
|
# check results serve as run conditions for all other jobs here
|
||||||
|
files-changed:
|
||||||
|
name: Detect File Changes - Federation
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
docker: ${{ steps.changes.outputs.docker }}
|
||||||
|
federation: ${{ steps.changes.outputs.federation }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3.3.0
|
||||||
|
|
||||||
|
- name: Check for frontend file changes
|
||||||
|
uses: dorny/paths-filter@v2.11.1
|
||||||
|
id: changes
|
||||||
|
with:
|
||||||
|
token: ${{ github.token }}
|
||||||
|
filters: .github/file-filters.yml
|
||||||
|
list-files: shell
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# JOB: DOCKER BUILD TEST #####################################################
|
# JOB: DOCKER BUILD TEST #####################################################
|
||||||
##############################################################################
|
##############################################################################
|
||||||
build:
|
build:
|
||||||
name: Docker Build Test - Federation
|
name: Docker Build Test - Federation
|
||||||
|
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.federation == 'true'
|
||||||
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@ -29,30 +50,24 @@ jobs:
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
lint:
|
lint:
|
||||||
name: Lint - Federation
|
name: Lint - Federation
|
||||||
|
if: needs.files-changed.outputs.federation == 'true'
|
||||||
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [build]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Download Docker Image
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: docker-federation-test
|
|
||||||
path: /tmp
|
|
||||||
- name: Load Docker Image
|
|
||||||
run: docker load < /tmp/federation.tar
|
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: docker run --rm gradido/federation:test yarn run lint
|
run: cd federation && yarn && yarn run lint
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# JOB: UNIT TEST #############################################################
|
# JOB: UNIT TEST #############################################################
|
||||||
##############################################################################
|
##############################################################################
|
||||||
unit_test:
|
unit_test:
|
||||||
name: Unit Tests - Federation
|
name: Unit Tests - Federation
|
||||||
|
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.federation == 'true'
|
||||||
|
needs: [files-changed, build]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [build]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@ -84,15 +99,4 @@ jobs:
|
|||||||
# run: cd database && yarn && yarn build && cd ../dht-node && yarn && yarn test
|
# run: cd database && yarn && yarn build && cd ../dht-node && yarn && yarn test
|
||||||
- name: Unit tests
|
- name: Unit tests
|
||||||
run: |
|
run: |
|
||||||
docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net -v ~/coverage:/app/coverage --rm gradido/federation:test yarn run test
|
docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net --rm gradido/federation:test yarn run test
|
||||||
cp -r ~/coverage ./coverage
|
|
||||||
|
|
||||||
- name: Coverage check
|
|
||||||
uses: webcraftmedia/coverage-check-action@master
|
|
||||||
with:
|
|
||||||
report_name: Coverage Federation
|
|
||||||
type: lcov
|
|
||||||
#result_path: ./federation/coverage/lcov.info
|
|
||||||
result_path: ./coverage/lcov.info
|
|
||||||
min_coverage: 72
|
|
||||||
token: ${{ github.token }}
|
|
||||||
|
|||||||
84
.github/workflows/test_frontend.yml
vendored
Normal file
84
.github/workflows/test_frontend.yml
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
name: Gradido Frontend Test CI
|
||||||
|
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# only (but most important) job from this workflow required for pull requests
|
||||||
|
# check results serve as run conditions for all other jobs here
|
||||||
|
files-changed:
|
||||||
|
name: Detect File Changes - Frontend
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
frontend: ${{ steps.changes.outputs.frontend }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3.3.0
|
||||||
|
|
||||||
|
- name: Check for frontend file changes
|
||||||
|
uses: dorny/paths-filter@v2.11.1
|
||||||
|
id: changes
|
||||||
|
with:
|
||||||
|
token: ${{ github.token }}
|
||||||
|
filters: .github/file-filters.yml
|
||||||
|
list-files: shell
|
||||||
|
|
||||||
|
|
||||||
|
build_test:
|
||||||
|
if: needs.files-changed.outputs.frontend == 'true'
|
||||||
|
name: Docker Build Test - Frontend
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Frontend | Build 'test' image
|
||||||
|
run: docker build --target test -t "gradido/frontend:test" frontend/ --build-arg NODE_ENV="test"
|
||||||
|
|
||||||
|
unit_test:
|
||||||
|
if: needs.files-changed.outputs.frontend == 'true'
|
||||||
|
name: Unit Tests - Frontend
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Frontend | Unit tests
|
||||||
|
run: cd frontend && yarn && yarn run test
|
||||||
|
|
||||||
|
lint:
|
||||||
|
if: needs.files-changed.outputs.frontend == 'true'
|
||||||
|
name: Lint - Frontend
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Frontend | Lint
|
||||||
|
run: cd frontend && yarn && yarn run lint
|
||||||
|
|
||||||
|
stylelint:
|
||||||
|
if: needs.files-changed.outputs.frontend == 'true'
|
||||||
|
name: Stylelint - Frontend
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Frontend | Stylelint
|
||||||
|
run: cd frontend && yarn && yarn run stylelint
|
||||||
|
|
||||||
|
locales:
|
||||||
|
if: needs.files-changed.outputs.frontend == 'true'
|
||||||
|
name: Locales - Frontend
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Frontend | Locales
|
||||||
|
run: cd frontend && yarn && yarn run locales
|
||||||
@ -1,11 +1,17 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
verbose: true,
|
verbose: true,
|
||||||
|
collectCoverage: true,
|
||||||
collectCoverageFrom: [
|
collectCoverageFrom: [
|
||||||
'src/**/*.{js,vue}',
|
'src/**/*.{js,vue}',
|
||||||
'!**/node_modules/**',
|
'!**/node_modules/**',
|
||||||
'!src/assets/**',
|
'!src/assets/**',
|
||||||
'!**/?(*.)+(spec|test).js?(x)',
|
'!**/?(*.)+(spec|test).js?(x)',
|
||||||
],
|
],
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
lines: 97,
|
||||||
|
},
|
||||||
|
},
|
||||||
moduleFileExtensions: [
|
moduleFileExtensions: [
|
||||||
'js',
|
'js',
|
||||||
// 'jsx',
|
// 'jsx',
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
"analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json",
|
"analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json",
|
||||||
"lint": "eslint --max-warnings=0 --ext .js,.vue,.json .",
|
"lint": "eslint --max-warnings=0 --ext .js,.vue,.json .",
|
||||||
"stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'",
|
"stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'",
|
||||||
"test": "cross-env TZ=UTC jest --coverage",
|
"test": "cross-env TZ=UTC jest",
|
||||||
"locales": "scripts/sort.sh"
|
"locales": "scripts/sort.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
},
|
},
|
||||||
"created": "Created for",
|
"created": "Created for",
|
||||||
"createdAt": "Created at",
|
"createdAt": "Created at",
|
||||||
"creation": "Amount",
|
"creation": "Creation",
|
||||||
"creationList": "Creation list",
|
"creationList": "Creation list",
|
||||||
"creation_form": {
|
"creation_form": {
|
||||||
"creation_for": "Active Basic Income for",
|
"creation_for": "Active Basic Income for",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
# Server
|
# Server
|
||||||
JWT_EXPIRES_IN=1m
|
JWT_EXPIRES_IN=2m
|
||||||
|
|
||||||
# Email
|
# Email
|
||||||
EMAIL=true
|
EMAIL=true
|
||||||
|
|||||||
@ -4,6 +4,11 @@ module.exports = {
|
|||||||
preset: 'ts-jest',
|
preset: 'ts-jest',
|
||||||
collectCoverage: true,
|
collectCoverage: true,
|
||||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
lines: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||||
setupFilesAfterEnv: ['<rootDir>/test/extensions.ts'],
|
setupFilesAfterEnv: ['<rootDir>/test/extensions.ts'],
|
||||||
modulePathIgnorePatterns: ['<rootDir>/build/'],
|
modulePathIgnorePatterns: ['<rootDir>/build/'],
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
"start": "cross-env TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js",
|
"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 --exec ts-node -r tsconfig-paths/register src/index.ts",
|
"dev": "cross-env TZ=UTC nodemon -w src --ext ts --exec ts-node -r tsconfig-paths/register src/index.ts",
|
||||||
"lint": "eslint --max-warnings=0 --ext .js,.ts .",
|
"lint": "eslint --max-warnings=0 --ext .js,.ts .",
|
||||||
"test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles",
|
"test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --forceExit --detectOpenHandles",
|
||||||
"seed": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/seeds/index.ts",
|
"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/klicktipp.ts",
|
"klicktipp": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/util/klicktipp.ts",
|
||||||
"locales": "scripts/sort.sh"
|
"locales": "scripts/sort.sh"
|
||||||
|
|||||||
@ -10,7 +10,7 @@ Decimal.set({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const constants = {
|
const constants = {
|
||||||
DB_VERSION: '0060-update_communities_table',
|
DB_VERSION: '0061-event_refactoring',
|
||||||
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||||
LOG4JS_CONFIG: 'log4js-config.json',
|
LOG4JS_CONFIG: 'log4js-config.json',
|
||||||
// default log level on production should be info
|
// default log level on production should be info
|
||||||
|
|||||||
@ -1,212 +1,217 @@
|
|||||||
import { EventProtocol as DbEvent } from '@entity/EventProtocol'
|
import { Event as DbEvent } from '@entity/Event'
|
||||||
|
import { User as DbUser } from '@entity/User'
|
||||||
|
import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage'
|
||||||
|
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||||
|
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
import { EventProtocolType } from './EventProtocolType'
|
import { EventProtocolType } from './EventProtocolType'
|
||||||
|
|
||||||
export const Event = (
|
export const Event = (
|
||||||
type: EventProtocolType,
|
type: EventProtocolType,
|
||||||
userId: number,
|
affectedUser: DbUser,
|
||||||
xUserId: number | null = null,
|
actingUser: DbUser,
|
||||||
xCommunityId: number | null = null,
|
involvedUser: DbUser | null = null,
|
||||||
transactionId: number | null = null,
|
involvedTransaction: DbTransaction | null = null,
|
||||||
contributionId: number | null = null,
|
involvedContribution: DbContribution | null = null,
|
||||||
|
involvedContributionMessage: DbContributionMessage | null = null,
|
||||||
amount: Decimal | null = null,
|
amount: Decimal | null = null,
|
||||||
messageId: number | null = null,
|
|
||||||
): DbEvent => {
|
): DbEvent => {
|
||||||
const event = new DbEvent()
|
const event = new DbEvent()
|
||||||
event.type = type
|
event.type = type
|
||||||
event.userId = userId
|
event.affectedUser = affectedUser
|
||||||
event.xUserId = xUserId
|
event.actingUser = actingUser
|
||||||
event.xCommunityId = xCommunityId
|
event.involvedUser = involvedUser
|
||||||
event.transactionId = transactionId
|
event.involvedTransaction = involvedTransaction
|
||||||
event.contributionId = contributionId
|
event.involvedContribution = involvedContribution
|
||||||
|
event.involvedContributionMessage = involvedContributionMessage
|
||||||
event.amount = amount
|
event.amount = amount
|
||||||
event.messageId = messageId
|
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EVENT_CONTRIBUTION_CREATE = async (
|
export const EVENT_CONTRIBUTION_CREATE = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
contributionId: number,
|
contribution: DbContribution,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.CONTRIBUTION_CREATE,
|
EventProtocolType.CONTRIBUTION_CREATE,
|
||||||
userId,
|
user,
|
||||||
|
user,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
contribution,
|
||||||
null,
|
null,
|
||||||
contributionId,
|
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_CONTRIBUTION_DELETE = async (
|
export const EVENT_CONTRIBUTION_DELETE = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
contributionId: number,
|
contribution: DbContribution,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.CONTRIBUTION_DELETE,
|
EventProtocolType.CONTRIBUTION_DELETE,
|
||||||
userId,
|
user,
|
||||||
|
user,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
contribution,
|
||||||
null,
|
null,
|
||||||
contributionId,
|
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_CONTRIBUTION_UPDATE = async (
|
export const EVENT_CONTRIBUTION_UPDATE = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
contributionId: number,
|
contribution: DbContribution,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.CONTRIBUTION_UPDATE,
|
EventProtocolType.CONTRIBUTION_UPDATE,
|
||||||
userId,
|
user,
|
||||||
|
user,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
contribution,
|
||||||
null,
|
null,
|
||||||
contributionId,
|
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_ADMIN_CONTRIBUTION_CREATE = async (
|
export const EVENT_ADMIN_CONTRIBUTION_CREATE = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
contributionId: number,
|
moderator: DbUser,
|
||||||
|
contribution: DbContribution,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
|
EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
|
||||||
userId,
|
user,
|
||||||
|
moderator,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
contribution,
|
||||||
null,
|
null,
|
||||||
contributionId,
|
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_ADMIN_CONTRIBUTION_UPDATE = async (
|
export const EVENT_ADMIN_CONTRIBUTION_UPDATE = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
contributionId: number,
|
moderator: DbUser,
|
||||||
|
contribution: DbContribution,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
|
EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
|
||||||
userId,
|
user,
|
||||||
|
moderator,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
contribution,
|
||||||
null,
|
null,
|
||||||
contributionId,
|
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_ADMIN_CONTRIBUTION_DELETE = async (
|
export const EVENT_ADMIN_CONTRIBUTION_DELETE = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
contributionId: number,
|
moderator: DbUser,
|
||||||
|
contribution: DbContribution,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
|
EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
|
||||||
userId,
|
user,
|
||||||
|
moderator,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
contribution,
|
||||||
null,
|
null,
|
||||||
contributionId,
|
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_CONTRIBUTION_CONFIRM = async (
|
export const EVENT_CONTRIBUTION_CONFIRM = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
contributionId: number,
|
moderator: DbUser,
|
||||||
|
contribution: DbContribution,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.CONTRIBUTION_CONFIRM,
|
EventProtocolType.CONTRIBUTION_CONFIRM,
|
||||||
userId,
|
user,
|
||||||
|
moderator,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
contribution,
|
||||||
null,
|
null,
|
||||||
contributionId,
|
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_ADMIN_CONTRIBUTION_DENY = async (
|
export const EVENT_ADMIN_CONTRIBUTION_DENY = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
xUserId: number,
|
moderator: DbUser,
|
||||||
contributionId: number,
|
contribution: DbContribution,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.ADMIN_CONTRIBUTION_DENY,
|
EventProtocolType.ADMIN_CONTRIBUTION_DENY,
|
||||||
userId,
|
user,
|
||||||
xUserId,
|
moderator,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
contributionId,
|
contribution,
|
||||||
|
null,
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_TRANSACTION_SEND = async (
|
export const EVENT_TRANSACTION_SEND = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
xUserId: number,
|
involvedUser: DbUser,
|
||||||
transactionId: number,
|
transaction: DbTransaction,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.TRANSACTION_SEND,
|
EventProtocolType.TRANSACTION_SEND,
|
||||||
userId,
|
user,
|
||||||
xUserId,
|
user,
|
||||||
|
involvedUser,
|
||||||
|
transaction,
|
||||||
null,
|
null,
|
||||||
transactionId,
|
|
||||||
null,
|
null,
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_TRANSACTION_RECEIVE = async (
|
export const EVENT_TRANSACTION_RECEIVE = async (
|
||||||
userId: number,
|
user: DbUser,
|
||||||
xUserId: number,
|
involvedUser: DbUser,
|
||||||
transactionId: number,
|
transaction: DbTransaction,
|
||||||
amount: Decimal,
|
amount: Decimal,
|
||||||
): Promise<DbEvent> =>
|
): Promise<DbEvent> =>
|
||||||
Event(
|
Event(
|
||||||
EventProtocolType.TRANSACTION_RECEIVE,
|
EventProtocolType.TRANSACTION_RECEIVE,
|
||||||
userId,
|
user,
|
||||||
xUserId,
|
involvedUser,
|
||||||
|
involvedUser,
|
||||||
|
transaction,
|
||||||
null,
|
null,
|
||||||
transactionId,
|
|
||||||
null,
|
null,
|
||||||
amount,
|
amount,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
export const EVENT_LOGIN = async (userId: number): Promise<DbEvent> =>
|
export const EVENT_LOGIN = async (user: DbUser): Promise<DbEvent> =>
|
||||||
Event(EventProtocolType.LOGIN, userId, null, null, null, null, null, null).save()
|
Event(EventProtocolType.LOGIN, user, user).save()
|
||||||
|
|
||||||
export const EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = async (
|
export const EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
|
||||||
userId: number,
|
Event(EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, user, { id: 0 } as DbUser).save()
|
||||||
): Promise<DbEvent> => Event(EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, userId).save()
|
|
||||||
|
|
||||||
export const EVENT_SEND_CONFIRMATION_EMAIL = async (userId: number): Promise<DbEvent> =>
|
export const EVENT_SEND_CONFIRMATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
|
||||||
Event(EventProtocolType.SEND_CONFIRMATION_EMAIL, userId).save()
|
Event(EventProtocolType.SEND_CONFIRMATION_EMAIL, user, user).save()
|
||||||
|
|
||||||
export const EVENT_ADMIN_SEND_CONFIRMATION_EMAIL = async (userId: number): Promise<DbEvent> =>
|
export const EVENT_ADMIN_SEND_CONFIRMATION_EMAIL = async (
|
||||||
Event(EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL, userId).save()
|
user: DbUser,
|
||||||
|
moderator: DbUser,
|
||||||
|
): Promise<DbEvent> =>
|
||||||
|
Event(EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL, user, moderator).save()
|
||||||
|
|
||||||
/* export const EVENT_REDEEM_REGISTER = async (
|
export const EVENT_REGISTER = async (user: DbUser): Promise<DbEvent> =>
|
||||||
userId: number,
|
Event(EventProtocolType.REGISTER, user, user).save()
|
||||||
transactionId: number | null = null,
|
|
||||||
contributionId: number | null = null,
|
|
||||||
): Promise<Event> =>
|
|
||||||
Event(
|
|
||||||
EventProtocolType.REDEEM_REGISTER,
|
|
||||||
userId,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
transactionId,
|
|
||||||
contributionId,
|
|
||||||
).save()
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const EVENT_REGISTER = async (userId: number): Promise<DbEvent> =>
|
export const EVENT_ACTIVATE_ACCOUNT = async (user: DbUser): Promise<DbEvent> =>
|
||||||
Event(EventProtocolType.REGISTER, userId).save()
|
Event(EventProtocolType.ACTIVATE_ACCOUNT, user, user).save()
|
||||||
|
|
||||||
export const EVENT_ACTIVATE_ACCOUNT = async (userId: number): Promise<DbEvent> =>
|
|
||||||
Event(EventProtocolType.ACTIVATE_ACCOUNT, userId).save()
|
|
||||||
|
|||||||
@ -21,9 +21,13 @@ export async function requestGetPublicKey(dbCom: DbCommunity): Promise<string |
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
const variables = {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest(query)
|
const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest(
|
||||||
|
query,
|
||||||
|
variables,
|
||||||
|
)
|
||||||
logger.debug(`Response-Data:`, data, errors, extensions, headers, status)
|
logger.debug(`Response-Data:`, data, errors, extensions, headers, status)
|
||||||
if (data) {
|
if (data) {
|
||||||
logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey)
|
logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey)
|
||||||
|
|||||||
@ -21,9 +21,13 @@ export async function requestGetPublicKey(dbCom: DbCommunity): Promise<string |
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
const variables = {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest(query)
|
const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest(
|
||||||
|
query,
|
||||||
|
variables,
|
||||||
|
)
|
||||||
logger.debug(`Response-Data:`, data, errors, extensions, headers, status)
|
logger.debug(`Response-Data:`, data, errors, extensions, headers, status)
|
||||||
if (data) {
|
if (data) {
|
||||||
logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey)
|
logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey)
|
||||||
|
|||||||
@ -1,8 +1,14 @@
|
|||||||
import { GraphQLClient } from 'graphql-request'
|
import { GraphQLClient } from 'graphql-request'
|
||||||
import { PatchedRequestInit } from 'graphql-request/dist/types'
|
import { PatchedRequestInit } from 'graphql-request/dist/types'
|
||||||
|
|
||||||
|
type ClientInstance = {
|
||||||
|
url: string
|
||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
client: GraphQLGetClient
|
||||||
|
}
|
||||||
|
|
||||||
export class GraphQLGetClient extends GraphQLClient {
|
export class GraphQLGetClient extends GraphQLClient {
|
||||||
private static instance: GraphQLGetClient
|
private static instanceArray: ClientInstance[] = []
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Singleton's constructor should always be private to prevent direct
|
* The Singleton's constructor should always be private to prevent direct
|
||||||
@ -20,16 +26,18 @@ export class GraphQLGetClient extends GraphQLClient {
|
|||||||
* just one instance of each subclass around.
|
* just one instance of each subclass around.
|
||||||
*/
|
*/
|
||||||
public static getInstance(url: string): GraphQLGetClient {
|
public static getInstance(url: string): GraphQLGetClient {
|
||||||
if (!GraphQLGetClient.instance) {
|
const instance = GraphQLGetClient.instanceArray.find((instance) => instance.url === url)
|
||||||
GraphQLGetClient.instance = new GraphQLGetClient(url, {
|
if (instance) {
|
||||||
method: 'GET',
|
return instance.client
|
||||||
jsonSerializer: {
|
|
||||||
parse: JSON.parse,
|
|
||||||
stringify: JSON.stringify,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
const client = new GraphQLGetClient(url, {
|
||||||
return GraphQLGetClient.instance
|
method: 'GET',
|
||||||
|
jsonSerializer: {
|
||||||
|
parse: JSON.parse,
|
||||||
|
stringify: JSON.stringify,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
GraphQLGetClient.instanceArray.push({ url, client } as ClientInstance)
|
||||||
|
return client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,17 +42,18 @@ export async function validateCommunities(): Promise<void> {
|
|||||||
pubKey,
|
pubKey,
|
||||||
`${dbCom.endPoint}/${dbCom.apiVersion}`,
|
`${dbCom.endPoint}/${dbCom.apiVersion}`,
|
||||||
)
|
)
|
||||||
if (pubKey && pubKey === dbCom.publicKey.toString('hex')) {
|
if (pubKey && pubKey === dbCom.publicKey.toString()) {
|
||||||
logger.info(`Federation: matching publicKey: ${pubKey}`)
|
logger.info(`Federation: matching publicKey: ${pubKey}`)
|
||||||
await DbCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() })
|
await DbCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() })
|
||||||
logger.debug(`Federation: updated dbCom: ${JSON.stringify(dbCom)}`)
|
logger.debug(`Federation: updated dbCom: ${JSON.stringify(dbCom)}`)
|
||||||
|
} else {
|
||||||
|
logger.warn(
|
||||||
|
`Federation: received not matching publicKey -> received: ${
|
||||||
|
pubKey || 'null'
|
||||||
|
}, expected: ${dbCom.publicKey.toString()} `,
|
||||||
|
)
|
||||||
|
// DbCommunity.delete({ id: dbCom.id })
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
else {
|
|
||||||
logger.warn(`Federation: received unknown publicKey -> delete dbCom with id=${dbCom.id} `)
|
|
||||||
DbCommunity.delete({ id: dbCom.id })
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!isLogError(err)) {
|
if (!isLogError(err)) {
|
||||||
logger.error(`Error:`, err)
|
logger.error(`Error:`, err)
|
||||||
|
|||||||
@ -46,7 +46,7 @@ import { userFactory } from '@/seeds/factory/user'
|
|||||||
import { creationFactory } from '@/seeds/factory/creation'
|
import { creationFactory } from '@/seeds/factory/creation'
|
||||||
import { creations } from '@/seeds/creation/index'
|
import { creations } from '@/seeds/creation/index'
|
||||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||||
import { EventProtocol } from '@entity/EventProtocol'
|
import { Event as DbEvent } from '@entity/Event'
|
||||||
import { Contribution } from '@entity/Contribution'
|
import { Contribution } from '@entity/Contribution'
|
||||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||||
import { User } from '@entity/User'
|
import { User } from '@entity/User'
|
||||||
@ -279,12 +279,13 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the CONTRIBUTION_CREATE event in the database', async () => {
|
it('stores the CONTRIBUTION_CREATE event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.CONTRIBUTION_CREATE,
|
type: EventProtocolType.CONTRIBUTION_CREATE,
|
||||||
|
affectedUserId: bibi.id,
|
||||||
|
actingUserId: bibi.id,
|
||||||
|
involvedContributionId: pendingContribution.data.createContribution.id,
|
||||||
amount: expect.decimalEqual(100),
|
amount: expect.decimalEqual(100),
|
||||||
contributionId: pendingContribution.data.createContribution.id,
|
|
||||||
userId: bibi.id,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -583,12 +584,13 @@ describe('ContributionResolver', () => {
|
|||||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
})
|
})
|
||||||
|
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.CONTRIBUTION_UPDATE,
|
type: EventProtocolType.CONTRIBUTION_UPDATE,
|
||||||
|
affectedUserId: bibi.id,
|
||||||
|
actingUserId: bibi.id,
|
||||||
|
involvedContributionId: pendingContribution.data.createContribution.id,
|
||||||
amount: expect.decimalEqual(10),
|
amount: expect.decimalEqual(10),
|
||||||
contributionId: pendingContribution.data.createContribution.id,
|
|
||||||
userId: bibi.id,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -813,12 +815,12 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the ADMIN_CONTRIBUTION_DENY event in the database', async () => {
|
it('stores the ADMIN_CONTRIBUTION_DENY event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.ADMIN_CONTRIBUTION_DENY,
|
type: EventProtocolType.ADMIN_CONTRIBUTION_DENY,
|
||||||
userId: bibi.id,
|
affectedUserId: bibi.id,
|
||||||
xUserId: admin.id,
|
actingUserId: admin.id,
|
||||||
contributionId: contributionToDeny.data.createContribution.id,
|
involvedContributionId: contributionToDeny.data.createContribution.id,
|
||||||
amount: expect.decimalEqual(100),
|
amount: expect.decimalEqual(100),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -941,12 +943,13 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the CONTRIBUTION_DELETE event in the database', async () => {
|
it('stores the CONTRIBUTION_DELETE event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.CONTRIBUTION_DELETE,
|
type: EventProtocolType.CONTRIBUTION_DELETE,
|
||||||
contributionId: contributionToDelete.data.createContribution.id,
|
affectedUserId: bibi.id,
|
||||||
|
actingUserId: bibi.id,
|
||||||
|
involvedContributionId: contributionToDelete.data.createContribution.id,
|
||||||
amount: expect.decimalEqual(100),
|
amount: expect.decimalEqual(100),
|
||||||
userId: bibi.id,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -2028,10 +2031,11 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the ADMIN_CONTRIBUTION_CREATE event in the database', async () => {
|
it('stores the ADMIN_CONTRIBUTION_CREATE event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
|
type: EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
|
||||||
userId: admin.id,
|
affectedUserId: bibi.id,
|
||||||
|
actingUserId: admin.id,
|
||||||
amount: expect.decimalEqual(200),
|
amount: expect.decimalEqual(200),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -2224,7 +2228,7 @@ describe('ContributionResolver', () => {
|
|||||||
mutate({
|
mutate({
|
||||||
mutation: adminUpdateContribution,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation?.id,
|
||||||
amount: new Decimal(300),
|
amount: new Decimal(300),
|
||||||
memo: 'Danke Peter!',
|
memo: 'Danke Peter!',
|
||||||
creationDate: creation
|
creationDate: creation
|
||||||
@ -2246,10 +2250,11 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
|
it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
|
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
|
||||||
userId: admin.id,
|
affectedUserId: creation?.userId,
|
||||||
|
actingUserId: admin.id,
|
||||||
amount: 300,
|
amount: 300,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -2263,7 +2268,7 @@ describe('ContributionResolver', () => {
|
|||||||
mutate({
|
mutate({
|
||||||
mutation: adminUpdateContribution,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation?.id,
|
||||||
amount: new Decimal(200),
|
amount: new Decimal(200),
|
||||||
memo: 'Das war leider zu Viel!',
|
memo: 'Das war leider zu Viel!',
|
||||||
creationDate: creation
|
creationDate: creation
|
||||||
@ -2285,10 +2290,11 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
|
it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
|
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
|
||||||
userId: admin.id,
|
affectedUserId: creation?.userId,
|
||||||
|
actingUserId: admin.id,
|
||||||
amount: expect.decimalEqual(200),
|
amount: expect.decimalEqual(200),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -2359,7 +2365,7 @@ describe('ContributionResolver', () => {
|
|||||||
mutate({
|
mutate({
|
||||||
mutation: adminDeleteContribution,
|
mutation: adminDeleteContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation?.id,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
@ -2370,10 +2376,12 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the ADMIN_CONTRIBUTION_DELETE event in the database', async () => {
|
it('stores the ADMIN_CONTRIBUTION_DELETE event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
|
type: EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
|
||||||
userId: admin.id,
|
affectedUserId: creation?.userId,
|
||||||
|
actingUserId: admin.id,
|
||||||
|
involvedContributionId: creation?.id,
|
||||||
amount: expect.decimalEqual(200),
|
amount: expect.decimalEqual(200),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -2526,7 +2534,7 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the CONTRIBUTION_CONFIRM event in the database', async () => {
|
it('stores the CONTRIBUTION_CONFIRM event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.CONTRIBUTION_CONFIRM,
|
type: EventProtocolType.CONTRIBUTION_CONFIRM,
|
||||||
}),
|
}),
|
||||||
@ -2558,7 +2566,7 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => {
|
it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.SEND_CONFIRMATION_EMAIL,
|
type: EventProtocolType.SEND_CONFIRMATION_EMAIL,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -91,7 +91,7 @@ export class ContributionResolver {
|
|||||||
logger.trace('contribution to save', contribution)
|
logger.trace('contribution to save', contribution)
|
||||||
await DbContribution.save(contribution)
|
await DbContribution.save(contribution)
|
||||||
|
|
||||||
await EVENT_CONTRIBUTION_CREATE(user.id, contribution.id, amount)
|
await EVENT_CONTRIBUTION_CREATE(user, contribution, amount)
|
||||||
|
|
||||||
return new UnconfirmedContribution(contribution, user, creations)
|
return new UnconfirmedContribution(contribution, user, creations)
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ export class ContributionResolver {
|
|||||||
contribution.deletedAt = new Date()
|
contribution.deletedAt = new Date()
|
||||||
await contribution.save()
|
await contribution.save()
|
||||||
|
|
||||||
await EVENT_CONTRIBUTION_DELETE(user.id, contribution.id, contribution.amount)
|
await EVENT_CONTRIBUTION_DELETE(user, contribution, contribution.amount)
|
||||||
|
|
||||||
const res = await contribution.softRemove()
|
const res = await contribution.softRemove()
|
||||||
return !!res
|
return !!res
|
||||||
@ -249,7 +249,7 @@ export class ContributionResolver {
|
|||||||
contributionToUpdate.updatedAt = new Date()
|
contributionToUpdate.updatedAt = new Date()
|
||||||
await DbContribution.save(contributionToUpdate)
|
await DbContribution.save(contributionToUpdate)
|
||||||
|
|
||||||
await EVENT_CONTRIBUTION_UPDATE(user.id, contributionId, amount)
|
await EVENT_CONTRIBUTION_UPDATE(user, contributionToUpdate, amount)
|
||||||
|
|
||||||
return new UnconfirmedContribution(contributionToUpdate, user, creations)
|
return new UnconfirmedContribution(contributionToUpdate, user, creations)
|
||||||
}
|
}
|
||||||
@ -306,7 +306,7 @@ export class ContributionResolver {
|
|||||||
|
|
||||||
await DbContribution.save(contribution)
|
await DbContribution.save(contribution)
|
||||||
|
|
||||||
await EVENT_ADMIN_CONTRIBUTION_CREATE(moderator.id, contribution.id, amount)
|
await EVENT_ADMIN_CONTRIBUTION_CREATE(emailContact.user, moderator, contribution, amount)
|
||||||
|
|
||||||
return getUserCreation(emailContact.userId, clientTimezoneOffset)
|
return getUserCreation(emailContact.userId, clientTimezoneOffset)
|
||||||
}
|
}
|
||||||
@ -322,7 +322,7 @@ export class ContributionResolver {
|
|||||||
const moderator = getUser(context)
|
const moderator = getUser(context)
|
||||||
|
|
||||||
const contributionToUpdate = await DbContribution.findOne({
|
const contributionToUpdate = await DbContribution.findOne({
|
||||||
where: { id, confirmedAt: IsNull(), deniedAt: IsNull() },
|
where: { id, confirmedAt: IsNull(), deniedAt: IsNull(), relations: ['user'] },
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!contributionToUpdate) {
|
if (!contributionToUpdate) {
|
||||||
@ -359,8 +359,9 @@ export class ContributionResolver {
|
|||||||
result.date = contributionToUpdate.contributionDate
|
result.date = contributionToUpdate.contributionDate
|
||||||
|
|
||||||
await EVENT_ADMIN_CONTRIBUTION_UPDATE(
|
await EVENT_ADMIN_CONTRIBUTION_UPDATE(
|
||||||
contributionToUpdate.userId,
|
contributionToUpdate.user,
|
||||||
contributionToUpdate.id,
|
moderator,
|
||||||
|
contributionToUpdate,
|
||||||
amount,
|
amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -420,7 +421,12 @@ export class ContributionResolver {
|
|||||||
await contribution.save()
|
await contribution.save()
|
||||||
const res = await contribution.softRemove()
|
const res = await contribution.softRemove()
|
||||||
|
|
||||||
await EVENT_ADMIN_CONTRIBUTION_DELETE(contribution.userId, contribution.id, contribution.amount)
|
await EVENT_ADMIN_CONTRIBUTION_DELETE(
|
||||||
|
{ id: contribution.userId } as DbUser,
|
||||||
|
moderator,
|
||||||
|
contribution,
|
||||||
|
contribution.amount,
|
||||||
|
)
|
||||||
|
|
||||||
void sendContributionDeletedEmail({
|
void sendContributionDeletedEmail({
|
||||||
firstName: user.firstName,
|
firstName: user.firstName,
|
||||||
@ -533,7 +539,7 @@ export class ContributionResolver {
|
|||||||
await queryRunner.release()
|
await queryRunner.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
await EVENT_CONTRIBUTION_CONFIRM(user.id, contribution.id, contribution.amount)
|
await EVENT_CONTRIBUTION_CONFIRM(user, moderatorUser, contribution, contribution.amount)
|
||||||
} finally {
|
} finally {
|
||||||
releaseLock()
|
releaseLock()
|
||||||
}
|
}
|
||||||
@ -620,9 +626,9 @@ export class ContributionResolver {
|
|||||||
const res = await contributionToUpdate.save()
|
const res = await contributionToUpdate.save()
|
||||||
|
|
||||||
await EVENT_ADMIN_CONTRIBUTION_DENY(
|
await EVENT_ADMIN_CONTRIBUTION_DENY(
|
||||||
contributionToUpdate.userId,
|
user,
|
||||||
moderator.id,
|
moderator,
|
||||||
contributionToUpdate.id,
|
contributionToUpdate,
|
||||||
contributionToUpdate.amount,
|
contributionToUpdate.amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -22,10 +22,12 @@ import {
|
|||||||
createContribution,
|
createContribution,
|
||||||
updateContribution,
|
updateContribution,
|
||||||
createTransactionLink,
|
createTransactionLink,
|
||||||
|
confirmContribution,
|
||||||
} from '@/seeds/graphql/mutations'
|
} from '@/seeds/graphql/mutations'
|
||||||
import { listTransactionLinksAdmin } from '@/seeds/graphql/queries'
|
import { listTransactionLinksAdmin } from '@/seeds/graphql/queries'
|
||||||
import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
|
import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
|
||||||
import { User } from '@entity/User'
|
import { User } from '@entity/User'
|
||||||
|
import { Transaction } from '@entity/Transaction'
|
||||||
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
|
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
|
||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
@ -142,6 +144,8 @@ describe('TransactionLinkResolver', () => {
|
|||||||
resetToken()
|
resetToken()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let contributionId: number
|
||||||
|
|
||||||
describe('unauthenticated', () => {
|
describe('unauthenticated', () => {
|
||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
@ -311,7 +315,6 @@ describe('TransactionLinkResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: have this test separated into a transactionLink and a contributionLink part
|
|
||||||
describe('redeem daily Contribution Link', () => {
|
describe('redeem daily Contribution Link', () => {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
let contributionLink: DbContributionLink | undefined
|
let contributionLink: DbContributionLink | undefined
|
||||||
@ -337,6 +340,10 @@ describe('TransactionLinkResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await resetEntity(Transaction)
|
||||||
|
})
|
||||||
|
|
||||||
it('has a daily contribution link in the database', async () => {
|
it('has a daily contribution link in the database', async () => {
|
||||||
const cls = await DbContributionLink.find()
|
const cls = await DbContributionLink.find()
|
||||||
expect(cls).toHaveLength(1)
|
expect(cls).toHaveLength(1)
|
||||||
@ -378,6 +385,7 @@ describe('TransactionLinkResolver', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
contribution = result.data.createContribution
|
contribution = result.data.createContribution
|
||||||
|
contributionId = result.data.createContribution.id
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not allow the user to redeem the contribution link', async () => {
|
it('does not allow the user to redeem the contribution link', async () => {
|
||||||
@ -513,6 +521,92 @@ describe('TransactionLinkResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('transaction link', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('link does not exits', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws and logs the error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: 'not-valid',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
errors: [new GraphQLError('Transaction link not found')],
|
||||||
|
})
|
||||||
|
expect(logger.error).toBeCalledWith('Transaction link not found', 'not-valid')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('link exists', () => {
|
||||||
|
let myCode: string
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
await mutate({
|
||||||
|
mutation: confirmContribution,
|
||||||
|
variables: { id: contributionId },
|
||||||
|
})
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
const {
|
||||||
|
data: {
|
||||||
|
createTransactionLink: { code },
|
||||||
|
},
|
||||||
|
} = await mutate({
|
||||||
|
mutation: createTransactionLink,
|
||||||
|
variables: {
|
||||||
|
amount: 200,
|
||||||
|
memo: 'This is a transaction link from bibi',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
myCode = code
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('own link', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws and logs an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: myCode,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
errors: [new GraphQLError('Cannot redeem own transaction link')],
|
||||||
|
})
|
||||||
|
expect(logger.error).toBeCalledWith(
|
||||||
|
'Cannot redeem own transaction link',
|
||||||
|
expect.any(Number),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -285,12 +285,20 @@ export class TransactionLinkResolver {
|
|||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const transactionLink = await DbTransactionLink.findOneOrFail({ code })
|
const transactionLink = await DbTransactionLink.findOne({ code })
|
||||||
const linkedUser = await DbUser.findOneOrFail(
|
if (!transactionLink) {
|
||||||
|
throw new LogError('Transaction link not found', code)
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkedUser = await DbUser.findOne(
|
||||||
{ id: transactionLink.userId },
|
{ id: transactionLink.userId },
|
||||||
{ relations: ['emailContact'] },
|
{ relations: ['emailContact'] },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!linkedUser) {
|
||||||
|
throw new LogError('Linked user not found for given link', transactionLink.userId)
|
||||||
|
}
|
||||||
|
|
||||||
if (user.id === linkedUser.id) {
|
if (user.id === linkedUser.id) {
|
||||||
throw new LogError('Cannot redeem own transaction link', user.id)
|
throw new LogError('Cannot redeem own transaction link', user.id)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import { bobBaumeister } from '@/seeds/users/bob-baumeister'
|
|||||||
import { garrickOllivander } from '@/seeds/users/garrick-ollivander'
|
import { garrickOllivander } from '@/seeds/users/garrick-ollivander'
|
||||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||||
import { stephenHawking } from '@/seeds/users/stephen-hawking'
|
import { stephenHawking } from '@/seeds/users/stephen-hawking'
|
||||||
import { EventProtocol } from '@entity/EventProtocol'
|
import { Event as DbEvent } from '@entity/Event'
|
||||||
import { Transaction } from '@entity/Transaction'
|
import { Transaction } from '@entity/Transaction'
|
||||||
import { User } from '@entity/User'
|
import { User } from '@entity/User'
|
||||||
import { cleanDB, testEnvironment } from '@test/helpers'
|
import { cleanDB, testEnvironment } from '@test/helpers'
|
||||||
@ -341,12 +341,13 @@ describe('send coins', () => {
|
|||||||
memo: 'unrepeatable memo',
|
memo: 'unrepeatable memo',
|
||||||
})
|
})
|
||||||
|
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.TRANSACTION_SEND,
|
type: EventProtocolType.TRANSACTION_SEND,
|
||||||
userId: user[1].id,
|
affectedUserId: user[1].id,
|
||||||
transactionId: transaction[0].id,
|
actingUserId: user[1].id,
|
||||||
xUserId: user[0].id,
|
involvedUserId: user[0].id,
|
||||||
|
involvedTransactionId: transaction[0].id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -358,12 +359,13 @@ describe('send coins', () => {
|
|||||||
memo: 'unrepeatable memo',
|
memo: 'unrepeatable memo',
|
||||||
})
|
})
|
||||||
|
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.TRANSACTION_RECEIVE,
|
type: EventProtocolType.TRANSACTION_RECEIVE,
|
||||||
userId: user[0].id,
|
affectedUserId: user[0].id,
|
||||||
transactionId: transaction[0].id,
|
actingUserId: user[1].id,
|
||||||
xUserId: user[1].id,
|
involvedUserId: user[1].id,
|
||||||
|
involvedTransactionId: transaction[0].id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -138,17 +138,12 @@ export const executeTransaction = async (
|
|||||||
await queryRunner.commitTransaction()
|
await queryRunner.commitTransaction()
|
||||||
logger.info(`commit Transaction successful...`)
|
logger.info(`commit Transaction successful...`)
|
||||||
|
|
||||||
await EVENT_TRANSACTION_SEND(
|
await EVENT_TRANSACTION_SEND(sender, recipient, transactionSend, transactionSend.amount)
|
||||||
transactionSend.userId,
|
|
||||||
transactionSend.linkedUserId,
|
|
||||||
transactionSend.id,
|
|
||||||
transactionSend.amount.mul(-1),
|
|
||||||
)
|
|
||||||
|
|
||||||
await EVENT_TRANSACTION_RECEIVE(
|
await EVENT_TRANSACTION_RECEIVE(
|
||||||
transactionReceive.userId,
|
recipient,
|
||||||
transactionReceive.linkedUserId,
|
sender,
|
||||||
transactionReceive.id,
|
transactionReceive,
|
||||||
transactionReceive.amount,
|
transactionReceive.amount,
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -40,7 +40,7 @@ import { transactionLinkFactory } from '@/seeds/factory/transactionLink'
|
|||||||
import { ContributionLink } from '@model/ContributionLink'
|
import { ContributionLink } from '@model/ContributionLink'
|
||||||
import { TransactionLink } from '@entity/TransactionLink'
|
import { TransactionLink } from '@entity/TransactionLink'
|
||||||
import { EventProtocolType } from '@/event/EventProtocolType'
|
import { EventProtocolType } from '@/event/EventProtocolType'
|
||||||
import { EventProtocol } from '@entity/EventProtocol'
|
import { Event as DbEvent } from '@entity/Event'
|
||||||
import { validate as validateUUID, version as versionUUID } from 'uuid'
|
import { validate as validateUUID, version as versionUUID } from 'uuid'
|
||||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||||
import { UserContact } from '@entity/UserContact'
|
import { UserContact } from '@entity/UserContact'
|
||||||
@ -187,10 +187,11 @@ describe('UserResolver', () => {
|
|||||||
{ email: 'peter@lustig.de' },
|
{ email: 'peter@lustig.de' },
|
||||||
{ relations: ['user'] },
|
{ relations: ['user'] },
|
||||||
)
|
)
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.REGISTER,
|
type: EventProtocolType.REGISTER,
|
||||||
userId: userConatct.user.id,
|
affectedUserId: userConatct.user.id,
|
||||||
|
actingUserId: userConatct.user.id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -216,10 +217,11 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => {
|
it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.SEND_CONFIRMATION_EMAIL,
|
type: EventProtocolType.SEND_CONFIRMATION_EMAIL,
|
||||||
userId: user[0].id,
|
affectedUserId: user[0].id,
|
||||||
|
actingUserId: user[0].id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -261,10 +263,11 @@ describe('UserResolver', () => {
|
|||||||
{ email: 'peter@lustig.de' },
|
{ email: 'peter@lustig.de' },
|
||||||
{ relations: ['user'] },
|
{ relations: ['user'] },
|
||||||
)
|
)
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL,
|
type: EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL,
|
||||||
userId: userConatct.user.id,
|
affectedUserId: userConatct.user.id,
|
||||||
|
actingUserId: 0,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -361,20 +364,22 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the ACTIVATE_ACCOUNT event in the database', async () => {
|
it('stores the ACTIVATE_ACCOUNT event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.ACTIVATE_ACCOUNT,
|
type: EventProtocolType.ACTIVATE_ACCOUNT,
|
||||||
userId: user[0].id,
|
affectedUserId: user[0].id,
|
||||||
|
actingUserId: user[0].id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('stores the REDEEM_REGISTER event in the database', async () => {
|
it('stores the REDEEM_REGISTER event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.REDEEM_REGISTER,
|
type: EventProtocolType.REDEEM_REGISTER,
|
||||||
userId: result.data.createUser.id,
|
affectedUserId: result.data.createUser.id,
|
||||||
contributionId: link.id,
|
actingUserId: result.data.createUser.id,
|
||||||
|
involvedContributionId: link.id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -454,10 +459,12 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the REDEEM_REGISTER event in the database', async () => {
|
it('stores the REDEEM_REGISTER event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.REDEEM_REGISTER,
|
type: EventProtocolType.REDEEM_REGISTER,
|
||||||
userId: newUser.data.createUser.id,
|
affectedUserId: newUser.data.createUser.id,
|
||||||
|
actingUserId: newUser.data.createUser.id,
|
||||||
|
involvedTransactionId: transactionLink.id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -685,10 +692,11 @@ describe('UserResolver', () => {
|
|||||||
{ email: 'bibi@bloxberg.de' },
|
{ email: 'bibi@bloxberg.de' },
|
||||||
{ relations: ['user'] },
|
{ relations: ['user'] },
|
||||||
)
|
)
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.LOGIN,
|
type: EventProtocolType.LOGIN,
|
||||||
userId: userConatct.user.id,
|
affectedUserId: userConatct.user.id,
|
||||||
|
actingUserId: userConatct.user.id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -933,10 +941,11 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('stores the LOGIN event in the database', async () => {
|
it('stores the LOGIN event in the database', async () => {
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.LOGIN,
|
type: EventProtocolType.LOGIN,
|
||||||
userId: user[0].id,
|
affectedUserId: user[0].id,
|
||||||
|
actingUserId: user[0].id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -1852,10 +1861,11 @@ describe('UserResolver', () => {
|
|||||||
{ email: 'bibi@bloxberg.de' },
|
{ email: 'bibi@bloxberg.de' },
|
||||||
{ relations: ['user'] },
|
{ relations: ['user'] },
|
||||||
)
|
)
|
||||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
type: EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL,
|
type: EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL,
|
||||||
userId: userConatct.user.id,
|
affectedUserId: userConatct.user.id,
|
||||||
|
actingUserId: admin.id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -20,7 +20,9 @@ import { getConnection, getCustomRepository, IsNull, Not } from '@dbTools/typeor
|
|||||||
import { User as DbUser } from '@entity/User'
|
import { User as DbUser } from '@entity/User'
|
||||||
import { UserContact as DbUserContact } from '@entity/UserContact'
|
import { UserContact as DbUserContact } from '@entity/UserContact'
|
||||||
import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink'
|
import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink'
|
||||||
|
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||||
import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
|
import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
|
||||||
|
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||||
import { UserRepository } from '@repository/User'
|
import { UserRepository } from '@repository/User'
|
||||||
|
|
||||||
import { User } from '@model/User'
|
import { User } from '@model/User'
|
||||||
@ -182,7 +184,7 @@ export class UserResolver {
|
|||||||
value: encode(dbUser.gradidoID),
|
value: encode(dbUser.gradidoID),
|
||||||
})
|
})
|
||||||
|
|
||||||
await EVENT_LOGIN(user.id)
|
await EVENT_LOGIN(dbUser)
|
||||||
logger.info(`successful Login: ${JSON.stringify(user, null, 2)}`)
|
logger.info(`successful Login: ${JSON.stringify(user, null, 2)}`)
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
@ -252,7 +254,7 @@ export class UserResolver {
|
|||||||
language: foundUser.language, // use language of the emails owner for sending
|
language: foundUser.language, // use language of the emails owner for sending
|
||||||
})
|
})
|
||||||
|
|
||||||
await EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL(foundUser.id)
|
await EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL(foundUser)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
`sendAccountMultiRegistrationEmail by ${firstName} ${lastName} to ${foundUser.firstName} ${foundUser.lastName} <${email}>`,
|
`sendAccountMultiRegistrationEmail by ${firstName} ${lastName} to ${foundUser.firstName} ${foundUser.lastName} <${email}>`,
|
||||||
@ -270,7 +272,11 @@ export class UserResolver {
|
|||||||
|
|
||||||
const gradidoID = await newGradidoID()
|
const gradidoID = await newGradidoID()
|
||||||
|
|
||||||
const eventRegisterRedeem = Event(EventProtocolType.REDEEM_REGISTER, 0)
|
const eventRegisterRedeem = Event(
|
||||||
|
EventProtocolType.REDEEM_REGISTER,
|
||||||
|
{ id: 0 } as DbUser,
|
||||||
|
{ id: 0 } as DbUser,
|
||||||
|
)
|
||||||
let dbUser = new DbUser()
|
let dbUser = new DbUser()
|
||||||
dbUser.gradidoID = gradidoID
|
dbUser.gradidoID = gradidoID
|
||||||
dbUser.firstName = firstName
|
dbUser.firstName = firstName
|
||||||
@ -287,14 +293,16 @@ export class UserResolver {
|
|||||||
logger.info('redeemCode found contributionLink', contributionLink)
|
logger.info('redeemCode found contributionLink', contributionLink)
|
||||||
if (contributionLink) {
|
if (contributionLink) {
|
||||||
dbUser.contributionLinkId = contributionLink.id
|
dbUser.contributionLinkId = contributionLink.id
|
||||||
eventRegisterRedeem.contributionId = contributionLink.id
|
// TODO this is so wrong
|
||||||
|
eventRegisterRedeem.involvedContribution = { id: contributionLink.id } as DbContribution
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const transactionLink = await DbTransactionLink.findOne({ code: redeemCode })
|
const transactionLink = await DbTransactionLink.findOne({ code: redeemCode })
|
||||||
logger.info('redeemCode found transactionLink', transactionLink)
|
logger.info('redeemCode found transactionLink', transactionLink)
|
||||||
if (transactionLink) {
|
if (transactionLink) {
|
||||||
dbUser.referrerId = transactionLink.userId
|
dbUser.referrerId = transactionLink.userId
|
||||||
eventRegisterRedeem.transactionId = transactionLink.id
|
// TODO this is so wrong
|
||||||
|
eventRegisterRedeem.involvedTransaction = { id: transactionLink.id } as DbTransaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,7 +341,7 @@ export class UserResolver {
|
|||||||
})
|
})
|
||||||
logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`)
|
logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`)
|
||||||
|
|
||||||
await EVENT_SEND_CONFIRMATION_EMAIL(dbUser.id)
|
await EVENT_SEND_CONFIRMATION_EMAIL(dbUser)
|
||||||
|
|
||||||
if (!emailSent) {
|
if (!emailSent) {
|
||||||
logger.debug(`Account confirmation link: ${activationLink}`)
|
logger.debug(`Account confirmation link: ${activationLink}`)
|
||||||
@ -350,10 +358,11 @@ export class UserResolver {
|
|||||||
logger.info('createUser() successful...')
|
logger.info('createUser() successful...')
|
||||||
|
|
||||||
if (redeemCode) {
|
if (redeemCode) {
|
||||||
eventRegisterRedeem.userId = dbUser.id
|
eventRegisterRedeem.affectedUser = dbUser
|
||||||
|
eventRegisterRedeem.actingUser = dbUser
|
||||||
await eventRegisterRedeem.save()
|
await eventRegisterRedeem.save()
|
||||||
} else {
|
} else {
|
||||||
await EVENT_REGISTER(dbUser.id)
|
await EVENT_REGISTER(dbUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
return new User(dbUser)
|
return new User(dbUser)
|
||||||
@ -469,7 +478,7 @@ export class UserResolver {
|
|||||||
await queryRunner.commitTransaction()
|
await queryRunner.commitTransaction()
|
||||||
logger.info('User and UserContact data written successfully...')
|
logger.info('User and UserContact data written successfully...')
|
||||||
|
|
||||||
await EVENT_ACTIVATE_ACCOUNT(user.id)
|
await EVENT_ACTIVATE_ACCOUNT(user)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await queryRunner.rollbackTransaction()
|
await queryRunner.rollbackTransaction()
|
||||||
throw new LogError('Error on writing User and User Contact data', e)
|
throw new LogError('Error on writing User and User Contact data', e)
|
||||||
@ -779,9 +788,13 @@ export class UserResolver {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO this is an admin function - needs refactor
|
||||||
@Authorized([RIGHTS.SEND_ACTIVATION_EMAIL])
|
@Authorized([RIGHTS.SEND_ACTIVATION_EMAIL])
|
||||||
@Mutation(() => Boolean)
|
@Mutation(() => Boolean)
|
||||||
async sendActivationEmail(@Arg('email') email: string): Promise<boolean> {
|
async sendActivationEmail(
|
||||||
|
@Arg('email') email: string,
|
||||||
|
@Ctx() context: Context,
|
||||||
|
): Promise<boolean> {
|
||||||
email = email.trim().toLowerCase()
|
email = email.trim().toLowerCase()
|
||||||
// const user = await dbUser.findOne({ id: emailContact.userId })
|
// const user = await dbUser.findOne({ id: emailContact.userId })
|
||||||
const user = await findUserByEmail(email)
|
const user = await findUserByEmail(email)
|
||||||
@ -806,7 +819,7 @@ export class UserResolver {
|
|||||||
if (!emailSent) {
|
if (!emailSent) {
|
||||||
logger.info(`Account confirmation link: ${activationLink}`)
|
logger.info(`Account confirmation link: ${activationLink}`)
|
||||||
} else {
|
} else {
|
||||||
await EVENT_ADMIN_SEND_CONFIRMATION_EMAIL(user.id)
|
await EVENT_ADMIN_SEND_CONFIRMATION_EMAIL(user, getUser(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|||||||
@ -191,4 +191,50 @@ describe('semaphore', () => {
|
|||||||
await expect(confirmBibisContribution).resolves.toMatchObject({ errors: undefined })
|
await expect(confirmBibisContribution).resolves.toMatchObject({ errors: undefined })
|
||||||
await expect(confirmBobsContribution).resolves.toMatchObject({ errors: undefined })
|
await expect(confirmBobsContribution).resolves.toMatchObject({ errors: undefined })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('redeem transaction link twice', () => {
|
||||||
|
let myCode: string
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
const {
|
||||||
|
data: { createTransactionLink: bibisLink },
|
||||||
|
} = await mutate({
|
||||||
|
mutation: createTransactionLink,
|
||||||
|
variables: {
|
||||||
|
amount: 20,
|
||||||
|
memo: 'Bibis Link',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
myCode = bibisLink.code
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'bob@baumeister.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not throw, but should', async () => {
|
||||||
|
const redeem1 = mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: myCode,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const redeem2 = mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: myCode,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await expect(redeem1).resolves.toMatchObject({
|
||||||
|
errors: undefined,
|
||||||
|
})
|
||||||
|
await expect(redeem2).resolves.toMatchObject({
|
||||||
|
errors: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -89,6 +89,12 @@ export const createTransactionLink = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const deleteTransactionLink = gql`
|
||||||
|
mutation ($id: Int!) {
|
||||||
|
deleteTransactionLink(id: $id)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
// from admin interface
|
// from admin interface
|
||||||
|
|
||||||
export const adminCreateContribution = gql`
|
export const adminCreateContribution = gql`
|
||||||
|
|||||||
83
database/entity/0061-event_refactoring/Event.ts
Normal file
83
database/entity/0061-event_refactoring/Event.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { Contribution } from '../Contribution'
|
||||||
|
import { ContributionMessage } from '../ContributionMessage'
|
||||||
|
import { User } from '../User'
|
||||||
|
import { Transaction } from '../Transaction'
|
||||||
|
import Decimal from 'decimal.js-light'
|
||||||
|
import {
|
||||||
|
BaseEntity,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
ManyToOne,
|
||||||
|
JoinColumn,
|
||||||
|
} from 'typeorm'
|
||||||
|
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
|
||||||
|
|
||||||
|
@Entity('events')
|
||||||
|
export class Event extends BaseEntity {
|
||||||
|
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||||
|
id: number
|
||||||
|
|
||||||
|
@Column({ length: 100, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||||
|
type: string
|
||||||
|
|
||||||
|
@CreateDateColumn({
|
||||||
|
name: 'created_at',
|
||||||
|
type: 'datetime',
|
||||||
|
default: () => 'CURRENT_TIMESTAMP(3)',
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
createdAt: Date
|
||||||
|
|
||||||
|
@Column({ name: 'affected_user_id', unsigned: true, nullable: false })
|
||||||
|
affectedUserId: number
|
||||||
|
|
||||||
|
@ManyToOne(() => User)
|
||||||
|
@JoinColumn({ name: 'affected_user_id', referencedColumnName: 'id' })
|
||||||
|
affectedUser: User
|
||||||
|
|
||||||
|
@Column({ name: 'acting_user_id', unsigned: true, nullable: false })
|
||||||
|
actingUserId: number
|
||||||
|
|
||||||
|
@ManyToOne(() => User)
|
||||||
|
@JoinColumn({ name: 'acting_user_id', referencedColumnName: 'id' })
|
||||||
|
actingUser: User
|
||||||
|
|
||||||
|
@Column({ name: 'involved_user_id', type: 'int', unsigned: true, nullable: true })
|
||||||
|
involvedUserId: number | null
|
||||||
|
|
||||||
|
@ManyToOne(() => User)
|
||||||
|
@JoinColumn({ name: 'involved_user_id', referencedColumnName: 'id' })
|
||||||
|
involvedUser: User | null
|
||||||
|
|
||||||
|
@Column({ name: 'involved_transaction_id', type: 'int', unsigned: true, nullable: true })
|
||||||
|
involvedTransactionId: number | null
|
||||||
|
|
||||||
|
@ManyToOne(() => Transaction)
|
||||||
|
@JoinColumn({ name: 'involved_transaction_id', referencedColumnName: 'id' })
|
||||||
|
involvedTransaction: Transaction | null
|
||||||
|
|
||||||
|
@Column({ name: 'involved_contribution_id', type: 'int', unsigned: true, nullable: true })
|
||||||
|
involvedContributionId: number | null
|
||||||
|
|
||||||
|
@ManyToOne(() => Contribution)
|
||||||
|
@JoinColumn({ name: 'involved_contribution_id', referencedColumnName: 'id' })
|
||||||
|
involvedContribution: Contribution | null
|
||||||
|
|
||||||
|
@Column({ name: 'involved_contribution_message_id', type: 'int', unsigned: true, nullable: true })
|
||||||
|
involvedContributionMessageId: number | null
|
||||||
|
|
||||||
|
@ManyToOne(() => ContributionMessage)
|
||||||
|
@JoinColumn({ name: 'involved_contribution_message_id', referencedColumnName: 'id' })
|
||||||
|
involvedContributionMessage: ContributionMessage | null
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
type: 'decimal',
|
||||||
|
precision: 40,
|
||||||
|
scale: 20,
|
||||||
|
nullable: true,
|
||||||
|
transformer: DecimalTransformer,
|
||||||
|
})
|
||||||
|
amount: Decimal | null
|
||||||
|
}
|
||||||
1
database/entity/Event.ts
Normal file
1
database/entity/Event.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { Event } from './0061-event_refactoring/Event'
|
||||||
@ -1 +0,0 @@
|
|||||||
export { EventProtocol } from './0050-add_messageId_to_event_protocol/EventProtocol'
|
|
||||||
@ -7,21 +7,21 @@ import { TransactionLink } from './TransactionLink'
|
|||||||
import { User } from './User'
|
import { User } from './User'
|
||||||
import { UserContact } from './UserContact'
|
import { UserContact } from './UserContact'
|
||||||
import { Contribution } from './Contribution'
|
import { Contribution } from './Contribution'
|
||||||
import { EventProtocol } from './EventProtocol'
|
import { Event } from './Event'
|
||||||
import { ContributionMessage } from './ContributionMessage'
|
import { ContributionMessage } from './ContributionMessage'
|
||||||
import { Community } from './Community'
|
import { Community } from './Community'
|
||||||
|
|
||||||
export const entities = [
|
export const entities = [
|
||||||
|
Community,
|
||||||
Contribution,
|
Contribution,
|
||||||
ContributionLink,
|
ContributionLink,
|
||||||
|
ContributionMessage,
|
||||||
|
Event,
|
||||||
LoginElopageBuys,
|
LoginElopageBuys,
|
||||||
LoginEmailOptIn,
|
LoginEmailOptIn,
|
||||||
Migration,
|
Migration,
|
||||||
Transaction,
|
Transaction,
|
||||||
TransactionLink,
|
TransactionLink,
|
||||||
User,
|
User,
|
||||||
EventProtocol,
|
|
||||||
ContributionMessage,
|
|
||||||
UserContact,
|
UserContact,
|
||||||
Community,
|
|
||||||
]
|
]
|
||||||
|
|||||||
98
database/migrations/0061-event_refactoring.ts
Normal file
98
database/migrations/0061-event_refactoring.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/* MIGRATION TO REFACTOR THE EVENT_PROTOCOL TABLE
|
||||||
|
*
|
||||||
|
* This migration refactors the `event_protocol` table.
|
||||||
|
* It renames the table to `event`, introduces new fields and renames others.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
|
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||||
|
await queryFn('RENAME TABLE `event_protocol` TO `events`;')
|
||||||
|
await queryFn('ALTER TABLE `events` RENAME COLUMN `user_id` TO `affected_user_id`;')
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` ADD COLUMN `acting_user_id` int(10) unsigned DEFAULT NULL AFTER `affected_user_id`;',
|
||||||
|
)
|
||||||
|
await queryFn('UPDATE `events` SET `acting_user_id` = `affected_user_id`;')
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` MODIFY COLUMN `acting_user_id` int(10) unsigned NOT NULL AFTER `affected_user_id`;',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `events` RENAME COLUMN `x_user_id` TO `involved_user_id`;')
|
||||||
|
await queryFn('ALTER TABLE `events` DROP COLUMN `x_community_id`;')
|
||||||
|
await queryFn('ALTER TABLE `events` RENAME COLUMN `transaction_id` TO `involved_transaction_id`;')
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` RENAME COLUMN `contribution_id` TO `involved_contribution_id`;',
|
||||||
|
)
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` MODIFY COLUMN `message_id` int(10) unsigned DEFAULT NULL AFTER `involved_contribution_id`;',
|
||||||
|
)
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` RENAME COLUMN `message_id` TO `involved_contribution_message_id`;',
|
||||||
|
)
|
||||||
|
|
||||||
|
// Moderator id was saved in former user_id
|
||||||
|
await queryFn(
|
||||||
|
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET affected_user_id=contributions.user_id WHERE `type` = "ADMIN_CONTRIBUTION_CREATE";',
|
||||||
|
)
|
||||||
|
|
||||||
|
// inconsistent data on this type, since not all data can be reconstructed
|
||||||
|
await queryFn(
|
||||||
|
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET acting_user_id=0 WHERE `type` = "ADMIN_CONTRIBUTION_UPDATE";',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET acting_user_id=contributions.deleted_by WHERE `type` = "ADMIN_CONTRIBUTION_DELETE";',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET acting_user_id=contributions.confirmed_by WHERE `type` = "CONTRIBUTION_CONFIRM";',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET involved_user_id=NULL, acting_user_id=contributions.denied_by WHERE `type` = "ADMIN_CONTRIBUTION_DENY";',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'UPDATE `events` SET acting_user_id=involved_user_id WHERE `type` = "TRANSACTION_RECEIVE";',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn('UPDATE `events` SET amount = amount * -1 WHERE `type` = "TRANSACTION_SEND";')
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` MODIFY COLUMN `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` MODIFY COLUMN `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP();',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn('UPDATE `events` SET amount = amount * -1 WHERE `type` = "TRANSACTION_SEND";')
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'UPDATE `events` SET involved_user_id=acting_user_id WHERE `type` = "ADMIN_CONTRIBUTION_DENY";',
|
||||||
|
)
|
||||||
|
await queryFn(
|
||||||
|
'UPDATE `events` SET affected_user_id=acting_user_id WHERE `type` = "ADMIN_CONTRIBUTION_CREATE";',
|
||||||
|
)
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` RENAME COLUMN `involved_contribution_message_id` TO `message_id`;',
|
||||||
|
)
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` MODIFY COLUMN `message_id` int(10) unsigned DEFAULT NULL AFTER `amount`;',
|
||||||
|
)
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` RENAME COLUMN `involved_contribution_id` TO `contribution_id`;',
|
||||||
|
)
|
||||||
|
await queryFn('ALTER TABLE `events` RENAME COLUMN `involved_transaction_id` TO `transaction_id`;')
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `events` ADD COLUMN `x_community_id` int(10) unsigned DEFAULT NULL AFTER `involved_user_id`;',
|
||||||
|
)
|
||||||
|
await queryFn('ALTER TABLE `events` RENAME COLUMN `involved_user_id` TO `x_user_id`;')
|
||||||
|
await queryFn('ALTER TABLE `events` DROP COLUMN `acting_user_id`;')
|
||||||
|
await queryFn('ALTER TABLE `events` RENAME COLUMN `affected_user_id` TO `user_id`;')
|
||||||
|
await queryFn('RENAME TABLE `events` TO `event_protocol`;')
|
||||||
|
}
|
||||||
@ -16,9 +16,7 @@
|
|||||||
"dev_up": "cross-env TZ=UTC ts-node src/index.ts up",
|
"dev_up": "cross-env TZ=UTC ts-node src/index.ts up",
|
||||||
"dev_down": "cross-env TZ=UTC ts-node src/index.ts down",
|
"dev_down": "cross-env TZ=UTC ts-node src/index.ts down",
|
||||||
"dev_reset": "cross-env TZ=UTC ts-node src/index.ts reset",
|
"dev_reset": "cross-env TZ=UTC ts-node src/index.ts reset",
|
||||||
"lint": "eslint --max-warnings=0 --ext .js,.ts .",
|
"lint": "eslint --max-warnings=0 --ext .js,.ts ."
|
||||||
"seed:config": "ts-node ./node_modules/typeorm-seeding/dist/cli.js config",
|
|
||||||
"seed": "cross-env TZ=UTC ts-node src/index.ts seed"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/faker": "^5.5.9",
|
"@types/faker": "^5.5.9",
|
||||||
|
|||||||
@ -65,7 +65,9 @@ FEDERATION_COMMUNITY_URL=http://stage1.gradido.net
|
|||||||
# the api port is the baseport, which will be added with the api-version, e.g. 1_0 = 5010
|
# the api port is the baseport, which will be added with the api-version, e.g. 1_0 = 5010
|
||||||
FEDERATION_COMMUNITY_API_PORT=5000
|
FEDERATION_COMMUNITY_API_PORT=5000
|
||||||
|
|
||||||
|
FEDERATION_CONFIG_VERSION=v1.2023-01-09
|
||||||
|
# comma separated list of api-versions, which cause starting several federation modules
|
||||||
|
FEDERATION_COMMUNITY_APIS=1_0,1_1,2_0
|
||||||
|
|
||||||
# database
|
# database
|
||||||
DATABASE_CONFIG_VERSION=v1.2022-03-18
|
DATABASE_CONFIG_VERSION=v1.2022-03-18
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
location /api/$FEDERATION_APIVERSION {
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
|
||||||
|
proxy_pass http://127.0.0.1:$FEDERATION_PORT;
|
||||||
|
proxy_redirect off;
|
||||||
|
|
||||||
|
access_log $GRADIDO_LOG_PATH/nginx-access.federation-$FEDERATION_PORT.log gradido_log;
|
||||||
|
error_log $GRADIDO_LOG_PATH/nginx-error.federation-$FEDERATION_PORT.log warn;
|
||||||
|
}
|
||||||
@ -42,19 +42,19 @@ server {
|
|||||||
|
|
||||||
# Frontend (default)
|
# Frontend (default)
|
||||||
location / {
|
location / {
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection 'upgrade';
|
proxy_set_header Connection 'upgrade';
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
|
|
||||||
proxy_pass http://127.0.0.1:3000;
|
proxy_pass http://127.0.0.1:3000;
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
|
|
||||||
access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log;
|
access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log;
|
||||||
error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn;
|
error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Backend
|
# Backend
|
||||||
location /graphql {
|
location /graphql {
|
||||||
@ -112,6 +112,9 @@ server {
|
|||||||
error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn;
|
error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Federation
|
||||||
|
$FEDERATION_NGINX_CONF
|
||||||
|
|
||||||
# TODO this could be a performance optimization
|
# TODO this could be a performance optimization
|
||||||
#location /vue {
|
#location /vue {
|
||||||
# alias /var/www/html/gradido/frontend/dist;
|
# alias /var/www/html/gradido/frontend/dist;
|
||||||
|
|||||||
@ -27,19 +27,19 @@ server {
|
|||||||
|
|
||||||
# Frontend (default)
|
# Frontend (default)
|
||||||
location / {
|
location / {
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection 'upgrade';
|
proxy_set_header Connection 'upgrade';
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
|
|
||||||
proxy_pass http://127.0.0.1:3000;
|
proxy_pass http://127.0.0.1:3000;
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
|
|
||||||
access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log;
|
access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log;
|
||||||
error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn;
|
error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Backend
|
# Backend
|
||||||
location /graphql {
|
location /graphql {
|
||||||
@ -98,6 +98,9 @@ server {
|
|||||||
error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn;
|
error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Federation
|
||||||
|
$FEDERATION_NGINX_CONF
|
||||||
|
|
||||||
# TODO this could be a performance optimization
|
# TODO this could be a performance optimization
|
||||||
#location /vue {
|
#location /vue {
|
||||||
# alias /var/www/html/gradido/frontend/dist;
|
# alias /var/www/html/gradido/frontend/dist;
|
||||||
|
|||||||
@ -59,8 +59,9 @@ ln -s /etc/nginx/sites-available/update-page.conf /etc/nginx/sites-enabled/
|
|||||||
sudo /etc/init.d/nginx restart
|
sudo /etc/init.d/nginx restart
|
||||||
|
|
||||||
# stop all services
|
# stop all services
|
||||||
echo 'Stopping all Gradido services' >> $UPDATE_HTML
|
echo 'Stop and delete all Gradido services' >> $UPDATE_HTML
|
||||||
pm2 stop all
|
pm2 delete all
|
||||||
|
pm2 save
|
||||||
|
|
||||||
# git
|
# git
|
||||||
BRANCH=${1:-master}
|
BRANCH=${1:-master}
|
||||||
@ -73,12 +74,41 @@ git pull
|
|||||||
export BUILD_COMMIT="$(git rev-parse HEAD)"
|
export BUILD_COMMIT="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
# Generate gradido.conf from template
|
# Generate gradido.conf from template
|
||||||
|
# *** 1st prepare for each apiversion the federation conf for nginx from federation-template
|
||||||
|
# *** set FEDERATION_PORT from FEDERATION_COMMUNITY_APIS and create gradido-federation.conf file
|
||||||
|
rm -f $NGINX_CONFIG_DIR/gradido.conf.tmp
|
||||||
|
rm -f $NGINX_CONFIG_DIR/gradido-federation.conf.locations
|
||||||
|
echo "====================================================================================================" >> $UPDATE_HTML
|
||||||
|
IFS="," read -a API_ARRAY <<< $FEDERATION_COMMUNITY_APIS
|
||||||
|
for api in "${API_ARRAY[@]}"
|
||||||
|
do
|
||||||
|
export FEDERATION_APIVERSION=$api
|
||||||
|
# calculate port by remove '_' and add value of api to baseport
|
||||||
|
port=${api//_/}
|
||||||
|
FEDERATION_PORT=${FEDERATION_COMMUNITY_API_PORT:-5000}
|
||||||
|
FEDERATION_PORT=$(($FEDERATION_PORT + $port))
|
||||||
|
export FEDERATION_PORT
|
||||||
|
echo "create ngingx config: location /api/$FEDERATION_APIVERSION to http://127.0.0.1:$FEDERATION_PORT" >> $UPDATE_HTML
|
||||||
|
envsubst '$FEDERATION_APIVERSION, $FEDERATION_PORT' < $NGINX_CONFIG_DIR/gradido-federation.conf.template >> $NGINX_CONFIG_DIR/gradido-federation.conf.locations
|
||||||
|
done
|
||||||
|
unset FEDERATION_APIVERSION
|
||||||
|
unset FEDERATION_PORT
|
||||||
|
echo "====================================================================================================" >> $UPDATE_HTML
|
||||||
|
|
||||||
|
# *** 2nd read gradido-federation.conf file in env variable to be replaced in 3rd step
|
||||||
|
export FEDERATION_NGINX_CONF=$(< $NGINX_CONFIG_DIR/gradido-federation.conf.locations)
|
||||||
|
|
||||||
|
# *** 3rd generate gradido nginx config including federation modules per api-version
|
||||||
echo 'Generate new gradido nginx config' >> $UPDATE_HTML
|
echo 'Generate new gradido nginx config' >> $UPDATE_HTML
|
||||||
case "$NGINX_SSL" in
|
case "$NGINX_SSL" in
|
||||||
true) TEMPLATE_FILE="gradido.conf.ssl.template" ;;
|
true) TEMPLATE_FILE="gradido.conf.ssl.template" ;;
|
||||||
*) TEMPLATE_FILE="gradido.conf.template" ;;
|
*) TEMPLATE_FILE="gradido.conf.template" ;;
|
||||||
esac
|
esac
|
||||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf
|
envsubst '$FEDERATION_NGINX_CONF' < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf.tmp
|
||||||
|
unset FEDERATION_NGINX_CONF
|
||||||
|
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/gradido.conf.tmp > $NGINX_CONFIG_DIR/gradido.conf
|
||||||
|
rm $NGINX_CONFIG_DIR/gradido.conf.tmp
|
||||||
|
rm $NGINX_CONFIG_DIR/gradido-federation.conf.locations
|
||||||
|
|
||||||
# Generate update-page.conf from template
|
# Generate update-page.conf from template
|
||||||
echo 'Generate new update-page nginx config' >> $UPDATE_HTML
|
echo 'Generate new update-page nginx config' >> $UPDATE_HTML
|
||||||
@ -94,11 +124,13 @@ cp -f $PROJECT_ROOT/backend/.env $PROJECT_ROOT/backend/.env.bak
|
|||||||
cp -f $PROJECT_ROOT/frontend/.env $PROJECT_ROOT/frontend/.env.bak
|
cp -f $PROJECT_ROOT/frontend/.env $PROJECT_ROOT/frontend/.env.bak
|
||||||
cp -f $PROJECT_ROOT/admin/.env $PROJECT_ROOT/admin/.env.bak
|
cp -f $PROJECT_ROOT/admin/.env $PROJECT_ROOT/admin/.env.bak
|
||||||
cp -f $PROJECT_ROOT/dht-node/.env $PROJECT_ROOT/dht-node/.env.bak
|
cp -f $PROJECT_ROOT/dht-node/.env $PROJECT_ROOT/dht-node/.env.bak
|
||||||
|
cp -f $PROJECT_ROOT/federation/.env $PROJECT_ROOT/federation/.env.bak
|
||||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env
|
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env
|
||||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env
|
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env
|
||||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env
|
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env
|
||||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env
|
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env
|
||||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env
|
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env
|
||||||
|
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env
|
||||||
|
|
||||||
# Install & build database
|
# Install & build database
|
||||||
echo 'Updating database' >> $UPDATE_HTML
|
echo 'Updating database' >> $UPDATE_HTML
|
||||||
@ -124,7 +156,6 @@ if [ "$DEPLOY_SEED_DATA" = "true" ]; then
|
|||||||
fi
|
fi
|
||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
export NODE_ENV=production
|
export NODE_ENV=production
|
||||||
pm2 delete gradido-backend
|
|
||||||
pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||||
pm2 save
|
pm2 save
|
||||||
|
|
||||||
@ -137,7 +168,6 @@ yarn install
|
|||||||
yarn build
|
yarn build
|
||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
export NODE_ENV=production
|
export NODE_ENV=production
|
||||||
pm2 delete gradido-frontend
|
|
||||||
pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||||
pm2 save
|
pm2 save
|
||||||
|
|
||||||
@ -150,7 +180,6 @@ yarn install
|
|||||||
yarn build
|
yarn build
|
||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
export NODE_ENV=production
|
export NODE_ENV=production
|
||||||
pm2 delete gradido-admin
|
|
||||||
pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||||
pm2 save
|
pm2 save
|
||||||
|
|
||||||
@ -163,15 +192,49 @@ yarn install
|
|||||||
yarn build
|
yarn build
|
||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
export NODE_ENV=production
|
export NODE_ENV=production
|
||||||
pm2 delete gradido-dht-node
|
|
||||||
if [ ! -z $FEDERATION_DHT_TOPIC ]; then
|
if [ ! -z $FEDERATION_DHT_TOPIC ]; then
|
||||||
pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||||
|
pm2 save
|
||||||
else
|
else
|
||||||
echo "====================================================================="
|
echo "=====================================================================" >> $UPDATE_HTML
|
||||||
echo "WARNING: FEDERATION_DHT_TOPIC not configured. DHT-Node not started..."
|
echo "WARNING: FEDERATION_DHT_TOPIC not configured. DHT-Node not started..." >> $UPDATE_HTML
|
||||||
echo "====================================================================="
|
echo "=====================================================================" >> $UPDATE_HTML
|
||||||
fi
|
fi
|
||||||
pm2 save
|
|
||||||
|
|
||||||
|
# Install & build federation
|
||||||
|
echo 'Updating federation' >> $UPDATE_HTML
|
||||||
|
cd $PROJECT_ROOT/federation
|
||||||
|
# TODO maybe handle this differently?
|
||||||
|
unset NODE_ENV
|
||||||
|
yarn install
|
||||||
|
yarn build
|
||||||
|
# TODO maybe handle this differently?
|
||||||
|
export NODE_ENV=production
|
||||||
|
|
||||||
|
# set FEDERATION_PORT from FEDERATION_COMMUNITY_APIS
|
||||||
|
IFS="," read -a API_ARRAY <<< $FEDERATION_COMMUNITY_APIS
|
||||||
|
for api in "${API_ARRAY[@]}"
|
||||||
|
do
|
||||||
|
export FEDERATION_API=$api
|
||||||
|
echo "FEDERATION_API=$FEDERATION_API" >> $UPDATE_HTML
|
||||||
|
export MODULENAME=gradido-federation-$api
|
||||||
|
echo "MODULENAME=$MODULENAME" >> $UPDATE_HTML
|
||||||
|
# calculate port by remove '_' and add value of api to baseport
|
||||||
|
port=${api//_/}
|
||||||
|
FEDERATION_PORT=${FEDERATION_COMMUNITY_API_PORT:-5000}
|
||||||
|
FEDERATION_PORT=$(($FEDERATION_PORT + $port))
|
||||||
|
export FEDERATION_PORT
|
||||||
|
echo "====================================================" >> $UPDATE_HTML
|
||||||
|
echo " start $MODULENAME listening on port=$FEDERATION_PORT" >> $UPDATE_HTML
|
||||||
|
echo "====================================================" >> $UPDATE_HTML
|
||||||
|
# pm2 delete $MODULENAME
|
||||||
|
pm2 start --name $MODULENAME "yarn --cwd $PROJECT_ROOT/federation start" -l $GRADIDO_LOG_PATH/pm2.$MODULENAME.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||||
|
pm2 save
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# let nginx showing gradido
|
# let nginx showing gradido
|
||||||
echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML
|
echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML
|
||||||
|
|||||||
@ -4,6 +4,11 @@ module.exports = {
|
|||||||
preset: 'ts-jest',
|
preset: 'ts-jest',
|
||||||
collectCoverage: true,
|
collectCoverage: true,
|
||||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
lines: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||||
setupFilesAfterEnv: [],
|
setupFilesAfterEnv: [],
|
||||||
modulePathIgnorePatterns: ['<rootDir>/build/'],
|
modulePathIgnorePatterns: ['<rootDir>/build/'],
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
"start": "cross-env TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js",
|
"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 --exec ts-node -r dotenv/config -r tsconfig-paths/register src/index.ts",
|
"dev": "cross-env TZ=UTC nodemon -w src --ext ts --exec ts-node -r dotenv/config -r tsconfig-paths/register src/index.ts",
|
||||||
"lint": "eslint --max-warnings=0 --ext .js,.ts .",
|
"lint": "eslint --max-warnings=0 --ext .js,.ts .",
|
||||||
"test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles"
|
"test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --forceExit --detectOpenHandles"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hyperswarm/dht": "^6.4.4",
|
"@hyperswarm/dht": "^6.4.4",
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import dotenv from 'dotenv'
|
|||||||
dotenv.config()
|
dotenv.config()
|
||||||
|
|
||||||
const constants = {
|
const constants = {
|
||||||
DB_VERSION: '0060-update_communities_table',
|
DB_VERSION: '0061-event_refactoring',
|
||||||
LOG4JS_CONFIG: 'log4js-config.json',
|
LOG4JS_CONFIG: 'log4js-config.json',
|
||||||
// default log level on production should be info
|
// default log level on production should be info
|
||||||
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
|
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
|
||||||
|
|||||||
@ -719,11 +719,11 @@ describe('federation', () => {
|
|||||||
JSON.stringify([
|
JSON.stringify([
|
||||||
{
|
{
|
||||||
api: '1_0',
|
api: '1_0',
|
||||||
url: 'http://localhost:5001/api/',
|
url: 'http://localhost/api/',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
api: '2_0',
|
api: '2_0',
|
||||||
url: 'http://localhost:5002/api/',
|
url: 'http://localhost/api/',
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
@ -747,7 +747,7 @@ describe('federation', () => {
|
|||||||
foreign: true,
|
foreign: true,
|
||||||
publicKey: expect.any(Buffer),
|
publicKey: expect.any(Buffer),
|
||||||
apiVersion: '1_0',
|
apiVersion: '1_0',
|
||||||
endPoint: 'http://localhost:5001/api/',
|
endPoint: 'http://localhost/api/',
|
||||||
lastAnnouncedAt: expect.any(Date),
|
lastAnnouncedAt: expect.any(Date),
|
||||||
createdAt: expect.any(Date),
|
createdAt: expect.any(Date),
|
||||||
updatedAt: null,
|
updatedAt: null,
|
||||||
@ -764,7 +764,7 @@ describe('federation', () => {
|
|||||||
foreign: true,
|
foreign: true,
|
||||||
publicKey: expect.any(Buffer),
|
publicKey: expect.any(Buffer),
|
||||||
apiVersion: '2_0',
|
apiVersion: '2_0',
|
||||||
endPoint: 'http://localhost:5002/api/',
|
endPoint: 'http://localhost/api/',
|
||||||
lastAnnouncedAt: expect.any(Date),
|
lastAnnouncedAt: expect.any(Date),
|
||||||
createdAt: expect.any(Date),
|
createdAt: expect.any(Date),
|
||||||
updatedAt: null,
|
updatedAt: null,
|
||||||
@ -786,15 +786,15 @@ describe('federation', () => {
|
|||||||
JSON.stringify([
|
JSON.stringify([
|
||||||
{
|
{
|
||||||
api: '1_0',
|
api: '1_0',
|
||||||
url: 'http://localhost:5001/api/',
|
url: 'http://localhost/api/',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
api: '1_1',
|
api: '1_1',
|
||||||
url: 'http://localhost:5002/api/',
|
url: 'http://localhost/api/',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
api: '2_0',
|
api: '2_0',
|
||||||
url: 'http://localhost:5003/api/',
|
url: 'http://localhost/api/',
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -181,11 +181,9 @@ export const startDHT = async (topic: string): Promise<void> => {
|
|||||||
|
|
||||||
async function writeHomeCommunityEnries(pubKey: any): Promise<CommunityApi[]> {
|
async function writeHomeCommunityEnries(pubKey: any): Promise<CommunityApi[]> {
|
||||||
const homeApiVersions: CommunityApi[] = Object.values(ApiVersionType).map(function (apiEnum) {
|
const homeApiVersions: CommunityApi[] = Object.values(ApiVersionType).map(function (apiEnum) {
|
||||||
const port =
|
|
||||||
Number.parseInt(CONFIG.FEDERATION_COMMUNITY_API_PORT) + Number(apiEnum.replace('_', ''))
|
|
||||||
const comApi: CommunityApi = {
|
const comApi: CommunityApi = {
|
||||||
api: apiEnum,
|
api: apiEnum,
|
||||||
url: CONFIG.FEDERATION_COMMUNITY_URL + ':' + port.toString() + '/api/',
|
url: CONFIG.FEDERATION_COMMUNITY_URL + '/api/',
|
||||||
}
|
}
|
||||||
return comApi
|
return comApi
|
||||||
})
|
})
|
||||||
|
|||||||
@ -56,7 +56,7 @@ export default defineConfig({
|
|||||||
env: {
|
env: {
|
||||||
backendURL: 'http://localhost:4000',
|
backendURL: 'http://localhost:4000',
|
||||||
mailserverURL: 'http://localhost:1080',
|
mailserverURL: 'http://localhost:1080',
|
||||||
loginQuery: `query ($email: String!, $password: String!, $publisherId: Int) {
|
loginQuery: `mutation ($email: String!, $password: String!, $publisherId: Int) {
|
||||||
login(email: $email, password: $password, publisherId: $publisherId) {
|
login(email: $email, password: $password, publisherId: $publisherId) {
|
||||||
email
|
email
|
||||||
firstName
|
firstName
|
||||||
@ -69,7 +69,8 @@ export default defineConfig({
|
|||||||
hasElopage
|
hasElopage
|
||||||
publisherId
|
publisherId
|
||||||
isAdmin
|
isAdmin
|
||||||
creation
|
hideAmountGDD
|
||||||
|
hideAmountGDT
|
||||||
__typename
|
__typename
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
|
|||||||
@ -5,13 +5,13 @@ Feature: User Authentication - reset password
|
|||||||
# TODO for these pre-conditions utilize seeding or API check, if user exists in test system
|
# TODO for these pre-conditions utilize seeding or API check, if user exists in test system
|
||||||
# Background:
|
# Background:
|
||||||
# Given the following "users" are in the database:
|
# Given the following "users" are in the database:
|
||||||
# | email | password | name |
|
# | email | password | name |
|
||||||
# | bibi@bloxberg.de | Aa12345_ | Bibi Bloxberg |
|
# | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz |
|
||||||
|
|
||||||
Scenario: Reset password from signin page successfully
|
Scenario: Reset password from signin page successfully
|
||||||
Given the user navigates to page "/login"
|
Given the user navigates to page "/login"
|
||||||
And the user navigates to the forgot password page
|
And the user navigates to the forgot password page
|
||||||
When the user enters the e-mail address "bibi@bloxberg.de"
|
When the user enters the e-mail address "raeuber@hotzenplotz.de"
|
||||||
And the user submits the e-mail form
|
And the user submits the e-mail form
|
||||||
Then the user receives an e-mail containing the "password reset" link
|
Then the user receives an e-mail containing the "password reset" link
|
||||||
When the user opens the "password reset" link in the browser
|
When the user opens the "password reset" link in the browser
|
||||||
@ -19,7 +19,7 @@ Feature: User Authentication - reset password
|
|||||||
And the user repeats the password "12345Aa_"
|
And the user repeats the password "12345Aa_"
|
||||||
And the user submits the password form
|
And the user submits the password form
|
||||||
And the user clicks the sign in button
|
And the user clicks the sign in button
|
||||||
Then the user submits the credentials "bibi@bloxberg.de" "Aa12345_"
|
Then the user submits the credentials "raeuber@hotzenplotz.de" "Aa12345_"
|
||||||
And the user cannot login
|
And the user cannot login
|
||||||
But the user submits the credentials "bibi@bloxberg.de" "12345Aa_"
|
But the user submits the credentials "raeuber@hotzenplotz.de" "12345Aa_"
|
||||||
And the user is logged in with username "Bibi Bloxberg"
|
And the user is logged in with username "Räuber Hotzenplotz"
|
||||||
|
|||||||
@ -5,14 +5,14 @@ Feature: User profile - change password
|
|||||||
Background:
|
Background:
|
||||||
# TODO for these pre-conditions utilize seeding or API check, if user exists in test system
|
# TODO for these pre-conditions utilize seeding or API check, if user exists in test system
|
||||||
# Given the following "users" are in the database:
|
# Given the following "users" are in the database:
|
||||||
# | email | password | name |
|
# | email | password | name |
|
||||||
# | bibi@bloxberg.de | Aa12345_ | Bibi Bloxberg | |
|
# | bob@baumeister.de | Aa12345_ | Bob der Baumeister |
|
||||||
|
|
||||||
# TODO instead of credentials use the name of an user object (see seeds in backend)
|
# TODO instead of credentials use the name of an user object (see seeds in backend)
|
||||||
Given the user is logged in as "bibi@bloxberg.de" "Aa12345_"
|
Given the user is logged in as "bob@baumeister.de" "Aa12345_"
|
||||||
|
|
||||||
Scenario: Change password successfully
|
Scenario: Change password successfully
|
||||||
Given the user navigates to page "/profile"
|
Given the user navigates to page "/settings"
|
||||||
And the user opens the change password menu
|
And the user opens the change password menu
|
||||||
When the user fills the password form with:
|
When the user fills the password form with:
|
||||||
| Old password | Aa12345_ |
|
| Old password | Aa12345_ |
|
||||||
@ -21,7 +21,7 @@ Feature: User profile - change password
|
|||||||
And the user submits the password form
|
And the user submits the password form
|
||||||
And the user is presented a "success" message
|
And the user is presented a "success" message
|
||||||
And the user logs out
|
And the user logs out
|
||||||
Then the user submits the credentials "bibi@bloxberg.de" "Aa12345_"
|
Then the user submits the credentials "bob@baumeister.de" "Aa12345_"
|
||||||
And the user cannot login
|
And the user cannot login
|
||||||
But the user submits the credentials "bibi@bloxberg.de" "12345Aa_"
|
But the user submits the credentials "bob@baumeister.de" "12345Aa_"
|
||||||
And the user is logged in with username "Bibi Bloxberg"
|
And the user is logged in with username "Bob der Baumeister"
|
||||||
|
|||||||
@ -11,7 +11,7 @@ export class SideNavMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
cy.get(this.logoutMenu).click()
|
cy.get('.main-sidebar').find(this.logoutMenu).click()
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
federation/.env.dist
Normal file
11
federation/.env.dist
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Database
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=gradido_community
|
||||||
|
DB_USER=root
|
||||||
|
DB_PASSWORD=
|
||||||
|
|
||||||
|
# Federation
|
||||||
|
FEDERATION_API=1_0
|
||||||
|
FEDERATION_PORT=5010
|
||||||
|
FEDERATION_COMMUNITY_URL=http://localhost
|
||||||
16
federation/.env.template
Normal file
16
federation/.env.template
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
CONFIG_VERSION=$FEDERATION_CONFIG_VERSION
|
||||||
|
|
||||||
|
LOG_LEVEL=$LOG_LEVEL
|
||||||
|
# this is set fix to false, because it is important for 'production' environments. only set to true if a graphql-playground should be in use
|
||||||
|
GRAPHIQL=false
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DB_HOST=$DB_HOST
|
||||||
|
DB_PORT=$DB_PORT
|
||||||
|
DB_DATABASE=$DB_DATABASE
|
||||||
|
DB_USER=$DB_USER
|
||||||
|
DB_PASSWORD=$DB_PASSWORD
|
||||||
|
|
||||||
|
# Federation
|
||||||
|
FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL
|
||||||
|
|
||||||
@ -9,6 +9,11 @@ module.exports = {
|
|||||||
'!src/seeds/**',
|
'!src/seeds/**',
|
||||||
'!build/**',
|
'!build/**',
|
||||||
],
|
],
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
lines: 72,
|
||||||
|
},
|
||||||
|
},
|
||||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||||
setupFilesAfterEnv: [],
|
setupFilesAfterEnv: [],
|
||||||
modulePathIgnorePatterns: ['<rootDir>/build/'],
|
modulePathIgnorePatterns: ['<rootDir>/build/'],
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
"build": "tsc --build",
|
"build": "tsc --build",
|
||||||
"clean": "tsc --build --clean",
|
"clean": "tsc --build --clean",
|
||||||
"start": "cross-env TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js",
|
"start": "cross-env TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js",
|
||||||
"test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles",
|
"test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --forceExit --detectOpenHandles",
|
||||||
"dev": "cross-env TZ=UTC nodemon -w src --ext ts --exec ts-node -r dotenv/config -r tsconfig-paths/register src/index.ts",
|
"dev": "cross-env TZ=UTC nodemon -w src --ext ts --exec ts-node -r dotenv/config -r tsconfig-paths/register src/index.ts",
|
||||||
"lint": "eslint --max-warnings=0 --ext .js,.ts ."
|
"lint": "eslint --max-warnings=0 --ext .js,.ts ."
|
||||||
},
|
},
|
||||||
|
|||||||
@ -11,7 +11,7 @@ Decimal.set({
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const constants = {
|
const constants = {
|
||||||
DB_VERSION: '0060-update_communities_table',
|
DB_VERSION: '0061-event_refactoring',
|
||||||
// DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
// DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||||
LOG4JS_CONFIG: 'log4js-config.json',
|
LOG4JS_CONFIG: 'log4js-config.json',
|
||||||
// default log level on production should be info
|
// default log level on production should be info
|
||||||
@ -24,7 +24,6 @@ const constants = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const server = {
|
const server = {
|
||||||
PORT: process.env.PORT || 5010,
|
|
||||||
// JWT_SECRET: process.env.JWT_SECRET || 'secret123',
|
// JWT_SECRET: process.env.JWT_SECRET || 'secret123',
|
||||||
// JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m',
|
// JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m',
|
||||||
GRAPHIQL: process.env.GRAPHIQL === 'true' || false,
|
GRAPHIQL: process.env.GRAPHIQL === 'true' || false,
|
||||||
@ -40,21 +39,6 @@ const database = {
|
|||||||
TYPEORM_LOGGING_RELATIVE_PATH:
|
TYPEORM_LOGGING_RELATIVE_PATH:
|
||||||
process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log',
|
process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log',
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
const community = {
|
|
||||||
COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung',
|
|
||||||
COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/',
|
|
||||||
COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register',
|
|
||||||
COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}',
|
|
||||||
COMMUNITY_REDEEM_CONTRIBUTION_URL:
|
|
||||||
process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}',
|
|
||||||
COMMUNITY_DESCRIPTION:
|
|
||||||
process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.',
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This is needed by graphql-directive-auth
|
|
||||||
// process.env.APP_SECRET = server.JWT_SECRET
|
|
||||||
|
|
||||||
// Check config version
|
// Check config version
|
||||||
constants.CONFIG_VERSION.CURRENT =
|
constants.CONFIG_VERSION.CURRENT =
|
||||||
@ -71,10 +55,8 @@ if (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const federation = {
|
const federation = {
|
||||||
// FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || null,
|
|
||||||
// FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED || null,
|
|
||||||
FEDERATION_PORT: process.env.FEDERATION_PORT || 5010,
|
|
||||||
FEDERATION_API: process.env.FEDERATION_API || '1_0',
|
FEDERATION_API: process.env.FEDERATION_API || '1_0',
|
||||||
|
FEDERATION_PORT: process.env.FEDERATION_PORT || 5010,
|
||||||
FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || null,
|
FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
federation/src/graphql/api/1_0/model/GetPublicKeyResult.ts
Normal file
13
federation/src/graphql/api/1_0/model/GetPublicKeyResult.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
publicKey: string
|
||||||
|
}
|
||||||
20
federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts
Normal file
20
federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import { Query, Resolver } from 'type-graphql'
|
||||||
|
import { federationLogger as logger } from '@/server/logger'
|
||||||
|
import { Community as DbCommunity } from '@entity/Community'
|
||||||
|
import { GetPublicKeyResult } from '../model/GetPublicKeyResult'
|
||||||
|
|
||||||
|
@Resolver()
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
export class PublicKeyResolver {
|
||||||
|
@Query(() => GetPublicKeyResult)
|
||||||
|
async getPublicKey(): Promise<GetPublicKeyResult> {
|
||||||
|
logger.info(`getPublicKey()...`)
|
||||||
|
const homeCom = await DbCommunity.findOneOrFail({
|
||||||
|
foreign: false,
|
||||||
|
apiVersion: '1_0',
|
||||||
|
})
|
||||||
|
logger.info(`getPublicKey()... with publicKey=${homeCom.publicKey}`)
|
||||||
|
return new GetPublicKeyResult(homeCom.publicKey.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,7 +20,7 @@ async function main() {
|
|||||||
if (CONFIG.GRAPHIQL) {
|
if (CONFIG.GRAPHIQL) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(
|
console.log(
|
||||||
`GraphIQL available at http://localhost:${CONFIG.FEDERATION_PORT}`
|
`GraphIQL available at ${CONFIG.FEDERATION_COMMUNITY_URL}/api/${CONFIG.FEDERATION_API}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,13 +1,18 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
verbose: true,
|
verbose: true,
|
||||||
|
collectCoverage: true,
|
||||||
collectCoverageFrom: ['src/**/*.{js,vue}', '!**/node_modules/**', '!**/?(*.)+(spec|test).js?(x)'],
|
collectCoverageFrom: ['src/**/*.{js,vue}', '!**/node_modules/**', '!**/?(*.)+(spec|test).js?(x)'],
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
lines: 95,
|
||||||
|
},
|
||||||
|
},
|
||||||
moduleFileExtensions: [
|
moduleFileExtensions: [
|
||||||
'js',
|
'js',
|
||||||
// 'jsx',
|
// 'jsx',
|
||||||
'json',
|
'json',
|
||||||
'vue',
|
'vue',
|
||||||
],
|
],
|
||||||
// coverageReporters: ['lcov', 'text'],
|
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'\\.(css|less)$': 'identity-obj-proxy',
|
'\\.(css|less)$': 'identity-obj-proxy',
|
||||||
'\\.(scss)$': '<rootDir>/src/assets/mocks/styleMock.js',
|
'\\.(scss)$': '<rootDir>/src/assets/mocks/styleMock.js',
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
"analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json",
|
"analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json",
|
||||||
"lint": "eslint --max-warnings=0 --ext .js,.vue,.json .",
|
"lint": "eslint --max-warnings=0 --ext .js,.vue,.json .",
|
||||||
"stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'",
|
"stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'",
|
||||||
"test": "cross-env TZ=UTC jest --coverage",
|
"test": "cross-env TZ=UTC jest",
|
||||||
"locales": "scripts/sort.sh"
|
"locales": "scripts/sort.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -49,15 +49,15 @@ describe('Sidebar', () => {
|
|||||||
expect(wrapper.findAll('.nav-item').at(2).text()).toEqual('navigation.transactions')
|
expect(wrapper.findAll('.nav-item').at(2).text()).toEqual('navigation.transactions')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has nav-item "gdt.gdt" in navbar', () => {
|
it('has nav-item "creation" in navbar', () => {
|
||||||
expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('creation')
|
expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('creation')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has nav-item "creation" in navbar', () => {
|
it('has nav-item "GDT" in navbar', () => {
|
||||||
expect(wrapper.findAll('.nav-item').at(4).text()).toContain('GDT')
|
expect(wrapper.findAll('.nav-item').at(4).text()).toContain('GDT')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has nav-item "Information" in navbar', () => {
|
it('has nav-item "navigation.info" in navbar', () => {
|
||||||
expect(wrapper.findAll('.nav-item').at(5).text()).toContain('navigation.info')
|
expect(wrapper.findAll('.nav-item').at(5).text()).toContain('navigation.info')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -68,13 +68,13 @@ describe('Sidebar', () => {
|
|||||||
expect(wrapper.findAll('ul').at(1).findAll('.nav-item')).toHaveLength(2)
|
expect(wrapper.findAll('ul').at(1).findAll('.nav-item')).toHaveLength(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has nav-item "navigation.info" in navbar', () => {
|
it('has nav-item "navigation.settings" in navbar', () => {
|
||||||
expect(wrapper.findAll('ul').at(1).findAll('.nav-item').at(0).text()).toEqual(
|
expect(wrapper.findAll('ul').at(1).findAll('.nav-item').at(0).text()).toEqual(
|
||||||
'navigation.settings',
|
'navigation.settings',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has nav-item "navigation.settings" in navbar', () => {
|
it('has nav-item "navigation.logout" in navbar', () => {
|
||||||
expect(wrapper.findAll('ul').at(1).findAll('.nav-item').at(1).text()).toEqual(
|
expect(wrapper.findAll('ul').at(1).findAll('.nav-item').at(1).text()).toEqual(
|
||||||
'navigation.logout',
|
'navigation.logout',
|
||||||
)
|
)
|
||||||
|
|||||||
@ -48,7 +48,12 @@
|
|||||||
<b-icon icon="shield-check" aria-hidden="true"></b-icon>
|
<b-icon icon="shield-check" aria-hidden="true"></b-icon>
|
||||||
<span class="ml-2">{{ $t('navigation.admin_area') }}</span>
|
<span class="ml-2">{{ $t('navigation.admin_area') }}</span>
|
||||||
</b-nav-item>
|
</b-nav-item>
|
||||||
<b-nav-item class="font-weight-bold" @click="$emit('logout')" active-class="activeRoute">
|
<b-nav-item
|
||||||
|
class="font-weight-bold"
|
||||||
|
@click="$emit('logout')"
|
||||||
|
active-class="activeRoute"
|
||||||
|
data-test="logout-menu"
|
||||||
|
>
|
||||||
<b-img src="/img/svg/logout.svg" height="20" class="svg-icon" />
|
<b-img src="/img/svg/logout.svg" height="20" class="svg-icon" />
|
||||||
<span class="ml-2 text-205">{{ $t('navigation.logout') }}</span>
|
<span class="ml-2 text-205">{{ $t('navigation.logout') }}</span>
|
||||||
</b-nav-item>
|
</b-nav-item>
|
||||||
|
|||||||
@ -7,6 +7,8 @@ FRONTEND_DIR="${PROJECT_DIR}/frontend/"
|
|||||||
BACKEND_DIR="${PROJECT_DIR}/backend/"
|
BACKEND_DIR="${PROJECT_DIR}/backend/"
|
||||||
DATABASE_DIR="${PROJECT_DIR}/database/"
|
DATABASE_DIR="${PROJECT_DIR}/database/"
|
||||||
ADMIN_DIR="${PROJECT_DIR}/admin/"
|
ADMIN_DIR="${PROJECT_DIR}/admin/"
|
||||||
|
DHTNODE_DIR="${PROJECT_DIR}/dht-node/"
|
||||||
|
FEDERATION_DIR="${PROJECT_DIR}/federation/"
|
||||||
|
|
||||||
# navigate to project directory
|
# navigate to project directory
|
||||||
cd ${PROJECT_DIR}
|
cd ${PROJECT_DIR}
|
||||||
@ -26,6 +28,10 @@ cd ${DATABASE_DIR}
|
|||||||
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
|
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
|
||||||
cd ${ADMIN_DIR}
|
cd ${ADMIN_DIR}
|
||||||
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
|
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
|
||||||
|
cd ${DHTNODE_DIR}
|
||||||
|
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
|
||||||
|
cd ${FEDERATION_DIR}
|
||||||
|
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
|
||||||
|
|
||||||
# generate changelog
|
# generate changelog
|
||||||
cd ${PROJECT_DIR}
|
cd ${PROJECT_DIR}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user