Merge branch 'master' into add_yarn_build_on_root

This commit is contained in:
Hannes Heine 2023-03-15 09:05:31 +01:00 committed by GitHub
commit b2d79515e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
266 changed files with 3684 additions and 1811 deletions

31
.github/file-filters.yml vendored Normal file
View File

@ -0,0 +1,31 @@
# 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/**/*'

View 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

View File

@ -29,31 +29,6 @@ jobs:
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 #############################################
##############################################################################
@ -211,60 +186,6 @@ jobs:
- 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 ##########################################################
##############################################################################
@ -281,7 +202,7 @@ jobs:
# LINT BACKEND ###########################################################
##########################################################################
- name: backend | Lint
run: cd backend && yarn && yarn run lint
run: cd database && yarn && cd ../backend && yarn && yarn run lint
##############################################################################
# JOB: LOCALES BACKEND #######################################################
@ -335,51 +256,7 @@ jobs:
# 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 }}
run: cd frontend && yarn && yarn run test
##############################################################################
# JOB: UNIT TEST BACKEND ####################################################
@ -415,20 +292,7 @@ jobs:
- name: backend | docker-compose database
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
- name: backend Unit tests | test
run: |
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 }}
run: cd database && yarn && yarn build && cd ../backend && yarn && yarn test
##########################################################################
# DATABASE MIGRATION TEST UP + RESET #####################################
@ -459,7 +323,7 @@ jobs:
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]
needs: [build_test_mariadb, build_test_database_up, build_test_frontend, build_test_nginx]
steps:
##########################################################################
# CHECKOUT CODE ##########################################################
@ -490,13 +354,6 @@ jobs:
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:
@ -550,7 +407,7 @@ jobs:
run: |
cd e2e-tests/
yarn
yarn run cypress run --spec cypress/e2e/User.Authentication.feature,cypress/e2e/User.Authentication.ResetPassword.feature
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

View File

@ -1,4 +1,4 @@
name: gradido test_dht-node CI
name: Gradido DHT Node Test CI
on: push
@ -7,7 +7,7 @@ jobs:
# JOB: DOCKER BUILD TEST #####################################################
##############################################################################
build:
name: Docker Build Test
name: Docker Build Test - DHT Node
runs-on: ubuntu-latest
steps:
- name: Checkout code
@ -28,7 +28,7 @@ jobs:
# JOB: LINT ##################################################################
##############################################################################
lint:
name: Lint
name: Lint - DHT Node
runs-on: ubuntu-latest
needs: [build]
steps:
@ -50,7 +50,7 @@ jobs:
# JOB: UNIT TEST #############################################################
##############################################################################
unit_test:
name: Unit tests
name: Unit Tests - DHT Node
runs-on: ubuntu-latest
needs: [build]
steps:
@ -83,16 +83,4 @@ jobs:
#- name: Unit tests
# run: cd database && yarn && yarn build && cd ../dht-node && yarn && yarn test
- name: Unit tests
run: |
docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net -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 }}
run: docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net --rm gradido/dht-node:test yarn run test

View File

@ -1,4 +1,4 @@
name: gradido test_federation CI
name: Gradido Federation Test CI
on: push
@ -7,7 +7,7 @@ jobs:
# JOB: DOCKER BUILD TEST #####################################################
##############################################################################
build:
name: Docker Build Test
name: Docker Build Test - Federation
runs-on: ubuntu-latest
steps:
- name: Checkout code
@ -28,7 +28,7 @@ jobs:
# JOB: LINT ##################################################################
##############################################################################
lint:
name: Lint
name: Lint - Federation
runs-on: ubuntu-latest
needs: [build]
steps:
@ -50,7 +50,7 @@ jobs:
# JOB: UNIT TEST #############################################################
##############################################################################
unit_test:
name: Unit tests
name: Unit Tests - Federation
runs-on: ubuntu-latest
needs: [build]
steps:
@ -84,15 +84,4 @@ jobs:
# run: cd database && yarn && yarn build && cd ../dht-node && yarn && yarn test
- name: Unit tests
run: |
docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net -v ~/coverage:/app/coverage --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 }}
docker run --env NODE_ENV=test --env DB_HOST=mariadb --network gradido_internal-net --rm gradido/federation:test yarn run test

View File

@ -4,8 +4,76 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [1.19.1](https://github.com/gradido/gradido/compare/1.19.0...1.19.1)
- fix(frontend): admin question clickable [`#2810`](https://github.com/gradido/gradido/pull/2810)
- refactor(frontend): change b-img to b-icon send [`#2809`](https://github.com/gradido/gradido/pull/2809)
- fix(admin): update openCreation in case of tab open. [`#2806`](https://github.com/gradido/gradido/pull/2806)
- fix(admin): english language for contributions in admin [`#2804`](https://github.com/gradido/gradido/pull/2804)
- refactor(admin): event buttons for myself turned off in open contributions [`#2760`](https://github.com/gradido/gradido/pull/2760)
- fix(admin): contribution page [`#2794`](https://github.com/gradido/gradido/pull/2794)
- fix(frontend): info.svg [`#2798`](https://github.com/gradido/gradido/pull/2798)
- fix(backend): add relation messages to database query [`#2795`](https://github.com/gradido/gradido/pull/2795)
- fix(admin): header and menu [`#2793`](https://github.com/gradido/gradido/pull/2793)
- fix(frontend): send gdd - change first submit button text to 'Check Now' [`#2774`](https://github.com/gradido/gradido/pull/2774)
- refactor(frontend): creations generated by link NL [`#2771`](https://github.com/gradido/gradido/pull/2771)
- refactor(frontend): creations generated by link (FR) + (NL) [`#2770`](https://github.com/gradido/gradido/pull/2770)
- refactor(frontend): update German locales [`#2765`](https://github.com/gradido/gradido/pull/2765)
- refactor(backend): use find contributions helper for list contributions [`#2762`](https://github.com/gradido/gradido/pull/2762)
#### [1.19.0](https://github.com/gradido/gradido/compare/1.18.2...1.19.0)
> 7 March 2023
- chore(release): version 1.19.0 [`#2786`](https://github.com/gradido/gradido/pull/2786)
- fix(frontend): change contribution design [`#2731`](https://github.com/gradido/gradido/pull/2731)
- refactor(frontend): commnity navbar- & unauthenticated b-gradido styles [`#2732`](https://github.com/gradido/gradido/pull/2732)
- fix(database): change downwards migration to delete entries with last_announced_at IS NULL [`#2767`](https://github.com/gradido/gradido/pull/2767)
- feat(admin): deleted contributions visible [`#2759`](https://github.com/gradido/gradido/pull/2759)
- feat(other): e2e test user story user registration [`#2753`](https://github.com/gradido/gradido/pull/2753)
- refactor(frontend): style and design changes to a contribution [`#2648`](https://github.com/gradido/gradido/pull/2648)
- test(backend): add tests that ``sendContributionDeleted`` and ``sendContributionDenied`` are called [`#2740`](https://github.com/gradido/gradido/pull/2740)
- fix(backend): set email tls true in test [`#2763`](https://github.com/gradido/gradido/pull/2763)
- refactor(frontend): add visible event an answer question [`#2750`](https://github.com/gradido/gradido/pull/2750)
- refactor(frontend): style sidebar, add icons [`#2737`](https://github.com/gradido/gradido/pull/2737)
- fix(backend): possible flaky test [`#2761`](https://github.com/gradido/gradido/pull/2761)
- fix(backend): emails adjust namings of menus to new design [`#2756`](https://github.com/gradido/gradido/pull/2756)
- ci(other): rename dht node and federation workflow jobs for better branch protection maintenance [`#2743`](https://github.com/gradido/gradido/pull/2743)
- refactor(backend): combine logic for `listTransactionLinks` & `listTransactionLinksAdmin` [`#2706`](https://github.com/gradido/gradido/pull/2706)
- refactor(backend): remove admin create contributions [`#2724`](https://github.com/gradido/gradido/pull/2724)
- refactor(frontend): remove .vue as imports [`#2725`](https://github.com/gradido/gradido/pull/2725)
- feat(federation): add dht-node to deployment scripts [`#2729`](https://github.com/gradido/gradido/pull/2729)
- fix(frontend): change fetchPolicy, add scripts.update [`#2718`](https://github.com/gradido/gradido/pull/2718)
- refactor(backend): list unconfirmed contribution to admin list all contribution [`#2666`](https://github.com/gradido/gradido/pull/2666)
- refactor(frontend): community routes [`#2721`](https://github.com/gradido/gradido/pull/2721)
- test(backend): authentication tests for TransactionLinkResolver [`#2705`](https://github.com/gradido/gradido/pull/2705)
- refactor(backend): use LogError on errors [`#2679`](https://github.com/gradido/gradido/pull/2679)
- refactor(backend): use LogError on encryptorUtils [`#2678`](https://github.com/gradido/gradido/pull/2678)
- refactor(backend): use LogError on creations [`#2677`](https://github.com/gradido/gradido/pull/2677)
- refactor(other): decrease docker build dependencies in test workflow [`#2719`](https://github.com/gradido/gradido/pull/2719)
- refactor(backend): unit test for the method denyContribution [`#2639`](https://github.com/gradido/gradido/pull/2639)
- refactor(frontend): logo inserted with better quality. [`#2646`](https://github.com/gradido/gradido/pull/2646)
- feat(federation): harmonize and sync modules and data of federation [`#2665`](https://github.com/gradido/gradido/pull/2665)
- feat(federation): add docker and github-workflow files [`#2680`](https://github.com/gradido/gradido/pull/2680)
- feat(other): e2e test user authentication reset password [`#2644`](https://github.com/gradido/gradido/pull/2644)
- refactor(admin): add tabs for all statusus on contributions [`#2623`](https://github.com/gradido/gradido/pull/2623)
- feat(federation): implement a graphql client to request getpublickey [`#2511`](https://github.com/gradido/gradido/pull/2511)
- refactor(frontend): style refactor mobil auth area [`#2643`](https://github.com/gradido/gradido/pull/2643)
- refactor(backend): use LogError on TransactionResolver [`#2676`](https://github.com/gradido/gradido/pull/2676)
- refactor(backend): event protocol rework [`#2691`](https://github.com/gradido/gradido/pull/2691)
- refactor(backend): use LogError on TransactionLinkResolver [`#2673`](https://github.com/gradido/gradido/pull/2673)
- fix(frontend): simple disabled function on submit send [`#2647`](https://github.com/gradido/gradido/pull/2647)
- refactor(frontend): missing message on old transactions [`#2660`](https://github.com/gradido/gradido/pull/2660)
- refactor(admin): remove overview and multi creation menu entry [`#2661`](https://github.com/gradido/gradido/pull/2661)
- feat(other): add locales check to backend and integrate it to test workflow [`#2693`](https://github.com/gradido/gradido/pull/2693)
- refactor(other): add linting rules like in backend modul [`#2695`](https://github.com/gradido/gradido/pull/2695)
- refactor(backend): use LogError on contributionResolver [`#2669`](https://github.com/gradido/gradido/pull/2669)
#### [1.18.2](https://github.com/gradido/gradido/compare/1.18.1...1.18.2)
> 10 February 2023
- chore(release): version 1.18.2 [`#2700`](https://github.com/gradido/gradido/pull/2700)
- fix(admin): deny contribution button to left [`#2699`](https://github.com/gradido/gradido/pull/2699)
#### [1.18.1](https://github.com/gradido/gradido/compare/1.18.0...1.18.1)

View File

@ -1,11 +1,17 @@
module.exports = {
verbose: true,
collectCoverage: true,
collectCoverageFrom: [
'src/**/*.{js,vue}',
'!**/node_modules/**',
'!src/assets/**',
'!**/?(*.)+(spec|test).js?(x)',
],
coverageThreshold: {
global: {
lines: 97,
},
},
moduleFileExtensions: [
'js',
// 'jsx',

View File

@ -3,7 +3,7 @@
"description": "Administraion Interface for Gradido",
"main": "index.js",
"author": "Moriz Wahl",
"version": "1.18.2",
"version": "1.19.1",
"license": "Apache-2.0",
"private": false,
"scripts": {
@ -14,7 +14,7 @@
"analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json",
"lint": "eslint --max-warnings=0 --ext .js,.vue,.json .",
"stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'",
"test": "cross-env TZ=UTC jest --coverage",
"test": "cross-env TZ=UTC jest",
"locales": "scripts/sort.sh"
},
"dependencies": {

View File

@ -6,7 +6,7 @@
</template>
<script>
import defaultLayout from '@/layouts/defaultLayout.vue'
import defaultLayout from '@/layouts/defaultLayout'
export default {
name: 'app',

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import ChangeUserRoleFormular from './ChangeUserRoleFormular.vue'
import ChangeUserRoleFormular from './ChangeUserRoleFormular'
import { setUserRole } from '../graphql/setUserRole'
import { toastSuccessSpy, toastErrorSpy } from '../../test/testSetup'

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import ConfirmRegisterMailFormular from './ConfirmRegisterMailFormular.vue'
import ConfirmRegisterMailFormular from './ConfirmRegisterMailFormular'
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import ContributionLink from './ContributionLink.vue'
import ContributionLink from './ContributionLink'
const localVue = global.localVue

View File

@ -43,8 +43,8 @@
</div>
</template>
<script>
import ContributionLinkForm from '../ContributionLink/ContributionLinkForm.vue'
import ContributionLinkList from '../ContributionLink/ContributionLinkList.vue'
import ContributionLinkForm from '../ContributionLink/ContributionLinkForm'
import ContributionLinkList from '../ContributionLink/ContributionLinkList'
export default {
name: 'ContributionLink',

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import ContributionLinkForm from './ContributionLinkForm.vue'
import ContributionLinkForm from './ContributionLinkForm'
import { toastErrorSpy, toastSuccessSpy } from '../../../test/testSetup'
import { createContributionLink } from '@/graphql/createContributionLink.js'

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import ContributionLinkList from './ContributionLinkList.vue'
import ContributionLinkList from './ContributionLinkList'
import { toastSuccessSpy, toastErrorSpy } from '../../../test/testSetup'
// import { deleteContributionLink } from '../graphql/deleteContributionLink'

View File

@ -46,7 +46,7 @@
</template>
<script>
import { deleteContributionLink } from '@/graphql/deleteContributionLink.js'
import FigureQrCode from '../FigureQrCode.vue'
import FigureQrCode from '../FigureQrCode'
export default {
name: 'ContributionLinkList',

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import ContributionMessagesFormular from './ContributionMessagesFormular.vue'
import ContributionMessagesFormular from './ContributionMessagesFormular'
import { toastErrorSpy, toastSuccessSpy } from '../../../test/testSetup'
const localVue = global.localVue

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import ContributionMessagesList from './ContributionMessagesList.vue'
import ContributionMessagesList from './ContributionMessagesList'
const localVue = global.localVue
@ -10,6 +10,7 @@ describe('ContributionMessagesList', () => {
const propsData = {
contributionId: 42,
contributionState: 'PENDING',
}
const mocks = {

View File

@ -1,22 +1,23 @@
<template>
<div class="contribution-messages-list">
<b-container>
{{ messages.lenght }}
<div v-for="message in messages" v-bind:key="message.id">
<contribution-messages-list-item :message="message" />
</div>
</b-container>
<contribution-messages-formular
:contributionId="contributionId"
@get-list-contribution-messages="getListContributionMessages"
@update-state="updateState"
/>
<div v-if="contributionState === 'PENDING' || contributionState === 'IN_PROGRESS'">
<contribution-messages-formular
:contributionId="contributionId"
@get-list-contribution-messages="getListContributionMessages"
@update-state="updateState"
/>
</div>
</div>
</template>
<script>
import ContributionMessagesListItem from './slots/ContributionMessagesListItem.vue'
import ContributionMessagesFormular from '../ContributionMessages/ContributionMessagesFormular.vue'
import ContributionMessagesListItem from './slots/ContributionMessagesListItem'
import ContributionMessagesFormular from '../ContributionMessages/ContributionMessagesFormular'
import { listContributionMessages } from '../../graphql/listContributionMessages.js'
export default {
@ -30,6 +31,10 @@ export default {
type: Number,
required: true,
},
contributionState: {
type: String,
required: true,
},
},
data() {
return {

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import ContributionMessagesListItem from './ContributionMessagesListItem.vue'
import ContributionMessagesListItem from './ContributionMessagesListItem'
const localVue = global.localVue

View File

@ -16,7 +16,7 @@
</div>
</template>
<script>
import ParseMessage from '@/components/ContributionMessages/ParseMessage.vue'
import ParseMessage from '@/components/ContributionMessages/ParseMessage'
export default {
name: 'ContributionMessagesListItem',

View File

@ -1,7 +1,6 @@
import { mount } from '@vue/test-utils'
import CreationFormular from './CreationFormular.vue'
import CreationFormular from './CreationFormular'
import { adminCreateContribution } from '../graphql/adminCreateContribution'
import { adminCreateContributions } from '../graphql/adminCreateContributions'
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
const localVue = global.localVue
@ -328,122 +327,6 @@ describe('CreationFormular', () => {
})
})
})
describe('mass creation with success', () => {
beforeEach(async () => {
jest.clearAllMocks()
apolloMutateMock.mockResolvedValue({
data: {
adminCreateContributions: {
success: true,
successfulContribution: ['bob@baumeister.de', 'bibi@bloxberg.de'],
failedContribution: [],
},
},
})
await wrapper.setProps({
type: 'massCreation',
creation: [200, 400, 600],
items: [{ email: 'bob@baumeister.de' }, { email: 'bibi@bloxberg.de' }],
})
await wrapper.findAll('input[type="radio"]').at(1).setChecked()
await wrapper.find('textarea').setValue('Test mass create coins')
await wrapper.find('input[type="number"]').setValue(200)
await wrapper.find('.test-submit').trigger('click')
})
it('calls the API', () => {
expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({
mutation: adminCreateContributions,
variables: {
pendingCreations: [
{
email: 'bob@baumeister.de',
creationDate: getCreationDate(1),
amount: 200,
memo: 'Test mass create coins',
},
{
email: 'bibi@bloxberg.de',
creationDate: getCreationDate(1),
amount: 200,
memo: 'Test mass create coins',
},
],
},
}),
)
})
it('updates open creations in store', () => {
expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 2)
})
it('emits remove-all-bookmark', () => {
expect(wrapper.emitted('remove-all-bookmark')).toBeTruthy()
})
})
describe('mass creation with success but all failed', () => {
beforeEach(async () => {
jest.clearAllMocks()
apolloMutateMock.mockResolvedValue({
data: {
adminCreateContributions: {
success: true,
successfulContribution: [],
failedContribution: ['bob@baumeister.de', 'bibi@bloxberg.de'],
},
},
})
await wrapper.setProps({
type: 'massCreation',
creation: [200, 400, 600],
items: [{ email: 'bob@baumeister.de' }, { email: 'bibi@bloxberg.de' }],
})
await wrapper.findAll('input[type="radio"]').at(1).setChecked()
await wrapper.find('textarea').setValue('Test mass create coins')
await wrapper.find('input[type="number"]').setValue(200)
await wrapper.find('.test-submit').trigger('click')
})
it('updates open creations in store', () => {
expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 0)
})
it('emits remove all bookmarks', () => {
expect(wrapper.emitted('remove-all-bookmark')).toBeTruthy()
})
it('emits toast failed creations with two emails', () => {
expect(wrapper.emitted('toast-failed-creations')).toEqual([
[['bob@baumeister.de', 'bibi@bloxberg.de']],
])
})
})
describe('mass creation with error', () => {
beforeEach(async () => {
jest.clearAllMocks()
apolloMutateMock.mockRejectedValue({
message: 'Oh no!',
})
await wrapper.setProps({
type: 'massCreation',
creation: [200, 400, 600],
items: [{ email: 'bob@baumeister.de' }, { email: 'bibi@bloxberg.de' }],
})
await wrapper.findAll('input[type="radio"]').at(1).setChecked()
await wrapper.find('textarea').setValue('Test mass create coins')
await wrapper.find('input[type="number"]').setValue(200)
await wrapper.find('.test-submit').trigger('click')
})
it('toasts an error message', () => {
expect(toastErrorSpy).toBeCalledWith('Oh no!')
})
})
})
})
})

View File

@ -86,16 +86,11 @@
</template>
<script>
import { adminCreateContribution } from '../graphql/adminCreateContribution'
import { adminCreateContributions } from '../graphql/adminCreateContributions'
import { creationMonths } from '../mixins/creationMonths'
export default {
name: 'CreationFormular',
mixins: [creationMonths],
props: {
type: {
type: String,
required: false,
},
pagetype: {
type: String,
required: false,
@ -140,78 +135,38 @@ export default {
updateRadioSelected(name) {
// do we want to reset the memo everytime the month changes?
this.text = this.$t('creation_form.creation_for') + ' ' + name.short + ' ' + name.year
if (this.type === 'singleCreation') {
this.rangeMin = 0
this.rangeMax = name.creation
}
this.rangeMin = 0
this.rangeMax = name.creation
},
submitCreation() {
let submitObj = []
if (this.type === 'massCreation') {
this.items.forEach((item) => {
submitObj.push({
email: item.email,
this.$apollo
.mutate({
mutation: adminCreateContribution,
variables: {
email: this.item.email,
creationDate: this.selected.date,
amount: Number(this.value),
memo: this.text,
})
},
})
.then((result) => {
this.$emit('update-user-data', this.item, result.data.adminCreateContribution)
this.$store.commit('openCreationsPlus', 1)
this.toastSuccess(
this.$t('creation_form.toasted', {
value: this.value,
email: this.item.email,
}),
)
// what is this? Tests says that this.text is not reseted
this.$refs.creationForm.reset()
this.value = 0
})
.catch((error) => {
this.toastError(error.message)
this.$refs.creationForm.reset()
this.value = 0
})
this.$apollo
.mutate({
mutation: adminCreateContributions,
variables: {
pendingCreations: submitObj,
},
fetchPolicy: 'no-cache',
})
.then((result) => {
const failedContributions = []
this.$store.commit(
'openCreationsPlus',
result.data.adminCreateContributions.successfulContribution.length,
)
if (result.data.adminCreateContributions.failedContribution.length > 0) {
result.data.adminCreateContributions.failedContribution.forEach((email) => {
failedContributions.push(email)
})
}
this.$emit('remove-all-bookmark')
this.$emit('toast-failed-creations', failedContributions)
})
.catch((error) => {
this.toastError(error.message)
})
} else if (this.type === 'singleCreation') {
submitObj = {
email: this.item.email,
creationDate: this.selected.date,
amount: Number(this.value),
memo: this.text,
}
this.$apollo
.mutate({
mutation: adminCreateContribution,
variables: submitObj,
})
.then((result) => {
this.$emit('update-user-data', this.item, result.data.adminCreateContribution)
this.$store.commit('openCreationsPlus', 1)
this.toastSuccess(
this.$t('creation_form.toasted', {
value: this.value,
email: this.item.email,
}),
)
// what is this? Tests says that this.text is not reseted
this.$refs.creationForm.reset()
this.value = 0
})
.catch((error) => {
this.toastError(error.message)
this.$refs.creationForm.reset()
this.value = 0
})
}
},
},
watch: {

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import CreationTransactionList from './CreationTransactionList.vue'
import CreationTransactionList from './CreationTransactionList'
import { toastErrorSpy } from '../../test/testSetup'
const localVue = global.localVue

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import DeletedUserFormular from './DeletedUserFormular.vue'
import DeletedUserFormular from './DeletedUserFormular'
import { deleteUser } from '../graphql/deleteUser'
import { unDeleteUser } from '../graphql/unDeleteUser'
import { toastErrorSpy } from '../../test/testSetup'

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import EditCreationFormular from './EditCreationFormular.vue'
import EditCreationFormular from './EditCreationFormular'
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
const localVue = global.localVue

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import FigureQrCode from './FigureQrCode.vue'
import FigureQrCode from './FigureQrCode'
const localVue = global.localVue

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import NavBar from './NavBar.vue'
import NavBar from './NavBar'
const localVue = global.localVue
@ -68,14 +68,11 @@ describe('NavBar', () => {
})
describe('wallet', () => {
const windowLocationMock = jest.fn()
const windowLocation = window.location
beforeEach(async () => {
delete window.location
window.location = {
assign: windowLocationMock,
}
await wrapper.findAll('.nav-item').at(5).find('a').trigger('click')
window.location = ''
await wrapper.findAll('.nav-item').at(4).find('a').trigger('click')
})
afterEach(() => {
@ -83,8 +80,8 @@ describe('NavBar', () => {
window.location = windowLocation
})
it.skip('changes window location to wallet', () => {
expect(windowLocationMock()).toBe('valid-token')
it('changes window location to wallet', () => {
expect(window.location).toBe('http://localhost/authenticate?token=valid-token')
})
it('dispatches logout to store', () => {

View File

@ -1,8 +1,8 @@
<template>
<div class="component-nabvar">
<b-navbar toggleable="md" type="dark" variant="success" class="p-3">
<b-navbar-brand to="/">
<img src="img/brand/gradido_logo_w.png" class="navbar-brand-img" alt="..." />
<b-navbar toggleable="md" type="dark" variant="success">
<b-navbar-brand class="mb-2" to="/">
<img src="img/brand/gradido_logo_w.png" class="navbar-brand-img pl-2" alt="..." />
</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
@ -10,7 +10,7 @@
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item to="/user">{{ $t('navbar.user_search') }}</b-nav-item>
<b-nav-item class="bg-color-creation p-1" to="/creation-confirm">
<b-nav-item class="bg-color-creation" to="/creation-confirm">
{{ $t('creation') }}
<b-badge v-show="$store.state.openCreations > 0" variant="danger">
{{ $store.state.openCreations }}
@ -52,6 +52,5 @@ export default {
<style>
.navbar-brand-img {
height: 2rem;
padding-left: 10px;
}
</style>

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import Overlay from './Overlay.vue'
import Overlay from './Overlay'
const localVue = global.localVue

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import OpenCreationsTable from './OpenCreationsTable.vue'
import OpenCreationsTable from './OpenCreationsTable'
const localVue = global.localVue

View File

@ -13,17 +13,19 @@
<b-icon :icon="getStatusIcon(row.item.state)"></b-icon>
</template>
<template #cell(bookmark)="row">
<b-button
variant="danger"
size="md"
@click="$emit('show-overlay', row.item, 'delete')"
class="mr-2"
>
<b-icon icon="trash" variant="light"></b-icon>
</b-button>
<div v-if="!myself(row.item)">
<b-button
variant="danger"
size="md"
@click="$emit('show-overlay', row.item, 'delete')"
class="mr-2"
>
<b-icon icon="trash" variant="light"></b-icon>
</b-button>
</div>
</template>
<template #cell(editCreation)="row">
<div v-if="$store.state.moderator.id !== row.item.userId">
<div v-if="!myself(row.item)">
<b-button
v-if="row.item.moderator"
variant="info"
@ -36,30 +38,26 @@
<b-button v-else @click="rowToggleDetails(row, 0)">
<b-icon icon="chat-dots"></b-icon>
<b-icon
v-if="row.item.state === 'PENDING' && row.item.messageCount > 0"
v-if="row.item.state === 'PENDING' && row.item.messagesCount > 0"
icon="exclamation-circle-fill"
variant="warning"
></b-icon>
<b-icon
v-if="row.item.state === 'IN_PROGRESS' && row.item.messageCount > 0"
v-if="row.item.state === 'IN_PROGRESS' && row.item.messagesCount > 0"
icon="question-diamond"
variant="light"
variant="warning"
class="pl-1"
></b-icon>
</b-button>
</div>
</template>
<template #cell(reActive)>
<b-button variant="warning" size="md" class="mr-2">
<b-icon icon="arrow-up" variant="light"></b-icon>
</b-button>
</template>
<template #cell(chatCreation)="row">
<b-button v-if="row.item.messagesCount > 0" @click="rowToggleDetails(row, 0)">
<b-icon icon="chat-dots"></b-icon>
</b-button>
</template>
<template #cell(deny)="row">
<div v-if="$store.state.moderator.id !== row.item.userId">
<div v-if="!myself(row.item)">
<b-button
variant="warning"
size="md"
@ -71,7 +69,7 @@
</div>
</template>
<template #cell(confirm)="row">
<div v-if="$store.state.moderator.id !== row.item.userId">
<div v-if="!myself(row.item)">
<b-button
variant="success"
size="md"
@ -104,6 +102,7 @@
<div v-else>
<contribution-messages-list
:contributionId="row.item.id"
:contributionState="row.item.state"
@update-state="updateState"
@update-user-data="updateUserData"
/>
@ -117,9 +116,9 @@
<script>
import { toggleRowDetails } from '../../mixins/toggleRowDetails'
import RowDetails from '../RowDetails.vue'
import EditCreationFormular from '../EditCreationFormular.vue'
import ContributionMessagesList from '../ContributionMessages/ContributionMessagesList.vue'
import RowDetails from '../RowDetails'
import EditCreationFormular from '../EditCreationFormular'
import ContributionMessagesList from '../ContributionMessages/ContributionMessagesList'
const iconMap = {
IN_PROGRESS: 'question-square',
@ -158,13 +157,22 @@ export default {
}
},
methods: {
myself(item) {
return (
`${item.firstName} ${item.lastName}` ===
`${this.$store.state.moderator.firstName} ${this.$store.state.moderator.lastName}`
)
},
getStatusIcon(status) {
return iconMap[status] ? iconMap[status] : 'default-icon'
},
rowClass(item, type) {
if (!item || type !== 'row') return
if (item.state === 'CONFIRMED') return 'table-success'
if (item.state === 'DENIED') return 'table-info'
if (item.state === 'DENIED') return 'table-warning'
if (item.state === 'DELETED') return 'table-danger'
if (item.state === 'IN_PROGRESS') return 'table-primary'
if (item.state === 'PENDING') return 'table-primary'
},
updateCreationData(data) {
const row = data.row

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import SearchUserTable from './SearchUserTable.vue'
import SearchUserTable from './SearchUserTable'
const localVue = global.localVue

View File

@ -53,7 +53,6 @@
<b-tab :title="$t('creation')" active :disabled="row.item.deletedAt !== null">
<creation-formular
v-if="!row.item.deletedAt"
type="singleCreation"
pagetype="singleCreation"
:creation="row.item.creation"
:item="row.item"
@ -92,12 +91,12 @@
</div>
</template>
<script>
import CreationFormular from '../CreationFormular.vue'
import ConfirmRegisterMailFormular from '../ConfirmRegisterMailFormular.vue'
import CreationTransactionList from '../CreationTransactionList.vue'
import TransactionLinkList from '../TransactionLinkList.vue'
import ChangeUserRoleFormular from '../ChangeUserRoleFormular.vue'
import DeletedUserFormular from '../DeletedUserFormular.vue'
import CreationFormular from '../CreationFormular'
import ConfirmRegisterMailFormular from '../ConfirmRegisterMailFormular'
import CreationTransactionList from '../CreationTransactionList'
import TransactionLinkList from '../TransactionLinkList'
import ChangeUserRoleFormular from '../ChangeUserRoleFormular'
import DeletedUserFormular from '../DeletedUserFormular'
export default {
name: 'SearchUserTable',

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import StatisticTable from './StatisticTable.vue'
import StatisticTable from './StatisticTable'
const localVue = global.localVue

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import TransactionLinkList from './TransactionLinkList.vue'
import TransactionLinkList from './TransactionLinkList'
import { listTransactionLinksAdmin } from '../graphql/listTransactionLinksAdmin.js'
import { toastErrorSpy } from '../../test/testSetup'
@ -9,8 +9,8 @@ const apolloQueryMock = jest.fn()
apolloQueryMock.mockResolvedValue({
data: {
listTransactionLinksAdmin: {
linkCount: 8,
linkList: [
count: 8,
links: [
{
amount: '19.99',
code: '62ef8236ace7217fbd066c5a',

View File

@ -42,8 +42,8 @@ export default {
},
})
.then((result) => {
this.rows = result.data.listTransactionLinksAdmin.linkCount
this.items = result.data.listTransactionLinksAdmin.linkList
this.rows = result.data.listTransactionLinksAdmin.count
this.items = result.data.listTransactionLinksAdmin.links
})
.catch((error) => {
this.toastError(error.message)

View File

@ -1,7 +1,7 @@
import gql from 'graphql-tag'
export const adminCreateContributionMessage = gql`
mutation ($contributionId: Float!, $message: String!) {
mutation ($contributionId: Int!, $message: String!) {
adminCreateContributionMessage(contributionId: $contributionId, message: $message) {
id
message

View File

@ -1,11 +0,0 @@
import gql from 'graphql-tag'
export const adminCreateContributions = gql`
mutation ($pendingCreations: [AdminCreateContributionArgs!]!) {
adminCreateContributions(pendingCreations: $pendingCreations) {
success
successfulContribution
failedContribution
}
}
`

View File

@ -1,13 +1,13 @@
import gql from 'graphql-tag'
export const listAllContributions = gql`
export const adminListAllContributions = gql`
query (
$currentPage: Int = 1
$pageSize: Int = 25
$order: Order = DESC
$statusFilter: [ContributionStatus!]
) {
listAllContributions(
adminListAllContributions(
currentPage: $currentPage
pageSize: $pageSize
order: $order
@ -28,6 +28,8 @@ export const listAllContributions = gql`
messagesCount
deniedAt
deniedBy
deletedAt
deletedBy
}
}
}

View File

@ -1,7 +1,7 @@
import gql from 'graphql-tag'
export const listContributionMessages = gql`
query ($contributionId: Float!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) {
query ($contributionId: Int!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) {
listContributionMessages(
contributionId: $contributionId
pageSize: $pageSize

View File

@ -8,8 +8,8 @@ export const listTransactionLinksAdmin = gql`
userId: $userId
filters: { withRedeemed: true, withExpired: true, withDeleted: true }
) {
linkCount
linkList {
count
links {
id
amount
holdAvailableAmount

View File

@ -7,8 +7,8 @@
</template>
<script>
import NavBar from '@/components/NavBar.vue'
import ContentFooter from '@/components/ContentFooter.vue'
import NavBar from '@/components/NavBar'
import ContentFooter from '@/components/ContentFooter'
export default {
name: 'defaultLayout',
components: {

View File

@ -63,7 +63,6 @@
"deleted_user": "Alle gelöschten Nutzer",
"delete_user": "Nutzer löschen",
"deny": "Ablehnen",
"edit": "Bearbeiten",
"enabled": "aktiviert",
"error": "Fehler",
"expired": "abgelaufen",
@ -101,7 +100,6 @@
"message": {
"request": "Die Anfrage wurde gesendet."
},
"mod": "Mod",
"moderator": "Moderator",
"name": "Name",
"navbar": {

View File

@ -34,11 +34,11 @@
"all": "All",
"confirms": "Confirmed",
"deleted": "Deleted",
"denied": "Denied",
"denied": "Rejected",
"open": "Open"
},
"created": "Confirmed",
"createdAt": "Created",
"created": "Created for",
"createdAt": "Created at",
"creation": "Creation",
"creationList": "Creation list",
"creation_form": {
@ -53,7 +53,7 @@
"toasted": "Open creation ({value} GDD) for {email} has been saved and is ready for confirmation.",
"toasted_created": "Creation has been successfully saved",
"toasted_delete": "Open creation has been deleted",
"toasted_denied": "Open creation has been denied",
"toasted_denied": "Open creation has been rejected",
"toasted_update": "Open creation {value} GDD) for {email} has been changed and is ready for confirmation.",
"update_creation": "Creation update"
},
@ -63,7 +63,6 @@
"deleted_user": "All deleted user",
"delete_user": "Delete user",
"deny": "Reject",
"edit": "Edit",
"enabled": "enabled",
"error": "Error",
"expired": "expired",
@ -87,7 +86,7 @@
"transactionlist": {
"confirmed": "When was it confirmed by a moderator / admin.",
"periods": "For what period was it submitted by the member.",
"state": "[PENDING = submitted, DELETED = deleted, IN_PROGRESS = in dialogue with moderator, DENIED = denied, CONFIRMED = confirmed]",
"state": "[PENDING = submitted, DELETED = deleted, IN_PROGRESS = in dialogue with moderator, DENIED = rejected, CONFIRMED = confirmed]",
"submitted": "When was it submitted by the member"
}
},
@ -101,7 +100,6 @@
"message": {
"request": "Request has been sent."
},
"mod": "Mod",
"moderator": "Moderator",
"name": "Name",
"navbar": {

View File

@ -1,5 +1,5 @@
import Vue from 'vue'
import App from './App.vue'
import App from './App'
// without this async calls are not working
import 'regenerator-runtime'

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import CommunityStatistic from './CommunityStatistic.vue'
import CommunityStatistic from './CommunityStatistic'
import { communityStatistics } from '@/graphql/communityStatistics.js'
import { toastErrorSpy } from '../../test/testSetup'
import VueApollo from 'vue-apollo'

View File

@ -5,7 +5,7 @@
</template>
<script>
import { communityStatistics } from '@/graphql/communityStatistics.js'
import StatisticTable from '../components/Tables/StatisticTable.vue'
import StatisticTable from '../components/Tables/StatisticTable'
export default {
name: 'CommunityStatistic',

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import ContributionLinks from './ContributionLinks.vue'
import ContributionLinks from './ContributionLinks'
import { listContributionLinks } from '@/graphql/listContributionLinks.js'
import { toastErrorSpy } from '../../test/testSetup'

View File

@ -9,7 +9,7 @@
</template>
<script>
import { listContributionLinks } from '@/graphql/listContributionLinks.js'
import ContributionLink from '../components/ContributionLink/ContributionLink.vue'
import ContributionLink from '../components/ContributionLink/ContributionLink'
export default {
name: 'ContributionLinks',

View File

@ -1,8 +1,8 @@
import { mount } from '@vue/test-utils'
import CreationConfirm from './CreationConfirm.vue'
import CreationConfirm from './CreationConfirm'
import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
import { denyContribution } from '../graphql/denyContribution'
import { listAllContributions } from '../graphql/listAllContributions'
import { adminListAllContributions } from '../graphql/adminListAllContributions'
import { confirmContribution } from '../graphql/confirmContribution'
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
import VueApollo from 'vue-apollo'
@ -38,7 +38,7 @@ const mocks = {
const defaultData = () => {
return {
listAllContributions: {
adminListAllContributions: {
contributionCount: 2,
contributionList: [
{
@ -92,14 +92,14 @@ const defaultData = () => {
describe('CreationConfirm', () => {
let wrapper
const adminListAllContributionsMock = jest.fn()
const adminDeleteContributionMock = jest.fn()
const adminDenyContributionMock = jest.fn()
const confirmContributionMock = jest.fn()
mockClient.setRequestHandler(
listAllContributions,
jest
.fn()
adminListAllContributions,
adminListAllContributionsMock
.mockRejectedValueOnce({ message: 'Ouch!' })
.mockResolvedValue({ data: defaultData() }),
)
@ -331,78 +331,82 @@ describe('CreationConfirm', () => {
describe('filter tabs', () => {
describe('click tab "confirmed"', () => {
let refetchSpy
beforeEach(async () => {
jest.clearAllMocks()
refetchSpy = jest.spyOn(wrapper.vm.$apollo.queries.ListAllContributions, 'refetch')
await wrapper.find('a[data-test="confirmed"]').trigger('click')
})
it('has statusFilter set to ["CONFIRMED"]', () => {
expect(
wrapper.vm.$apollo.queries.ListAllContributions.observer.options.variables,
).toMatchObject({ statusFilter: ['CONFIRMED'] })
})
it('refetches contributions', () => {
expect(refetchSpy).toBeCalled()
it('refetches contributions with proper filter', () => {
expect(adminListAllContributionsMock).toBeCalledWith({
currentPage: 1,
order: 'DESC',
pageSize: 25,
statusFilter: ['CONFIRMED'],
})
})
describe('click tab "open"', () => {
beforeEach(async () => {
jest.clearAllMocks()
refetchSpy = jest.spyOn(wrapper.vm.$apollo.queries.ListAllContributions, 'refetch')
await wrapper.find('a[data-test="open"]').trigger('click')
})
it('has statusFilter set to ["IN_PROGRESS", "PENDING"]', () => {
expect(
wrapper.vm.$apollo.queries.ListAllContributions.observer.options.variables,
).toMatchObject({ statusFilter: ['IN_PROGRESS', 'PENDING'] })
})
it('refetches contributions', () => {
expect(refetchSpy).toBeCalled()
it('refetches contributions with proper filter', () => {
expect(adminListAllContributionsMock).toBeCalledWith({
currentPage: 1,
order: 'DESC',
pageSize: 25,
statusFilter: ['IN_PROGRESS', 'PENDING'],
})
})
})
describe('click tab "denied"', () => {
beforeEach(async () => {
jest.clearAllMocks()
refetchSpy = jest.spyOn(wrapper.vm.$apollo.queries.ListAllContributions, 'refetch')
await wrapper.find('a[data-test="denied"]').trigger('click')
})
it('has statusFilter set to ["DENIED"]', () => {
expect(
wrapper.vm.$apollo.queries.ListAllContributions.observer.options.variables,
).toMatchObject({ statusFilter: ['DENIED'] })
it('refetches contributions with proper filter', () => {
expect(adminListAllContributionsMock).toBeCalledWith({
currentPage: 1,
order: 'DESC',
pageSize: 25,
statusFilter: ['DENIED'],
})
})
})
describe('click tab "deleted"', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.find('a[data-test="deleted"]').trigger('click')
})
it('refetches contributions', () => {
expect(refetchSpy).toBeCalled()
it('refetches contributions with proper filter', () => {
expect(adminListAllContributionsMock).toBeCalledWith({
currentPage: 1,
order: 'DESC',
pageSize: 25,
statusFilter: ['DELETED'],
})
})
})
describe('click tab "all"', () => {
beforeEach(async () => {
jest.clearAllMocks()
refetchSpy = jest.spyOn(wrapper.vm.$apollo.queries.ListAllContributions, 'refetch')
await wrapper.find('a[data-test="all"]').trigger('click')
})
it('has statusFilter set to ["IN_PROGRESS", "PENDING", "CONFIRMED", "DENIED", "DELETED"]', () => {
expect(
wrapper.vm.$apollo.queries.ListAllContributions.observer.options.variables,
).toMatchObject({
it('refetches contributions with proper filter', () => {
expect(adminListAllContributionsMock).toBeCalledWith({
currentPage: 1,
order: 'DESC',
pageSize: 25,
statusFilter: ['IN_PROGRESS', 'PENDING', 'CONFIRMED', 'DENIED', 'DELETED'],
})
})
it('refetches contributions', () => {
expect(refetchSpy).toBeCalled()
})
})
})
})
@ -412,10 +416,20 @@ describe('CreationConfirm', () => {
await wrapper.findComponent({ name: 'OpenCreationsTable' }).vm.$emit('update-state', 2)
})
it.skip('updates the status', () => {
it('updates the status', () => {
expect(wrapper.vm.items.find((obj) => obj.id === 2).messagesCount).toBe(1)
expect(wrapper.vm.items.find((obj) => obj.id === 2).state).toBe('IN_PROGRESS')
})
})
describe('unknown variant', () => {
beforeEach(async () => {
await wrapper.setData({ variant: 'unknown' })
})
it('has overlay icon "info"', () => {
expect(wrapper.vm.overlayIcon).toBe('info')
})
})
})
})

View File

@ -5,25 +5,37 @@
<b-tabs v-model="tabIndex" content-class="mt-3" fill>
<b-tab active :title-link-attributes="{ 'data-test': 'open' }">
<template #title>
<b-icon icon="bell-fill" variant="primary"></b-icon>
{{ $t('contributions.open') }}
<b-badge v-if="$store.state.openCreations > 0" variant="danger">
{{ $store.state.openCreations }}
</b-badge>
</template>
</b-tab>
<b-tab
:title="$t('contributions.confirms')"
:title-link-attributes="{ 'data-test': 'confirmed' }"
/>
<b-tab
:title="$t('contributions.denied')"
:title-link-attributes="{ 'data-test': 'denied' }"
/>
<b-tab
:title="$t('contributions.deleted')"
:title-link-attributes="{ 'data-test': 'deleted' }"
/>
<b-tab :title="$t('contributions.all')" :title-link-attributes="{ 'data-test': 'all' }" />
<b-tab :title-link-attributes="{ 'data-test': 'confirmed' }">
<template #title>
<b-icon icon="check" variant="success"></b-icon>
{{ $t('contributions.confirms') }}
</template>
</b-tab>
<b-tab :title-link-attributes="{ 'data-test': 'denied' }">
<template #title>
<b-icon icon="x-circle" variant="warning"></b-icon>
{{ $t('contributions.denied') }}
</template>
</b-tab>
<b-tab :title-link-attributes="{ 'data-test': 'deleted' }">
<template #title>
<b-icon icon="trash" variant="danger"></b-icon>
{{ $t('contributions.deleted') }}
</template>
</b-tab>
<b-tab :title-link-attributes="{ 'data-test': 'all' }">
<template #title>
<b-icon icon="list"></b-icon>
{{ $t('contributions.all') }}
</template>
</b-tab>
</b-tabs>
</div>
<open-creations-table
@ -71,9 +83,9 @@
</div>
</template>
<script>
import Overlay from '../components/Overlay.vue'
import OpenCreationsTable from '../components/Tables/OpenCreationsTable.vue'
import { listAllContributions } from '../graphql/listAllContributions'
import Overlay from '../components/Overlay'
import OpenCreationsTable from '../components/Tables/OpenCreationsTable'
import { adminListAllContributions } from '../graphql/adminListAllContributions'
import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
import { confirmContribution } from '../graphql/confirmContribution'
import { denyContribution } from '../graphql/denyContribution'
@ -172,19 +184,17 @@ export default {
this.items.find((obj) => obj.id === id).messagesCount++
this.items.find((obj) => obj.id === id).state = 'IN_PROGRESS'
},
},
watch: {
statusFilter() {
this.$apollo.queries.ListAllContributions.refetch()
formatDateOrDash(value) {
return value ? this.$d(new Date(value), 'short') : '—'
},
},
computed: {
fields() {
return [
[
// open contributions
{ key: 'bookmark', label: this.$t('delete') },
{ key: 'deny', label: this.$t('deny') },
{ key: 'email', label: this.$t('e_mail') },
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
@ -199,14 +209,15 @@ export default {
key: 'contributionDate',
label: this.$t('created'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{ key: 'moderator', label: this.$t('moderator') },
{ key: 'editCreation', label: this.$t('edit') },
{ key: 'editCreation', label: this.$t('chat') },
{ key: 'confirm', label: this.$t('save') },
],
[
// confirmed contributions
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
@ -221,27 +232,28 @@ export default {
key: 'contributionDate',
label: this.$t('created'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{
key: 'createdAt',
label: this.$t('createdAt'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{
key: 'confirmedAt',
label: this.$t('contributions.confirms'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{ key: 'confirmedBy', label: this.$t('moderator') },
{ key: 'chatCreation', label: this.$t('chat') },
],
[
{ key: 'reActive', label: 'reActive' },
// denied contributions
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
@ -256,29 +268,28 @@ export default {
key: 'contributionDate',
label: this.$t('created'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{
key: 'createdAt',
label: this.$t('createdAt'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{
key: 'deniedAt',
label: this.$t('contributions.denied'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{ key: 'deniedBy', label: this.$t('mod') },
{ key: 'deniedBy', label: this.$t('moderator') },
{ key: 'chatCreation', label: this.$t('chat') },
],
[],
[
{ key: 'state', label: 'state' },
// deleted contributions
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
@ -293,24 +304,61 @@ export default {
key: 'contributionDate',
label: this.$t('created'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{
key: 'createdAt',
label: this.$t('createdAt'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{
key: 'deletedAt',
label: this.$t('contributions.deleted'),
formatter: (value) => {
return this.formatDateOrDash(value)
},
},
{ key: 'deletedBy', label: this.$t('moderator') },
{ key: 'chatCreation', label: this.$t('chat') },
],
[
// all contributions
{ key: 'state', label: this.$t('status') },
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
key: 'amount',
label: this.$t('creation'),
formatter: (value) => {
return value + ' GDD'
},
},
{ key: 'memo', label: this.$t('text'), class: 'text-break' },
{
key: 'contributionDate',
label: this.$t('created'),
formatter: (value) => {
return this.formatDateOrDash(value)
},
},
{
key: 'createdAt',
label: this.$t('createdAt'),
formatter: (value) => {
return this.formatDateOrDash(value)
},
},
{
key: 'confirmedAt',
label: this.$t('contributions.confirms'),
formatter: (value) => {
return this.$d(new Date(value), 'short')
return this.formatDateOrDash(value)
},
},
{ key: 'confirmedBy', label: this.$t('mod') },
{ key: 'confirmedBy', label: this.$t('moderator') },
{ key: 'chatCreation', label: this.$t('chat') },
],
][this.tabIndex]
@ -349,19 +397,22 @@ export default {
apollo: {
ListAllContributions: {
query() {
return listAllContributions
return adminListAllContributions
},
variables() {
// may be at some point we need a pagination here
return {
currentPage: this.currentPage,
pageSize: this.pageSize,
statusFilter: this.statusFilter,
}
},
update({ listAllContributions }) {
this.rows = listAllContributions.contributionCount
this.items = listAllContributions.contributionList
fetchPolicy: 'no-cache',
update({ adminListAllContributions }) {
this.rows = adminListAllContributions.contributionCount
this.items = adminListAllContributions.contributionList
if (this.statusFilter === FILTER_TAB_MAP[0]) {
this.$store.commit('setOpenCreations', adminListAllContributions.contributionCount)
}
},
error({ message }) {
this.toastError(message)

View File

@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils'
import Overview from './Overview.vue'
import { listAllContributions } from '../graphql/listAllContributions'
import Overview from './Overview'
import { adminListAllContributions } from '../graphql/adminListAllContributions'
import VueApollo from 'vue-apollo'
import { createMockClient } from 'mock-apollo-client'
import { toastErrorSpy } from '../../test/testSetup'
@ -30,7 +30,7 @@ const mocks = {
const defaultData = () => {
return {
listAllContributions: {
adminListAllContributions: {
contributionCount: 2,
contributionList: [
{
@ -84,11 +84,11 @@ const defaultData = () => {
describe('Overview', () => {
let wrapper
const listAllContributionsMock = jest.fn()
const adminListAllContributionsMock = jest.fn()
mockClient.setRequestHandler(
listAllContributions,
listAllContributionsMock
adminListAllContributions,
adminListAllContributionsMock
.mockRejectedValueOnce({ message: 'Ouch!' })
.mockResolvedValue({ data: defaultData() }),
)
@ -109,8 +109,8 @@ describe('Overview', () => {
})
})
it('calls the listAllContributions query', () => {
expect(listAllContributionsMock).toBeCalledWith({
it('calls the adminListAllContributions query', () => {
expect(adminListAllContributionsMock).toBeCalledWith({
currentPage: 1,
order: 'DESC',
pageSize: 25,

View File

@ -31,7 +31,7 @@
</div>
</template>
<script>
import { listAllContributions } from '../graphql/listAllContributions'
import { adminListAllContributions } from '../graphql/adminListAllContributions'
export default {
name: 'overview',
@ -43,7 +43,7 @@ export default {
apollo: {
AllContributions: {
query() {
return listAllContributions
return adminListAllContributions
},
variables() {
// may be at some point we need a pagination here
@ -51,8 +51,8 @@ export default {
statusFilter: this.statusFilter,
}
},
update({ listAllContributions }) {
this.$store.commit('setOpenCreations', listAllContributions.contributionCount)
update({ adminListAllContributions }) {
this.$store.commit('setOpenCreations', adminListAllContributions.contributionCount)
},
error({ message }) {
this.toastError(message)

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import UserSearch from './UserSearch.vue'
import UserSearch from './UserSearch'
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
const localVue = global.localVue

View File

@ -58,7 +58,7 @@
</div>
</template>
<script>
import SearchUserTable from '../components/Tables/SearchUserTable.vue'
import SearchUserTable from '../components/Tables/SearchUserTable'
import { searchUsers } from '../graphql/searchUsers'
import { creationMonths } from '../mixins/creationMonths'
@ -72,7 +72,6 @@ export default {
return {
showArrays: false,
searchResult: [],
massCreation: [],
criteria: '',
filters: {
byActivated: null,

View File

@ -24,9 +24,6 @@ export const mutations = {
moderator: (state, moderator) => {
state.moderator = moderator
},
setUserSelectedInMassCreation: (state, userSelectedInMassCreation) => {
state.userSelectedInMassCreation = userSelectedInMassCreation
},
}
export const actions = {

View File

@ -10,7 +10,6 @@ const {
resetOpenCreations,
setOpenCreations,
moderator,
setUserSelectedInMassCreation,
} = mutations
const { logout } = actions
@ -65,14 +64,6 @@ describe('Vuex store', () => {
expect(state.openCreations).toEqual(12)
})
})
describe('setUserSelectedInMassCreation', () => {
it('sets userSelectedInMassCreation to given value', () => {
const state = { userSelectedInMassCreation: [] }
setUserSelectedInMassCreation(state, [0, 1, 2])
expect(state.userSelectedInMassCreation).toEqual([0, 1, 2])
})
})
})
describe('actions', () => {

View File

@ -1,5 +1,5 @@
# Server
JWT_EXPIRES_IN=1m
JWT_EXPIRES_IN=2m
# Email
EMAIL=true

View File

@ -2,16 +2,10 @@ module.exports = {
root: true,
env: {
node: true,
// jest: true,
},
parser: '@typescript-eslint/parser',
plugins: ['prettier', '@typescript-eslint' /*, 'jest' */],
extends: [
'standard',
'eslint:recommended',
'plugin:prettier/recommended',
'plugin:@typescript-eslint/recommended',
],
plugins: ['prettier', '@typescript-eslint', 'type-graphql'],
extends: ['standard', 'eslint:recommended', 'plugin:prettier/recommended'],
// add your custom rules here
rules: {
'no-console': ['error'],
@ -23,4 +17,28 @@ module.exports = {
},
],
},
overrides: [
// only for ts files
{
files: ['*.ts'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:type-graphql/recommended',
],
rules: {
// allow explicitly defined dangling promises
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
'no-void': ['error', { allowAsStatement: true }],
// ignore prefer-regexp-exec rule to allow string.match(regex)
'@typescript-eslint/prefer-regexp-exec': 'off',
},
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
// this is to properly reference the referenced project database without requirement of compiling it
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
},
},
],
}

View File

@ -4,6 +4,11 @@ module.exports = {
preset: 'ts-jest',
collectCoverage: true,
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
coverageThreshold: {
global: {
lines: 80,
},
},
setupFiles: ['<rootDir>/test/testSetup.ts'],
setupFilesAfterEnv: ['<rootDir>/test/extensions.ts'],
modulePathIgnorePatterns: ['<rootDir>/build/'],

View File

@ -1,6 +1,6 @@
{
"name": "gradido-backend",
"version": "1.18.2",
"version": "1.19.1",
"description": "Gradido unified backend providing an API-Service for Gradido Transactions",
"main": "src/index.ts",
"repository": "https://github.com/gradido/gradido/backend",
@ -13,7 +13,7 @@
"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",
"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",
"klicktipp": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/util/klicktipp.ts",
"locales": "scripts/sort.sh"
@ -65,6 +65,7 @@
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-type-graphql": "^1.0.0",
"faker": "^5.5.3",
"jest": "^27.2.4",
"nodemon": "^2.0.7",

View File

@ -1,16 +1,19 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import axios from 'axios'
import { backendLogger as logger } from '@/server/logger'
import LogError from '@/server/LogError'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const apiPost = async (url: string, payload: unknown): Promise<any> => {
logger.trace('POST: url=' + url + ' payload=' + payload)
logger.trace('POST', url, payload)
return axios
.post(url, payload)
.then((result) => {
logger.trace('POST-Response: result=' + result)
logger.trace('POST-Response', result)
if (result.status !== 200) {
throw new Error('HTTP Status Error ' + result.status)
throw new LogError('HTTP Status Error', result.status)
}
if (result.data.state !== 'success') {
throw new Error(result.data.msg)
@ -28,9 +31,9 @@ export const apiGet = async (url: string): Promise<any> => {
return axios
.get(url)
.then((result) => {
logger.trace('GET-Response: result=' + result)
logger.trace('GET-Response', result)
if (result.status !== 200) {
throw new Error('HTTP Status Error ' + result.status)
throw new LogError('HTTP Status Error', result.status)
}
if (!['success', 'warning'].includes(result.data.state)) {
throw new Error(result.data.msg)

View File

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { KlicktippConnector } from './klicktippConnector'

View File

@ -1,3 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import axios, { AxiosRequestConfig, Method } from 'axios'

View File

@ -42,7 +42,6 @@ export enum RIGHTS {
DELETE_USER = 'DELETE_USER',
UNDELETE_USER = 'UNDELETE_USER',
ADMIN_CREATE_CONTRIBUTION = 'ADMIN_CREATE_CONTRIBUTION',
ADMIN_CREATE_CONTRIBUTIONS = 'ADMIN_CREATE_CONTRIBUTIONS',
ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION',
ADMIN_DELETE_CONTRIBUTION = 'ADMIN_DELETE_CONTRIBUTION',
LIST_UNCONFIRMED_CONTRIBUTIONS = 'LIST_UNCONFIRMED_CONTRIBUTIONS',
@ -55,4 +54,5 @@ export enum RIGHTS {
UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK',
ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE',
DENY_CONTRIBUTION = 'DENY_CONTRIBUTION',
ADMIN_OPEN_CREATIONS = 'ADMIN_OPEN_CREATIONS',
}

View File

@ -10,7 +10,7 @@ Decimal.set({
})
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
LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info

View File

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/unbound-method */
import { createTransport } from 'nodemailer'
import { logger, i18n } from '@test/testSetup'
import CONFIG from '@/config'
@ -8,6 +10,7 @@ CONFIG.EMAIL_SMTP_URL = 'EMAIL_SMTP_URL'
CONFIG.EMAIL_SMTP_PORT = '1234'
CONFIG.EMAIL_USERNAME = 'user'
CONFIG.EMAIL_PASSWORD = 'pwd'
CONFIG.EMAIL_TLS = true
jest.mock('nodemailer', () => {
return {

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import CONFIG from '@/config'
import { backendLogger as logger } from '@/server/logger'
import path from 'path'

View File

@ -1,5 +1,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import Decimal from 'decimal.js-light'
import { testEnvironment } from '@test/helpers'
import { logger, i18n as localization } from '@test/testSetup'
@ -106,7 +109,7 @@ describe('sendEmailVariants', () => {
'you have received a message from Bibi Bloxberg regarding your common good contribution “My contribution.”.',
)
expect(result.originalMessage.html).toContain(
'To view and reply to the message, go to the “Community” menu in your Gradido account and click on the “My contributions to the common good” tab!',
'To view and reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab!',
)
expect(result.originalMessage.html).toContain(
`Link to your account: <a href="${CONFIG.EMAIL_LINK_OVERVIEW}">${CONFIG.EMAIL_LINK_OVERVIEW}</a>`,
@ -424,7 +427,7 @@ describe('sendEmailVariants', () => {
'Your public good contribution “My contribution.” was rejected by Bibi Bloxberg.',
)
expect(result.originalMessage.html).toContain(
'To see your common good contributions and related messages, go to the “Community” menu in your Gradido account and click on the “My contributions to the common good” tab!',
'To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab!',
)
expect(result.originalMessage.html).toContain(
`Link to your account: <a href="${CONFIG.EMAIL_LINK_OVERVIEW}">${CONFIG.EMAIL_LINK_OVERVIEW}</a>`,
@ -502,7 +505,7 @@ describe('sendEmailVariants', () => {
'Your public good contribution “My contribution.” was deleted by Bibi Bloxberg.',
)
expect(result.originalMessage.html).toContain(
'To see your common good contributions and related messages, go to the “Community” menu in your Gradido account and click on the “My contributions to the common good” tab!',
'To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab!',
)
expect(result.originalMessage.html).toContain(
`Link to your account: <a href="${CONFIG.EMAIL_LINK_OVERVIEW}">${CONFIG.EMAIL_LINK_OVERVIEW}</a>`,

View File

@ -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 { EventProtocolType } from './EventProtocolType'
export const Event = (
type: EventProtocolType,
userId: number,
xUserId: number | null = null,
xCommunityId: number | null = null,
transactionId: number | null = null,
contributionId: number | null = null,
affectedUser: DbUser,
actingUser: DbUser,
involvedUser: DbUser | null = null,
involvedTransaction: DbTransaction | null = null,
involvedContribution: DbContribution | null = null,
involvedContributionMessage: DbContributionMessage | null = null,
amount: Decimal | null = null,
messageId: number | null = null,
): DbEvent => {
const event = new DbEvent()
event.type = type
event.userId = userId
event.xUserId = xUserId
event.xCommunityId = xCommunityId
event.transactionId = transactionId
event.contributionId = contributionId
event.affectedUser = affectedUser
event.actingUser = actingUser
event.involvedUser = involvedUser
event.involvedTransaction = involvedTransaction
event.involvedContribution = involvedContribution
event.involvedContributionMessage = involvedContributionMessage
event.amount = amount
event.messageId = messageId
return event
}
export const EVENT_CONTRIBUTION_CREATE = async (
userId: number,
contributionId: number,
user: DbUser,
contribution: DbContribution,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.CONTRIBUTION_CREATE,
userId,
user,
user,
null,
null,
contribution,
null,
contributionId,
amount,
).save()
export const EVENT_CONTRIBUTION_DELETE = async (
userId: number,
contributionId: number,
user: DbUser,
contribution: DbContribution,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.CONTRIBUTION_DELETE,
userId,
user,
user,
null,
null,
contribution,
null,
contributionId,
amount,
).save()
export const EVENT_CONTRIBUTION_UPDATE = async (
userId: number,
contributionId: number,
user: DbUser,
contribution: DbContribution,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.CONTRIBUTION_UPDATE,
userId,
user,
user,
null,
null,
contribution,
null,
contributionId,
amount,
).save()
export const EVENT_ADMIN_CONTRIBUTION_CREATE = async (
userId: number,
contributionId: number,
user: DbUser,
moderator: DbUser,
contribution: DbContribution,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
userId,
user,
moderator,
null,
null,
contribution,
null,
contributionId,
amount,
).save()
export const EVENT_ADMIN_CONTRIBUTION_UPDATE = async (
userId: number,
contributionId: number,
user: DbUser,
moderator: DbUser,
contribution: DbContribution,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
userId,
user,
moderator,
null,
null,
contribution,
null,
contributionId,
amount,
).save()
export const EVENT_ADMIN_CONTRIBUTION_DELETE = async (
userId: number,
contributionId: number,
user: DbUser,
moderator: DbUser,
contribution: DbContribution,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
userId,
user,
moderator,
null,
null,
contribution,
null,
contributionId,
amount,
).save()
export const EVENT_CONTRIBUTION_CONFIRM = async (
userId: number,
contributionId: number,
user: DbUser,
moderator: DbUser,
contribution: DbContribution,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.CONTRIBUTION_CONFIRM,
userId,
user,
moderator,
null,
null,
contribution,
null,
contributionId,
amount,
).save()
export const EVENT_ADMIN_CONTRIBUTION_DENY = async (
userId: number,
xUserId: number,
contributionId: number,
user: DbUser,
moderator: DbUser,
contribution: DbContribution,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.ADMIN_CONTRIBUTION_DENY,
userId,
xUserId,
user,
moderator,
null,
null,
contributionId,
contribution,
null,
amount,
).save()
export const EVENT_TRANSACTION_SEND = async (
userId: number,
xUserId: number,
transactionId: number,
user: DbUser,
involvedUser: DbUser,
transaction: DbTransaction,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.TRANSACTION_SEND,
userId,
xUserId,
user,
user,
involvedUser,
transaction,
null,
transactionId,
null,
amount,
).save()
export const EVENT_TRANSACTION_RECEIVE = async (
userId: number,
xUserId: number,
transactionId: number,
user: DbUser,
involvedUser: DbUser,
transaction: DbTransaction,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.TRANSACTION_RECEIVE,
userId,
xUserId,
user,
involvedUser,
involvedUser,
transaction,
null,
transactionId,
null,
amount,
).save()
export const EVENT_LOGIN = async (userId: number): Promise<DbEvent> =>
Event(EventProtocolType.LOGIN, userId, null, null, null, null, null, null).save()
export const EVENT_LOGIN = async (user: DbUser): Promise<DbEvent> =>
Event(EventProtocolType.LOGIN, user, user).save()
export const EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = async (
userId: number,
): Promise<DbEvent> => Event(EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, userId).save()
export const EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
Event(EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, user, { id: 0 } as DbUser).save()
export const EVENT_SEND_CONFIRMATION_EMAIL = async (userId: number): Promise<DbEvent> =>
Event(EventProtocolType.SEND_CONFIRMATION_EMAIL, userId).save()
export const EVENT_SEND_CONFIRMATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
Event(EventProtocolType.SEND_CONFIRMATION_EMAIL, user, user).save()
export const EVENT_ADMIN_SEND_CONFIRMATION_EMAIL = async (userId: number): Promise<DbEvent> =>
Event(EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL, userId).save()
export const EVENT_ADMIN_SEND_CONFIRMATION_EMAIL = async (
user: DbUser,
moderator: DbUser,
): Promise<DbEvent> =>
Event(EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL, user, moderator).save()
/* export const EVENT_REDEEM_REGISTER = async (
userId: number,
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 (user: DbUser): Promise<DbEvent> =>
Event(EventProtocolType.REGISTER, user, user).save()
export const EVENT_REGISTER = async (userId: number): Promise<DbEvent> =>
Event(EventProtocolType.REGISTER, userId).save()
export const EVENT_ACTIVATE_ACCOUNT = async (userId: number): Promise<DbEvent> =>
Event(EventProtocolType.ACTIVATE_ACCOUNT, userId).save()
export const EVENT_ACTIVATE_ACCOUNT = async (user: DbUser): Promise<DbEvent> =>
Event(EventProtocolType.ACTIVATE_ACCOUNT, user, user).save()

View File

@ -1,3 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { gql } from 'graphql-request'
import { backendLogger as logger } from '@/server/logger'
import { Community as DbCommunity } from '@entity/Community'
@ -18,9 +21,13 @@ export async function requestGetPublicKey(dbCom: DbCommunity): Promise<string |
}
}
`
const variables = {}
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)
if (data) {
logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey)

View File

@ -1,3 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { gql } from 'graphql-request'
import { backendLogger as logger } from '@/server/logger'
import { Community as DbCommunity } from '@entity/Community'
@ -18,9 +21,13 @@ export async function requestGetPublicKey(dbCom: DbCommunity): Promise<string |
}
}
`
const variables = {}
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)
if (data) {
logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey)

View File

@ -1,8 +1,14 @@
import { GraphQLClient } from 'graphql-request'
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 {
private static instance: GraphQLGetClient
private static instanceArray: ClientInstance[] = []
/**
* 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.
*/
public static getInstance(url: string): GraphQLGetClient {
if (!GraphQLGetClient.instance) {
GraphQLGetClient.instance = new GraphQLGetClient(url, {
method: 'GET',
jsonSerializer: {
parse: JSON.parse,
stringify: JSON.stringify,
},
})
const instance = GraphQLGetClient.instanceArray.find((instance) => instance.url === url)
if (instance) {
return instance.client
}
return GraphQLGetClient.instance
const client = new GraphQLGetClient(url, {
method: 'GET',
jsonSerializer: {
parse: JSON.parse,
stringify: JSON.stringify,
},
})
GraphQLGetClient.instanceArray.push({ url, client } as ClientInstance)
return client
}
}

View File

@ -1,3 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/unbound-method */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
@ -150,7 +154,8 @@ describe('validate Communities', () => {
})
it('logs unsupported api for community with api 2_0 ', () => {
expect(logger.warn).toBeCalledWith(
`Federation: dbCom: ${dbCom.id} with unsupported apiVersion=2_0; supported versions=1_0,1_1`,
`Federation: dbCom: ${dbCom.id} with unsupported apiVersion=2_0; supported versions`,
['1_0', '1_1'],
)
})
})

View File

@ -8,14 +8,14 @@ import { backendLogger as logger } from '@/server/logger'
import { ApiVersionType } from './enum/apiVersionType'
import LogError from '@/server/LogError'
export async function startValidateCommunities(timerInterval: number): Promise<void> {
export function startValidateCommunities(timerInterval: number): void {
logger.info(
`Federation: startValidateCommunities loop with an interval of ${timerInterval} ms...`,
)
// TODO: replace the timer-loop by an event-based communication to verify announced foreign communities
// better to use setTimeout twice than setInterval once -> see https://javascript.info/settimeout-setinterval
setTimeout(function run() {
validateCommunities()
void validateCommunities()
setTimeout(run, timerInterval)
}, timerInterval)
}
@ -27,8 +27,8 @@ export async function validateCommunities(): Promise<void> {
.getMany()
logger.debug(`Federation: found ${dbCommunities.length} dbCommunities`)
dbCommunities.forEach(async function (dbCom) {
logger.debug(`Federation: dbCom: ${JSON.stringify(dbCom)}`)
for (const dbCom of dbCommunities) {
logger.debug('Federation: dbCom', dbCom)
const apiValueStrings: string[] = Object.values(ApiVersionType)
logger.debug(`suppported ApiVersions=`, apiValueStrings)
if (apiValueStrings.includes(dbCom.apiVersion)) {
@ -38,19 +38,22 @@ export async function validateCommunities(): Promise<void> {
try {
const pubKey = await invokeVersionedRequestGetPublicKey(dbCom)
logger.info(
`Federation: received publicKey=${pubKey} from endpoint=${dbCom.endPoint}/${dbCom.apiVersion}`,
'Federation: received publicKey from endpoint',
pubKey,
`${dbCom.endPoint}/${dbCom.apiVersion}`,
)
if (pubKey && pubKey === dbCom.publicKey.toString('hex')) {
if (pubKey && pubKey === dbCom.publicKey.toString()) {
logger.info(`Federation: matching publicKey: ${pubKey}`)
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)}`)
} 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) {
if (!isLogError(err)) {
logger.error(`Error:`, err)
@ -58,10 +61,11 @@ export async function validateCommunities(): Promise<void> {
}
} else {
logger.warn(
`Federation: dbCom: ${dbCom.id} with unsupported apiVersion=${dbCom.apiVersion}; supported versions=${apiValueStrings}`,
`Federation: dbCom: ${dbCom.id} with unsupported apiVersion=${dbCom.apiVersion}; supported versions`,
apiValueStrings,
)
}
})
}
}
function isLogError(err: unknown) {

View File

@ -22,7 +22,7 @@ export default class ContributionLinkArgs {
validTo?: string | null
@Field(() => Decimal, { nullable: true })
maxAmountPerMonth: Decimal | null
maxAmountPerMonth?: Decimal | null
@Field(() => Int)
maxPerCycle: number

View File

@ -1,9 +1,9 @@
import { ArgsType, Field, InputType } from 'type-graphql'
import { ArgsType, Field, Int, InputType } from 'type-graphql'
@InputType()
@ArgsType()
export default class ContributionMessageArgs {
@Field(() => Number)
@Field(() => Int)
contributionId: number
@Field(() => String)

View File

@ -11,11 +11,11 @@ export default class CreateUserArgs {
@Field(() => String)
lastName: string
@Field(() => String)
language?: string // Will default to DEFAULT_LANGUAGE
@Field(() => String, { nullable: true })
language?: string | null
@Field(() => Int, { nullable: true })
publisherId: number
publisherId?: number | null
@Field(() => String, { nullable: true })
redeemCode?: string | null

View File

@ -1,3 +1,4 @@
/* eslint-disable type-graphql/invalid-nullable-input-type */
import { ArgsType, Field, Int } from 'type-graphql'
import { Order } from '@enum/Order'

View File

@ -7,11 +7,14 @@ export default class SearchUsersArgs {
searchText: string
@Field(() => Int, { nullable: true })
// eslint-disable-next-line type-graphql/invalid-nullable-input-type
currentPage?: number
@Field(() => Int, { nullable: true })
// eslint-disable-next-line type-graphql/invalid-nullable-input-type
pageSize?: number
// eslint-disable-next-line type-graphql/wrong-decorator-signature
@Field(() => SearchUsersFilters, { nullable: true, defaultValue: null })
filters: SearchUsersFilters
filters?: SearchUsersFilters | null
}

View File

@ -3,8 +3,8 @@ import { Field, InputType } from 'type-graphql'
@InputType()
export default class SearchUsersFilters {
@Field(() => Boolean, { nullable: true, defaultValue: null })
byActivated: boolean
byActivated?: boolean | null
@Field(() => Boolean, { nullable: true, defaultValue: null })
byDeleted: boolean
byDeleted?: boolean | null
}

View File

@ -1,13 +1,14 @@
/* eslint-disable type-graphql/invalid-nullable-input-type */
import { Field, InputType } from 'type-graphql'
@InputType()
export default class TransactionLinkFilters {
@Field(() => Boolean, { nullable: true })
withDeleted: boolean
withDeleted?: boolean
@Field(() => Boolean, { nullable: true })
withExpired: boolean
withExpired?: boolean
@Field(() => Boolean, { nullable: true })
withRedeemed: boolean
withRedeemed?: boolean
}

View File

@ -9,5 +9,5 @@ export default class UnsecureLoginArgs {
password: string
@Field(() => Int, { nullable: true })
publisherId: number
publisherId?: number | null
}

View File

@ -1,4 +1,4 @@
import { ArgsType, Field } from 'type-graphql'
import { ArgsType, Field, Int } from 'type-graphql'
@ArgsType()
export default class UpdateUserInfosArgs {
@ -11,8 +11,8 @@ export default class UpdateUserInfosArgs {
@Field({ nullable: true })
language?: string
@Field({ nullable: true })
publisherId?: number
@Field(() => Int, { nullable: true })
publisherId?: number | null
@Field({ nullable: true })
password?: string

View File

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { AuthChecker } from 'type-graphql'

View File

@ -1,19 +0,0 @@
import { ObjectType, Field } from 'type-graphql'
@ObjectType()
export class AdminCreateContributions {
constructor() {
this.success = false
this.successfulContribution = []
this.failedContribution = []
}
@Field(() => Boolean)
success: boolean
@Field(() => [String])
successfulContribution: string[]
@Field(() => [String])
failedContribution: string[]
}

View File

@ -1,4 +1,4 @@
import { ObjectType, Field } from 'type-graphql'
import { ObjectType, Field, Int, Float } from 'type-graphql'
import Decimal from 'decimal.js-light'
@ObjectType()
@ -19,14 +19,14 @@ export class Balance {
@Field(() => Decimal)
balance: Decimal
@Field(() => Number, { nullable: true })
@Field(() => Float, { nullable: true })
balanceGDT: number | null
// the count of all transactions
@Field(() => Number)
@Field(() => Int)
count: number
// the count of transaction links
@Field(() => Number)
@Field(() => Int)
linkCount: number
}

View File

@ -1,6 +1,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { ObjectType, Field } from 'type-graphql'
import { ObjectType, Field, Int } from 'type-graphql'
@ObjectType()
export class Community {
@ -14,7 +16,7 @@ export class Community {
}
}
@Field(() => Number)
@Field(() => Int)
id: number
@Field(() => String)

View File

@ -1,9 +1,9 @@
import { ObjectType, Field } from 'type-graphql'
import { ObjectType, Field, Int } from 'type-graphql'
import Decimal from 'decimal.js-light'
@ObjectType()
export class DynamicStatisticsFields {
@Field(() => Number)
@Field(() => Int)
activeUsers: number
@Field(() => Decimal)
@ -15,13 +15,13 @@ export class DynamicStatisticsFields {
@ObjectType()
export class CommunityStatistics {
@Field(() => Number)
@Field(() => Int)
allUsers: number
@Field(() => Number)
@Field(() => Int)
totalUsers: number
@Field(() => Number)
@Field(() => Int)
deletedUsers: number
@Field(() => Decimal)

View File

@ -12,7 +12,6 @@ export class Contribution {
this.amount = contribution.amount
this.memo = contribution.memo
this.createdAt = contribution.createdAt
this.deletedAt = contribution.deletedAt
this.confirmedAt = contribution.confirmedAt
this.confirmedBy = contribution.confirmedBy
this.contributionDate = contribution.contributionDate
@ -20,9 +19,11 @@ export class Contribution {
this.messagesCount = contribution.messages ? contribution.messages.length : 0
this.deniedAt = contribution.deniedAt
this.deniedBy = contribution.deniedBy
this.deletedAt = contribution.deletedAt
this.deletedBy = contribution.deletedBy
}
@Field(() => Number)
@Field(() => Int)
id: number
@Field(() => String, { nullable: true })
@ -40,25 +41,28 @@ export class Contribution {
@Field(() => Date)
createdAt: Date
@Field(() => Date, { nullable: true })
deletedAt: Date | null
@Field(() => Date, { nullable: true })
confirmedAt: Date | null
@Field(() => Number, { nullable: true })
@Field(() => Int, { nullable: true })
confirmedBy: number | null
@Field(() => Date, { nullable: true })
deniedAt: Date | null
@Field(() => Number, { nullable: true })
@Field(() => Int, { nullable: true })
deniedBy: number | null
@Field(() => Date, { nullable: true })
deletedAt: Date | null
@Field(() => Int, { nullable: true })
deletedBy: number | null
@Field(() => Date)
contributionDate: Date
@Field(() => Number)
@Field(() => Int)
messagesCount: number
@Field(() => String)

View File

@ -21,7 +21,7 @@ export class ContributionLink {
this.link = CONFIG.COMMUNITY_REDEEM_CONTRIBUTION_URL.replace(/{code}/g, this.code)
}
@Field(() => Number)
@Field(() => Int)
id: number
@Field(() => Decimal)

View File

@ -1,4 +1,4 @@
import { ObjectType, Field } from 'type-graphql'
import { ObjectType, Field, Int } from 'type-graphql'
import { ContributionLink } from '@model/ContributionLink'
@ObjectType()
@ -6,6 +6,6 @@ export class ContributionLinkList {
@Field(() => [ContributionLink])
links: ContributionLink[]
@Field(() => Number)
@Field(() => Int)
count: number
}

View File

@ -1,4 +1,4 @@
import { Field, ObjectType } from 'type-graphql'
import { Field, Int, ObjectType } from 'type-graphql'
import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage'
import { User } from '@entity/User'
@ -16,7 +16,7 @@ export class ContributionMessage {
this.isModerator = contributionMessage.isModerator
}
@Field(() => Number)
@Field(() => Int)
id: number
@Field(() => String)
@ -26,7 +26,7 @@ export class ContributionMessage {
createdAt: Date
@Field(() => Date, { nullable: true })
updatedAt?: Date | null
updatedAt: Date | null
@Field(() => String)
type: string
@ -37,7 +37,7 @@ export class ContributionMessage {
@Field(() => String, { nullable: true })
userLastName: string | null
@Field(() => Number, { nullable: true })
@Field(() => Int, { nullable: true })
userId: number | null
@Field(() => Boolean)
@ -45,7 +45,7 @@ export class ContributionMessage {
}
@ObjectType()
export class ContributionMessageListResult {
@Field(() => Number)
@Field(() => Int)
count: number
@Field(() => [ContributionMessage])

View File

@ -1,6 +1,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { ObjectType, Field } from 'type-graphql'
import { ObjectType, Field, Float, Int } from 'type-graphql'
import { GdtEntryType } from '@enum/GdtEntryType'
@ObjectType()
@ -19,10 +21,10 @@ export class GdtEntry {
this.gdt = json.gdt
}
@Field(() => Number)
@Field(() => Int)
id: number
@Field(() => Number)
@Field(() => Float)
amount: number
@Field(() => String)
@ -40,15 +42,15 @@ export class GdtEntry {
@Field(() => GdtEntryType)
gdtEntryType: GdtEntryType
@Field(() => Number)
@Field(() => Float)
factor: number
@Field(() => Number)
@Field(() => Float)
amount2: number
@Field(() => Number)
@Field(() => Float)
factor2: number
@Field(() => Number)
@Field(() => Float)
gdt: number
}

View File

@ -1,7 +1,10 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { GdtEntry } from './GdtEntry'
import { ObjectType, Field } from 'type-graphql'
import { ObjectType, Field, Int, Float } from 'type-graphql'
@ObjectType()
export class GdtEntryList {
@ -16,15 +19,15 @@ export class GdtEntryList {
@Field(() => String)
state: string
@Field(() => Number)
@Field(() => Int)
count: number
@Field(() => [GdtEntry], { nullable: true })
gdtEntries?: GdtEntry[]
gdtEntries: GdtEntry[] | null
@Field(() => Number)
@Field(() => Float)
gdtSum: number
@Field(() => Number)
@Field(() => Float)
timeUsed: number
}

View File

@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { ObjectType, Field } from 'type-graphql'

View File

@ -1,4 +1,4 @@
import { ObjectType, Field } from 'type-graphql'
import { ObjectType, Field, Int } from 'type-graphql'
import { Decay } from './Decay'
import { Transaction as dbTransaction } from '@entity/Transaction'
import Decimal from 'decimal.js-light'
@ -41,19 +41,19 @@ export class Transaction {
this.memo = transaction.memo
this.creationDate = transaction.creationDate
this.linkedUser = linkedUser
this.linkedTransactionId = transaction.linkedTransactionId
this.linkedTransactionId = transaction.linkedTransactionId || null
this.linkId = transaction.contribution
? transaction.contribution.contributionLinkId
: transaction.transactionLinkId
: transaction.transactionLinkId || null
}
@Field(() => Number)
@Field(() => Int)
id: number
@Field(() => User)
user: User
@Field(() => Number, { nullable: true })
@Field(() => Int, { nullable: true })
previous: number | null
@Field(() => TransactionTypeId)
@ -80,10 +80,10 @@ export class Transaction {
@Field(() => User, { nullable: true })
linkedUser: User | null
@Field(() => Number, { nullable: true })
linkedTransactionId?: number | null
@Field(() => Int, { nullable: true })
linkedTransactionId: number | null
// Links to the TransactionLink/ContributionLink when transaction was created by a link
@Field(() => Number, { nullable: true })
linkId?: number | null
@Field(() => Int, { nullable: true })
linkId: number | null
}

View File

@ -21,7 +21,7 @@ export class TransactionLink {
this.link = CONFIG.COMMUNITY_REDEEM_URL.replace(/{code}/g, this.code)
}
@Field(() => Number)
@Field(() => Int)
id: number
@Field(() => User)
@ -61,8 +61,8 @@ export class TransactionLink {
@ObjectType()
export class TransactionLinkResult {
@Field(() => Int)
linkCount: number
count: number
@Field(() => [TransactionLink])
linkList: TransactionLink[]
links: TransactionLink[]
}

View File

@ -24,12 +24,12 @@ export class UnconfirmedContribution {
firstName: string
@Field(() => Int)
id?: number
id: number
@Field(() => String)
lastName: string
@Field(() => Number)
@Field(() => Int)
userId: number
@Field(() => String)
@ -44,7 +44,7 @@ export class UnconfirmedContribution {
@Field(() => Decimal)
amount: Decimal
@Field(() => Number, { nullable: true })
@Field(() => Int, { nullable: true })
moderator: number | null
@Field(() => [Decimal])
@ -53,6 +53,6 @@ export class UnconfirmedContribution {
@Field(() => String)
state: string
@Field(() => Number)
@Field(() => Int)
messageCount: number
}

Some files were not shown because too many files have changed in this diff Show More