mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge remote-tracking branch 'origin/master' into 2630-feature-federation-implement-a-graphql-endpoint-for-request-getpublickey
This commit is contained in:
commit
e9babd1014
158
.github/workflows/test.yml
vendored
158
.github/workflows/test.yml
vendored
@ -163,7 +163,6 @@ jobs:
|
||||
locales_frontend:
|
||||
name: Locales - Frontend
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_frontend]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -171,20 +170,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Frontend)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-frontend-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/frontend.tar
|
||||
##########################################################################
|
||||
# LOCALES FRONTEND #######################################################
|
||||
##########################################################################
|
||||
- name: Frontend | Locales
|
||||
run: docker run --rm gradido/frontend:test yarn run locales
|
||||
run: cd frontend && yarn && yarn run locales
|
||||
|
||||
##############################################################################
|
||||
# JOB: LINT FRONTEND #########################################################
|
||||
@ -192,7 +181,6 @@ jobs:
|
||||
lint_frontend:
|
||||
name: Lint - Frontend
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_frontend]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -200,20 +188,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Frontend)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-frontend-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/frontend.tar
|
||||
##########################################################################
|
||||
# LINT FRONTEND ##########################################################
|
||||
##########################################################################
|
||||
- name: Frontend | Lint
|
||||
run: docker run --rm gradido/frontend:test yarn run lint
|
||||
run: cd frontend && yarn && yarn run lint
|
||||
|
||||
##############################################################################
|
||||
# JOB: STYLELINT FRONTEND ####################################################
|
||||
@ -221,7 +199,6 @@ jobs:
|
||||
stylelint_frontend:
|
||||
name: Stylelint - Frontend
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_frontend]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -229,20 +206,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Frontend)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-frontend-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/frontend.tar
|
||||
##########################################################################
|
||||
# STYLELINT FRONTEND #####################################################
|
||||
##########################################################################
|
||||
- name: Frontend | Stylelint
|
||||
run: docker run --rm gradido/frontend:test yarn run stylelint
|
||||
run: cd frontend && yarn && yarn run stylelint
|
||||
|
||||
##############################################################################
|
||||
# JOB: LINT ADMIN INTERFACE ##################################################
|
||||
@ -250,7 +217,6 @@ jobs:
|
||||
lint_admin:
|
||||
name: Lint - Admin Interface
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_admin]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -258,20 +224,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Admin Interface)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-admin-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/admin.tar
|
||||
##########################################################################
|
||||
# LINT ADMIN INTERFACE ###################################################
|
||||
##########################################################################
|
||||
- name: Admin Interface | Lint
|
||||
run: docker run --rm gradido/admin:test yarn run lint
|
||||
run: cd admin && yarn && yarn run lint
|
||||
|
||||
##############################################################################
|
||||
# JOB: STYLELINT ADMIN INTERFACE #############################################
|
||||
@ -279,7 +235,6 @@ jobs:
|
||||
stylelint_admin:
|
||||
name: Stylelint - Admin Interface
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_admin]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -287,20 +242,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Admin Interface)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-admin-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/admin.tar
|
||||
##########################################################################
|
||||
# STYLELINT ADMIN INTERFACE ##############################################
|
||||
##########################################################################
|
||||
- name: Admin Interface | Stylelint
|
||||
run: docker run --rm gradido/admin:test yarn run stylelint
|
||||
run: cd admin && yarn && yarn run stylelint
|
||||
|
||||
##############################################################################
|
||||
# JOB: LOCALES ADMIN #########################################################
|
||||
@ -308,7 +253,6 @@ jobs:
|
||||
locales_admin:
|
||||
name: Locales - Admin Interface
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_admin]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -316,20 +260,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Admin Interface)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-admin-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/admin.tar
|
||||
##########################################################################
|
||||
# LOCALES FRONTEND #######################################################
|
||||
##########################################################################
|
||||
- name: admin | Locales
|
||||
run: docker run --rm gradido/admin:test yarn run locales
|
||||
- name: Admin | Locales
|
||||
run: cd admin && yarn && yarn run locales
|
||||
|
||||
##############################################################################
|
||||
# JOB: LINT BACKEND ##########################################################
|
||||
@ -337,7 +271,6 @@ jobs:
|
||||
lint_backend:
|
||||
name: Lint - Backend
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_backend]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -345,20 +278,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Backend)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-backend-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/backend.tar
|
||||
##########################################################################
|
||||
# LINT BACKEND ###########################################################
|
||||
##########################################################################
|
||||
- name: backend | Lint
|
||||
run: docker run --rm gradido/backend:test yarn run lint
|
||||
run: cd backend && yarn && yarn run lint
|
||||
|
||||
##############################################################################
|
||||
# JOB: LOCALES BACKEND #######################################################
|
||||
@ -366,7 +289,6 @@ jobs:
|
||||
locales_backend:
|
||||
name: Locales - Backend
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_backend]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -385,7 +307,6 @@ jobs:
|
||||
lint_database_up:
|
||||
name: Lint - Database Up
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_database_up]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -393,20 +314,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Backend)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-database-test_up
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/database_up.tar
|
||||
##########################################################################
|
||||
# LINT DATABASE ##########################################################
|
||||
##########################################################################
|
||||
- name: database | Lint
|
||||
run: docker run --rm gradido/database:test_up yarn run lint
|
||||
- name: Database | Lint
|
||||
run: cd database && yarn && yarn run lint
|
||||
|
||||
##############################################################################
|
||||
# JOB: UNIT TEST FRONTEND ###################################################
|
||||
@ -414,7 +325,6 @@ jobs:
|
||||
unit_test_frontend:
|
||||
name: Unit tests - Frontend
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_frontend]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -422,30 +332,12 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGES #################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Frontend)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-frontend-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/frontend.tar
|
||||
##########################################################################
|
||||
# UNIT TESTS FRONTEND ####################################################
|
||||
##########################################################################
|
||||
- name: frontend | Unit tests
|
||||
- name: Frontend | Unit tests
|
||||
run: |
|
||||
docker run --env NODE_ENV=test -v ~/coverage:/app/coverage --rm gradido/frontend:test yarn run test
|
||||
cp -r ~/coverage ./coverage
|
||||
##########################################################################
|
||||
# COVERAGE REPORT FRONTEND ###############################################
|
||||
##########################################################################
|
||||
#- name: frontend | Coverage report
|
||||
# uses: romeovs/lcov-reporter-action@v0.2.21
|
||||
# with:
|
||||
# github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# lcov-file: ./coverage/lcov.info
|
||||
cd frontend && yarn && yarn run test
|
||||
cp -r ./coverage ../
|
||||
##########################################################################
|
||||
# COVERAGE CHECK FRONTEND ################################################
|
||||
##########################################################################
|
||||
@ -454,7 +346,7 @@ jobs:
|
||||
with:
|
||||
report_name: Coverage Frontend
|
||||
type: lcov
|
||||
result_path: ./coverage/lcov.info
|
||||
result_path: ./frontend/coverage/lcov.info
|
||||
min_coverage: 95
|
||||
token: ${{ github.token }}
|
||||
|
||||
@ -464,7 +356,6 @@ jobs:
|
||||
unit_test_admin:
|
||||
name: Unit tests - Admin Interface
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_admin]
|
||||
steps:
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
@ -472,22 +363,12 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGES #################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Admin Interface)
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-admin-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/admin.tar
|
||||
##########################################################################
|
||||
# UNIT TESTS ADMIN INTERFACE #############################################
|
||||
##########################################################################
|
||||
- name: Admin Interface | Unit tests
|
||||
run: |
|
||||
docker run -v ~/coverage:/app/coverage --rm gradido/admin:test yarn run test
|
||||
cp -r ~/coverage ./coverage
|
||||
cd admin && yarn && yarn run test
|
||||
cp -r ./coverage ../
|
||||
##########################################################################
|
||||
# COVERAGE CHECK ADMIN INTERFACE #########################################
|
||||
##########################################################################
|
||||
@ -496,7 +377,7 @@ jobs:
|
||||
with:
|
||||
report_name: Coverage Admin Interface
|
||||
type: lcov
|
||||
result_path: ./coverage/lcov.info
|
||||
result_path: ./admin/coverage/lcov.info
|
||||
min_coverage: 97
|
||||
token: ${{ github.token }}
|
||||
|
||||
@ -534,8 +415,9 @@ 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
|
||||
# run: docker-compose -f docker-compose.yml -f docker-compose.test.yml exec -T backend yarn test
|
||||
run: |
|
||||
cd database && yarn && yarn build && cd ../backend && yarn && yarn test
|
||||
cp -r ./coverage ../
|
||||
##########################################################################
|
||||
# COVERAGE CHECK BACKEND #################################################
|
||||
##########################################################################
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import defaultLayout from '@/layouts/defaultLayout.vue'
|
||||
import defaultLayout from '@/layouts/defaultLayout'
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import ContributionLink from './ContributionLink.vue'
|
||||
import ContributionLink from './ContributionLink'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import ContributionMessagesList from './ContributionMessagesList.vue'
|
||||
import ContributionMessagesList from './ContributionMessagesList'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
</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 {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import ContributionMessagesListItem from './ContributionMessagesListItem.vue'
|
||||
import ContributionMessagesListItem from './ContributionMessagesListItem'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ParseMessage from '@/components/ContributionMessages/ParseMessage.vue'
|
||||
import ParseMessage from '@/components/ContributionMessages/ParseMessage'
|
||||
|
||||
export default {
|
||||
name: 'ContributionMessagesListItem',
|
||||
|
||||
@ -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!')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import FigureQrCode from './FigureQrCode.vue'
|
||||
import FigureQrCode from './FigureQrCode'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -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', () => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Overlay from './Overlay.vue'
|
||||
import Overlay from './Overlay'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import OpenCreationsTable from './OpenCreationsTable.vue'
|
||||
import OpenCreationsTable from './OpenCreationsTable'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -117,9 +117,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',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import SearchUserTable from './SearchUserTable.vue'
|
||||
import SearchUserTable from './SearchUserTable'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import StatisticTable from './StatisticTable.vue'
|
||||
import StatisticTable from './StatisticTable'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const adminCreateContributions = gql`
|
||||
mutation ($pendingCreations: [AdminCreateContributionArgs!]!) {
|
||||
adminCreateContributions(pendingCreations: $pendingCreations) {
|
||||
success
|
||||
successfulContribution
|
||||
failedContribution
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -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: {
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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'
|
||||
|
||||
@ -71,8 +71,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Overlay from '../components/Overlay.vue'
|
||||
import OpenCreationsTable from '../components/Tables/OpenCreationsTable.vue'
|
||||
import Overlay from '../components/Overlay'
|
||||
import OpenCreationsTable from '../components/Tables/OpenCreationsTable'
|
||||
import { listAllContributions } from '../graphql/listAllContributions'
|
||||
import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
|
||||
import { confirmContribution } from '../graphql/confirmContribution'
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Overview from './Overview.vue'
|
||||
import Overview from './Overview'
|
||||
import { listAllContributions } from '../graphql/listAllContributions'
|
||||
import VueApollo from 'vue-apollo'
|
||||
import { createMockClient } from 'mock-apollo-client'
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -24,9 +24,6 @@ export const mutations = {
|
||||
moderator: (state, moderator) => {
|
||||
state.moderator = moderator
|
||||
},
|
||||
setUserSelectedInMassCreation: (state, userSelectedInMassCreation) => {
|
||||
state.userSelectedInMassCreation = userSelectedInMassCreation
|
||||
},
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
|
||||
@ -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', () => {
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import jwt from 'jsonwebtoken'
|
||||
import CONFIG from '@/config/'
|
||||
import { CustomJwtPayload } from './CustomJwtPayload'
|
||||
import LogError from '@/server/LogError'
|
||||
|
||||
export const decode = (token: string): CustomJwtPayload | null => {
|
||||
if (!token) throw new Error('401 Unauthorized')
|
||||
if (!token) throw new LogError('401 Unauthorized')
|
||||
try {
|
||||
return <CustomJwtPayload>jwt.verify(token, CONFIG.JWT_SECRET)
|
||||
} catch (err) {
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -7,6 +7,7 @@ import { ROLE_UNAUTHORIZED, ROLE_USER, ROLE_ADMIN } from '@/auth/ROLES'
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import { INALIENABLE_RIGHTS } from '@/auth/INALIENABLE_RIGHTS'
|
||||
import { User } from '@entity/User'
|
||||
import LogError from '@/server/LogError'
|
||||
|
||||
const isAuthorized: AuthChecker<any> = async ({ context }, rights) => {
|
||||
context.role = ROLE_UNAUTHORIZED // unauthorized user
|
||||
@ -17,13 +18,13 @@ const isAuthorized: AuthChecker<any> = async ({ context }, rights) => {
|
||||
|
||||
// Do we have a token?
|
||||
if (!context.token) {
|
||||
throw new Error('401 Unauthorized')
|
||||
throw new LogError('401 Unauthorized')
|
||||
}
|
||||
|
||||
// Decode the token
|
||||
const decoded = decode(context.token)
|
||||
if (!decoded) {
|
||||
throw new Error('403.13 - Client certificate revoked')
|
||||
throw new LogError('403.13 - Client certificate revoked')
|
||||
}
|
||||
// Set context gradidoID
|
||||
context.gradidoID = decoded.gradidoID
|
||||
@ -39,13 +40,13 @@ const isAuthorized: AuthChecker<any> = async ({ context }, rights) => {
|
||||
context.role = user.isAdmin ? ROLE_ADMIN : ROLE_USER
|
||||
} catch {
|
||||
// in case the database query fails (user deleted)
|
||||
throw new Error('401 Unauthorized')
|
||||
throw new LogError('401 Unauthorized')
|
||||
}
|
||||
|
||||
// check for correct rights
|
||||
const missingRights = (<RIGHTS[]>rights).filter((right) => !context.role.hasRight(right))
|
||||
if (missingRights.length !== 0) {
|
||||
throw new Error('401 Unauthorized')
|
||||
throw new LogError('401 Unauthorized')
|
||||
}
|
||||
|
||||
// set new header token
|
||||
|
||||
@ -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[]
|
||||
}
|
||||
@ -257,17 +257,13 @@ describe('Contribution Links', () => {
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [
|
||||
new GraphQLError('Start-Date is not initialized. A Start-Date must be set!'),
|
||||
],
|
||||
errors: [new GraphQLError('A Start-Date must be set')],
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Start-Date is not initialized. A Start-Date must be set!',
|
||||
)
|
||||
expect(logger.error).toBeCalledWith('A Start-Date must be set')
|
||||
})
|
||||
|
||||
it('returns an error if missing endDate', async () => {
|
||||
@ -282,15 +278,13 @@ describe('Contribution Links', () => {
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('End-Date is not initialized. An End-Date must be set!')],
|
||||
errors: [new GraphQLError('An End-Date must be set')],
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'End-Date is not initialized. An End-Date must be set!',
|
||||
)
|
||||
expect(logger.error).toBeCalledWith('An End-Date must be set')
|
||||
})
|
||||
|
||||
it('returns an error if endDate is before startDate', async () => {
|
||||
@ -307,7 +301,7 @@ describe('Contribution Links', () => {
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [
|
||||
new GraphQLError(`The value of validFrom must before or equals the validTo!`),
|
||||
new GraphQLError(`The value of validFrom must before or equals the validTo`),
|
||||
],
|
||||
}),
|
||||
)
|
||||
@ -315,7 +309,7 @@ describe('Contribution Links', () => {
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
`The value of validFrom must before or equals the validTo!`,
|
||||
`The value of validFrom must before or equals the validTo`,
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@ -33,10 +33,14 @@ export class ContributionMessageResolver {
|
||||
try {
|
||||
const contribution = await DbContribution.findOne({ id: contributionId })
|
||||
if (!contribution) {
|
||||
throw new Error('Contribution not found')
|
||||
throw new LogError('Contribution not found', contributionId)
|
||||
}
|
||||
if (contribution.userId !== user.id) {
|
||||
throw new Error('Can not send message to contribution of another user')
|
||||
throw new LogError(
|
||||
'Can not send message to contribution of another user',
|
||||
contribution.userId,
|
||||
user.id,
|
||||
)
|
||||
}
|
||||
|
||||
contributionMessage.contributionId = contributionId
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql'
|
||||
import { FindOperator, IsNull, In, getConnection } from '@dbTools/typeorm'
|
||||
import { FindOperator, IsNull, getConnection } from '@dbTools/typeorm'
|
||||
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { ContributionMessage } from '@entity/ContributionMessage'
|
||||
@ -8,7 +8,6 @@ import { UserContact } from '@entity/UserContact'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||
|
||||
import { AdminCreateContributions } from '@model/AdminCreateContributions'
|
||||
import { AdminUpdateContribution } from '@model/AdminUpdateContribution'
|
||||
import { Contribution, ContributionListResult } from '@model/Contribution'
|
||||
import { Decay } from '@model/Decay'
|
||||
@ -30,12 +29,11 @@ import { backendLogger as logger } from '@/server/logger'
|
||||
import {
|
||||
getCreationDates,
|
||||
getUserCreation,
|
||||
getUserCreations,
|
||||
validateContribution,
|
||||
updateCreations,
|
||||
isValidDateString,
|
||||
} from './util/creations'
|
||||
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS, FULL_CREATION_AVAILABLE } from './const/const'
|
||||
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const'
|
||||
import {
|
||||
EVENT_CONTRIBUTION_CREATE,
|
||||
EVENT_CONTRIBUTION_DELETE,
|
||||
@ -56,6 +54,7 @@ import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
|
||||
import LogError from '@/server/LogError'
|
||||
|
||||
import { getLastTransaction } from './util/getLastTransaction'
|
||||
import { findContributions } from './util/findContributions'
|
||||
|
||||
@Resolver()
|
||||
export class ContributionResolver {
|
||||
@ -168,25 +167,14 @@ export class ContributionResolver {
|
||||
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
|
||||
statusFilter?: ContributionStatus[],
|
||||
): Promise<ContributionListResult> {
|
||||
const where: {
|
||||
contributionStatus?: FindOperator<string> | null
|
||||
} = {}
|
||||
const [dbContributions, count] = await findContributions(
|
||||
order,
|
||||
currentPage,
|
||||
pageSize,
|
||||
false,
|
||||
statusFilter,
|
||||
)
|
||||
|
||||
if (statusFilter && statusFilter.length) {
|
||||
where.contributionStatus = In(statusFilter)
|
||||
}
|
||||
|
||||
const [dbContributions, count] = await getConnection()
|
||||
.createQueryBuilder()
|
||||
.select('c')
|
||||
.from(DbContribution, 'c')
|
||||
.innerJoinAndSelect('c.user', 'u')
|
||||
.leftJoinAndSelect('c.messages', 'm')
|
||||
.where(where)
|
||||
.orderBy('c.createdAt', order)
|
||||
.limit(pageSize)
|
||||
.offset((currentPage - 1) * pageSize)
|
||||
.getManyAndCount()
|
||||
return new ContributionListResult(
|
||||
count,
|
||||
dbContributions.map((contribution) => new Contribution(contribution, contribution.user)),
|
||||
@ -329,33 +317,6 @@ export class ContributionResolver {
|
||||
return getUserCreation(emailContact.userId, clientTimezoneOffset)
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTIONS])
|
||||
@Mutation(() => AdminCreateContributions)
|
||||
async adminCreateContributions(
|
||||
@Arg('pendingCreations', () => [AdminCreateContributionArgs])
|
||||
contributions: AdminCreateContributionArgs[],
|
||||
@Ctx() context: Context,
|
||||
): Promise<AdminCreateContributions> {
|
||||
let success = false
|
||||
const successfulContribution: string[] = []
|
||||
const failedContribution: string[] = []
|
||||
for (const contribution of contributions) {
|
||||
await this.adminCreateContribution(contribution, context)
|
||||
.then(() => {
|
||||
successfulContribution.push(contribution.email)
|
||||
success = true
|
||||
})
|
||||
.catch(() => {
|
||||
failedContribution.push(contribution.email)
|
||||
})
|
||||
}
|
||||
return {
|
||||
success,
|
||||
successfulContribution,
|
||||
failedContribution,
|
||||
}
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.ADMIN_UPDATE_CONTRIBUTION])
|
||||
@Mutation(() => AdminUpdateContribution)
|
||||
async adminUpdateContribution(
|
||||
@ -425,40 +386,25 @@ export class ContributionResolver {
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.LIST_UNCONFIRMED_CONTRIBUTIONS])
|
||||
@Query(() => [UnconfirmedContribution])
|
||||
async listUnconfirmedContributions(@Ctx() context: Context): Promise<UnconfirmedContribution[]> {
|
||||
const clientTimezoneOffset = getClientTimezoneOffset(context)
|
||||
const contributions = await getConnection()
|
||||
.createQueryBuilder()
|
||||
.select('c')
|
||||
.from(DbContribution, 'c')
|
||||
.leftJoinAndSelect('c.messages', 'm')
|
||||
.where({ confirmedAt: IsNull() })
|
||||
.andWhere({ deniedAt: IsNull() })
|
||||
.getMany()
|
||||
@Query(() => ContributionListResult) // [UnconfirmedContribution]
|
||||
async adminListAllContributions(
|
||||
@Args()
|
||||
{ currentPage = 1, pageSize = 3, order = Order.DESC }: Paginated,
|
||||
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
|
||||
statusFilter?: ContributionStatus[],
|
||||
): Promise<ContributionListResult> {
|
||||
const [dbContributions, count] = await findContributions(
|
||||
order,
|
||||
currentPage,
|
||||
pageSize,
|
||||
true,
|
||||
statusFilter,
|
||||
)
|
||||
|
||||
if (contributions.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
const userIds = contributions.map((p) => p.userId)
|
||||
const userCreations = await getUserCreations(userIds, clientTimezoneOffset)
|
||||
const users = await DbUser.find({
|
||||
where: { id: In(userIds) },
|
||||
withDeleted: true,
|
||||
relations: ['emailContact'],
|
||||
})
|
||||
|
||||
return contributions.map((contribution) => {
|
||||
const user = users.find((u) => u.id === contribution.userId)
|
||||
const creation = userCreations.find((c) => c.id === contribution.userId)
|
||||
|
||||
return new UnconfirmedContribution(
|
||||
contribution,
|
||||
user,
|
||||
creation ? creation.creations : FULL_CREATION_AVAILABLE,
|
||||
)
|
||||
})
|
||||
return new ContributionListResult(
|
||||
count,
|
||||
dbContributions.map((contribution) => new Contribution(contribution, contribution.user)),
|
||||
)
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION])
|
||||
|
||||
@ -8,6 +8,7 @@ import { Context, getUser } from '@/server/context'
|
||||
import CONFIG from '@/config'
|
||||
import { apiGet, apiPost } from '@/apis/HttpRequest'
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import LogError from '@/server/LogError'
|
||||
|
||||
@Resolver()
|
||||
export class GdtResolver {
|
||||
@ -25,11 +26,11 @@ export class GdtResolver {
|
||||
`${CONFIG.GDT_API_URL}/GdtEntries/listPerEmailApi/${userEntity.emailContact.email}/${currentPage}/${pageSize}/${order}`,
|
||||
)
|
||||
if (!resultGDT.success) {
|
||||
throw new Error(resultGDT.data)
|
||||
throw new LogError(resultGDT.data)
|
||||
}
|
||||
return new GdtEntryList(resultGDT.data)
|
||||
} catch (err) {
|
||||
throw new Error('GDT Server is not reachable.')
|
||||
throw new LogError('GDT Server is not reachable')
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +43,7 @@ export class GdtResolver {
|
||||
email: user.emailContact.email,
|
||||
})
|
||||
if (!resultGDTSum.success) {
|
||||
throw new Error('Call not successful')
|
||||
throw new LogError('Call not successful')
|
||||
}
|
||||
return Number(resultGDTSum.data.sum) || 0
|
||||
} catch (err) {
|
||||
@ -59,7 +60,7 @@ export class GdtResolver {
|
||||
// load user
|
||||
const resultPID = await apiGet(`${CONFIG.GDT_API_URL}/publishers/checkPidApi/${pid}`)
|
||||
if (!resultPID.success) {
|
||||
throw new Error(resultPID.data)
|
||||
throw new LogError(resultPID.data)
|
||||
}
|
||||
return resultPID.data.pid
|
||||
}
|
||||
|
||||
@ -53,65 +53,81 @@ afterAll(async () => {
|
||||
|
||||
describe('TransactionLinkResolver', () => {
|
||||
describe('createTransactionLink', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||
describe('unauthenticated', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
resetToken()
|
||||
await expect(
|
||||
mutate({ mutation: createTransactionLink, variables: { amount: 0, memo: 'Test' } }),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('401 Unauthorized')],
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('throws error when amount is zero', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createTransactionLink,
|
||||
variables: {
|
||||
amount: 0,
|
||||
memo: 'Test',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Amount must be a positive number')],
|
||||
describe('authenticated', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||
})
|
||||
})
|
||||
})
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Amount must be a positive number', new Decimal(0))
|
||||
})
|
||||
|
||||
it('throws error when amount is negative', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createTransactionLink,
|
||||
variables: {
|
||||
amount: -10,
|
||||
memo: 'Test',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Amount must be a positive number')],
|
||||
it('throws error when amount is zero', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createTransactionLink,
|
||||
variables: {
|
||||
amount: 0,
|
||||
memo: 'Test',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Amount must be a positive number')],
|
||||
})
|
||||
})
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Amount must be a positive number', new Decimal(0))
|
||||
})
|
||||
})
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Amount must be a positive number', new Decimal(-10))
|
||||
})
|
||||
|
||||
it('throws error when user has not enough GDD', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createTransactionLink,
|
||||
variables: {
|
||||
amount: 1001,
|
||||
memo: 'Test',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('User has not enough GDD')],
|
||||
it('throws error when amount is negative', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createTransactionLink,
|
||||
variables: {
|
||||
amount: -10,
|
||||
memo: 'Test',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Amount must be a positive number')],
|
||||
})
|
||||
})
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Amount must be a positive number', new Decimal(-10))
|
||||
})
|
||||
|
||||
it('throws error when user has not enough GDD', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createTransactionLink,
|
||||
variables: {
|
||||
amount: 1001,
|
||||
memo: 'Test',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('User has not enough GDD')],
|
||||
})
|
||||
})
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('User has not enough GDD', expect.any(Number))
|
||||
})
|
||||
})
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('User has not enough GDD', expect.any(Number))
|
||||
})
|
||||
})
|
||||
|
||||
@ -121,236 +137,37 @@ describe('TransactionLinkResolver', () => {
|
||||
resetToken()
|
||||
})
|
||||
|
||||
describe('contributionLink', () => {
|
||||
describe('input not valid', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||
})
|
||||
})
|
||||
|
||||
it('throws error when link does not exists', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-123456',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Creation from contribution link was not successful')],
|
||||
})
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'No contribution link found to given code',
|
||||
'CL-123456',
|
||||
)
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error('No contribution link found to given code'),
|
||||
)
|
||||
})
|
||||
|
||||
const now = new Date()
|
||||
const validFrom = new Date(now.getFullYear() + 1, 0, 1)
|
||||
|
||||
it('throws error when link is not valid yet', async () => {
|
||||
jest.clearAllMocks()
|
||||
const {
|
||||
data: { createContributionLink: contributionLink },
|
||||
} = await mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
amount: new Decimal(5),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
cycle: 'DAILY',
|
||||
validFrom: validFrom.toISOString(),
|
||||
validTo: new Date(now.getFullYear() + 1, 11, 31, 23, 59, 59, 999).toISOString(),
|
||||
maxAmountPerMonth: new Decimal(200),
|
||||
maxPerCycle: 1,
|
||||
},
|
||||
})
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + contributionLink.code,
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Creation from contribution link was not successful')],
|
||||
})
|
||||
await resetEntity(DbContributionLink)
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Contribution link is not valid yet', validFrom)
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error('Contribution link is not valid yet'),
|
||||
)
|
||||
})
|
||||
|
||||
it('throws error when contributionLink cycle is invalid', async () => {
|
||||
jest.clearAllMocks()
|
||||
const now = new Date()
|
||||
const {
|
||||
data: { createContributionLink: contributionLink },
|
||||
} = await mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
amount: new Decimal(5),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
cycle: 'INVALID',
|
||||
validFrom: new Date(now.getFullYear(), 0, 1).toISOString(),
|
||||
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999).toISOString(),
|
||||
maxAmountPerMonth: new Decimal(200),
|
||||
maxPerCycle: 1,
|
||||
},
|
||||
})
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + contributionLink.code,
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Creation from contribution link was not successful')],
|
||||
})
|
||||
await resetEntity(DbContributionLink)
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Contribution link has unknown cycle', 'INVALID')
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error('Contribution link has unknown cycle'),
|
||||
)
|
||||
})
|
||||
|
||||
const validTo = new Date(now.getFullYear() - 1, 11, 31, 23, 59, 59, 0)
|
||||
it('throws error when link is no longer valid', async () => {
|
||||
jest.clearAllMocks()
|
||||
const {
|
||||
data: { createContributionLink: contributionLink },
|
||||
} = await mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
amount: new Decimal(5),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
cycle: 'DAILY',
|
||||
validFrom: new Date(now.getFullYear() - 1, 0, 1).toISOString(),
|
||||
validTo: validTo.toISOString(),
|
||||
maxAmountPerMonth: new Decimal(200),
|
||||
maxPerCycle: 1,
|
||||
},
|
||||
})
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + contributionLink.code,
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Creation from contribution link was not successful')],
|
||||
})
|
||||
await resetEntity(DbContributionLink)
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Contribution link is no longer valid', validTo)
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error('Contribution link is no longer valid'),
|
||||
)
|
||||
})
|
||||
describe('unauthenticated', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
resetToken()
|
||||
await expect(
|
||||
mutate({ mutation: redeemTransactionLink, variables: { code: 'CL-123456' } }),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('401 Unauthorized')],
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: have this test separated into a transactionLink and a contributionLink part
|
||||
describe('redeem daily Contribution Link', () => {
|
||||
const now = new Date()
|
||||
let contributionLink: DbContributionLink | undefined
|
||||
let contribution: UnconfirmedContribution | undefined
|
||||
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||
})
|
||||
await mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
amount: new Decimal(5),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
cycle: 'DAILY',
|
||||
validFrom: new Date(now.getFullYear(), 0, 1).toISOString(),
|
||||
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999).toISOString(),
|
||||
maxAmountPerMonth: new Decimal(200),
|
||||
maxPerCycle: 1,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('has a daily contribution link in the database', async () => {
|
||||
const cls = await DbContributionLink.find()
|
||||
expect(cls).toHaveLength(1)
|
||||
contributionLink = cls[0]
|
||||
expect(contributionLink).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(Number),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
validFrom: new Date(now.getFullYear(), 0, 1),
|
||||
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 0),
|
||||
cycle: 'DAILY',
|
||||
maxPerCycle: 1,
|
||||
totalMaxCountOfContribution: null,
|
||||
maxAccountBalance: null,
|
||||
minGapHours: null,
|
||||
createdAt: expect.any(Date),
|
||||
deletedAt: null,
|
||||
code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
|
||||
linkEnabled: true,
|
||||
amount: expect.decimalEqual(5),
|
||||
maxAmountPerMonth: expect.decimalEqual(200),
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
describe('user has pending contribution of 1000 GDD', () => {
|
||||
describe('authenticated', () => {
|
||||
describe('contributionLink', () => {
|
||||
describe('input not valid', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||
})
|
||||
const result = await mutate({
|
||||
mutation: createContribution,
|
||||
variables: {
|
||||
amount: new Decimal(1000),
|
||||
memo: 'I was brewing potions for the community the whole month',
|
||||
creationDate: now.toISOString(),
|
||||
},
|
||||
})
|
||||
contribution = result.data.createContribution
|
||||
})
|
||||
|
||||
it('does not allow the user to redeem the contribution link', async () => {
|
||||
it('throws error when link does not exists', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||
code: 'CL-123456',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
@ -359,85 +176,247 @@ describe('TransactionLinkResolver', () => {
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'No contribution link found to given code',
|
||||
'CL-123456',
|
||||
)
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error(
|
||||
'The amount (5 GDD) to be created exceeds the amount (0 GDD) still available for this month.',
|
||||
),
|
||||
new Error('No contribution link found to given code'),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('user has no pending contributions that would not allow to redeem the link', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||
})
|
||||
await mutate({
|
||||
mutation: updateContribution,
|
||||
variables: {
|
||||
contributionId: contribution ? contribution.id : -1,
|
||||
amount: new Decimal(800),
|
||||
memo: 'I was brewing potions for the community the whole month',
|
||||
creationDate: now.toISOString(),
|
||||
},
|
||||
})
|
||||
})
|
||||
const now = new Date()
|
||||
const validFrom = new Date(now.getFullYear() + 1, 0, 1)
|
||||
|
||||
it('allows the user to redeem the contribution link', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
redeemTransactionLink: true,
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('does not allow the user to redeem the contribution link a second time on the same day', async () => {
|
||||
it('throws error when link is not valid yet', async () => {
|
||||
jest.clearAllMocks()
|
||||
const {
|
||||
data: { createContributionLink: contributionLink },
|
||||
} = await mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
amount: new Decimal(5),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
cycle: 'DAILY',
|
||||
validFrom: validFrom.toISOString(),
|
||||
validTo: new Date(now.getFullYear() + 1, 11, 31, 23, 59, 59, 999).toISOString(),
|
||||
maxAmountPerMonth: new Decimal(200),
|
||||
maxPerCycle: 1,
|
||||
},
|
||||
})
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||
code: 'CL-' + contributionLink.code,
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Creation from contribution link was not successful')],
|
||||
})
|
||||
await resetEntity(DbContributionLink)
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Contribution link is not valid yet', validFrom)
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error('Contribution link already redeemed today'),
|
||||
new Error('Contribution link is not valid yet'),
|
||||
)
|
||||
})
|
||||
|
||||
describe('after one day', () => {
|
||||
it('throws error when contributionLink cycle is invalid', async () => {
|
||||
jest.clearAllMocks()
|
||||
const now = new Date()
|
||||
const {
|
||||
data: { createContributionLink: contributionLink },
|
||||
} = await mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
amount: new Decimal(5),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
cycle: 'INVALID',
|
||||
validFrom: new Date(now.getFullYear(), 0, 1).toISOString(),
|
||||
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999).toISOString(),
|
||||
maxAmountPerMonth: new Decimal(200),
|
||||
maxPerCycle: 1,
|
||||
},
|
||||
})
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + contributionLink.code,
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Creation from contribution link was not successful')],
|
||||
})
|
||||
await resetEntity(DbContributionLink)
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Contribution link has unknown cycle', 'INVALID')
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error('Contribution link has unknown cycle'),
|
||||
)
|
||||
})
|
||||
|
||||
const validTo = new Date(now.getFullYear() - 1, 11, 31, 23, 59, 59, 0)
|
||||
it('throws error when link is no longer valid', async () => {
|
||||
jest.clearAllMocks()
|
||||
const {
|
||||
data: { createContributionLink: contributionLink },
|
||||
} = await mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
amount: new Decimal(5),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
cycle: 'DAILY',
|
||||
validFrom: new Date(now.getFullYear() - 1, 0, 1).toISOString(),
|
||||
validTo: validTo.toISOString(),
|
||||
maxAmountPerMonth: new Decimal(200),
|
||||
maxPerCycle: 1,
|
||||
},
|
||||
})
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + contributionLink.code,
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Creation from contribution link was not successful')],
|
||||
})
|
||||
await resetEntity(DbContributionLink)
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('Contribution link is no longer valid', validTo)
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error('Contribution link is no longer valid'),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: have this test separated into a transactionLink and a contributionLink part
|
||||
describe('redeem daily Contribution Link', () => {
|
||||
const now = new Date()
|
||||
let contributionLink: DbContributionLink | undefined
|
||||
let contribution: UnconfirmedContribution | undefined
|
||||
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||
})
|
||||
await mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
amount: new Decimal(5),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
cycle: 'DAILY',
|
||||
validFrom: new Date(now.getFullYear(), 0, 1).toISOString(),
|
||||
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999).toISOString(),
|
||||
maxAmountPerMonth: new Decimal(200),
|
||||
maxPerCycle: 1,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('has a daily contribution link in the database', async () => {
|
||||
const cls = await DbContributionLink.find()
|
||||
expect(cls).toHaveLength(1)
|
||||
contributionLink = cls[0]
|
||||
expect(contributionLink).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(Number),
|
||||
name: 'Daily Contribution Link',
|
||||
memo: 'Thank you for contribute daily to the community',
|
||||
validFrom: new Date(now.getFullYear(), 0, 1),
|
||||
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 0),
|
||||
cycle: 'DAILY',
|
||||
maxPerCycle: 1,
|
||||
totalMaxCountOfContribution: null,
|
||||
maxAccountBalance: null,
|
||||
minGapHours: null,
|
||||
createdAt: expect.any(Date),
|
||||
deletedAt: null,
|
||||
code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
|
||||
linkEnabled: true,
|
||||
amount: expect.decimalEqual(5),
|
||||
maxAmountPerMonth: expect.decimalEqual(200),
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
describe('user has pending contribution of 1000 GDD', () => {
|
||||
beforeAll(async () => {
|
||||
jest.useFakeTimers()
|
||||
setTimeout(jest.fn(), 1000 * 60 * 60 * 24)
|
||||
jest.runAllTimers()
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||
})
|
||||
const result = await mutate({
|
||||
mutation: createContribution,
|
||||
variables: {
|
||||
amount: new Decimal(1000),
|
||||
memo: 'I was brewing potions for the community the whole month',
|
||||
creationDate: now.toISOString(),
|
||||
},
|
||||
})
|
||||
contribution = result.data.createContribution
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers()
|
||||
it('does not allow the user to redeem the contribution link', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Creation from contribution link was not successful')],
|
||||
})
|
||||
})
|
||||
|
||||
it('allows the user to redeem the contribution link again', async () => {
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error(
|
||||
'The amount to be created exceeds the amount still available for this month',
|
||||
),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('user has no pending contributions that would not allow to redeem the link', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||
})
|
||||
await mutate({
|
||||
mutation: updateContribution,
|
||||
variables: {
|
||||
contributionId: contribution ? contribution.id : -1,
|
||||
amount: new Decimal(800),
|
||||
memo: 'I was brewing potions for the community the whole month',
|
||||
creationDate: now.toISOString(),
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('allows the user to redeem the contribution link', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
@ -473,6 +452,59 @@ describe('TransactionLinkResolver', () => {
|
||||
new Error('Contribution link already redeemed today'),
|
||||
)
|
||||
})
|
||||
|
||||
describe('after one day', () => {
|
||||
beforeAll(async () => {
|
||||
jest.useFakeTimers()
|
||||
setTimeout(jest.fn(), 1000 * 60 * 60 * 24)
|
||||
jest.runAllTimers()
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers()
|
||||
})
|
||||
|
||||
it('allows the user to redeem the contribution link again', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
redeemTransactionLink: true,
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('does not allow the user to redeem the contribution link a second time on the same day', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: redeemTransactionLink,
|
||||
variables: {
|
||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [new GraphQLError('Creation from contribution link was not successful')],
|
||||
})
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Creation from contribution link was not successful',
|
||||
new Error('Contribution link already redeemed today'),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -86,8 +86,8 @@ export class TransactionLinkResolver {
|
||||
transactionLink.code = transactionLinkCode(createdDate)
|
||||
transactionLink.createdAt = createdDate
|
||||
transactionLink.validUntil = validUntil
|
||||
await DbTransactionLink.save(transactionLink).catch(() => {
|
||||
throw new Error('Unable to save transaction link')
|
||||
await DbTransactionLink.save(transactionLink).catch((e) => {
|
||||
throw new LogError('Unable to save transaction link', e)
|
||||
})
|
||||
|
||||
return new TransactionLink(transactionLink, new User(user))
|
||||
@ -103,19 +103,23 @@ export class TransactionLinkResolver {
|
||||
|
||||
const transactionLink = await DbTransactionLink.findOne({ id })
|
||||
if (!transactionLink) {
|
||||
throw new Error('Transaction Link not found!')
|
||||
throw new LogError('Transaction link not found', id)
|
||||
}
|
||||
|
||||
if (transactionLink.userId !== user.id) {
|
||||
throw new Error('Transaction Link cannot be deleted!')
|
||||
throw new LogError(
|
||||
'Transaction link cannot be deleted by another user',
|
||||
transactionLink.userId,
|
||||
user.id,
|
||||
)
|
||||
}
|
||||
|
||||
if (transactionLink.redeemedBy) {
|
||||
throw new Error('Transaction Link already redeemed!')
|
||||
throw new LogError('Transaction link already redeemed', transactionLink.redeemedBy)
|
||||
}
|
||||
|
||||
await transactionLink.softRemove().catch(() => {
|
||||
throw new Error('Transaction Link could not be deleted!')
|
||||
await transactionLink.softRemove().catch((e) => {
|
||||
throw new LogError('Transaction link could not be deleted', e)
|
||||
})
|
||||
|
||||
return true
|
||||
@ -312,18 +316,18 @@ export class TransactionLinkResolver {
|
||||
)
|
||||
|
||||
if (user.id === linkedUser.id) {
|
||||
throw new Error('Cannot redeem own transaction link.')
|
||||
throw new LogError('Cannot redeem own transaction link', user.id)
|
||||
}
|
||||
|
||||
// TODO: The now check should be done within the semaphore lock,
|
||||
// since the program might wait a while till it is ready to proceed
|
||||
// writing the transaction.
|
||||
if (transactionLink.validUntil.getTime() < now.getTime()) {
|
||||
throw new Error('Transaction Link is not valid anymore.')
|
||||
throw new LogError('Transaction link is not valid anymore', transactionLink.validUntil)
|
||||
}
|
||||
|
||||
if (transactionLink.redeemedBy) {
|
||||
throw new Error('Transaction Link already redeemed.')
|
||||
throw new LogError('Transaction link already redeemed', transactionLink.redeemedBy)
|
||||
}
|
||||
|
||||
await executeTransaction(
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import LogError from '@/server/LogError'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
import { getConnection } from '@dbTools/typeorm'
|
||||
import { Contribution } from '@entity/Contribution'
|
||||
@ -19,19 +20,14 @@ export const validateContribution = (
|
||||
const index = getCreationIndex(creationDate.getMonth(), timezoneOffset)
|
||||
|
||||
if (index < 0) {
|
||||
logger.error(
|
||||
'No information for available creations with the given creationDate=',
|
||||
creationDate.toString(),
|
||||
)
|
||||
throw new Error('No information for available creations for the given date')
|
||||
throw new LogError('No information for available creations for the given date', creationDate)
|
||||
}
|
||||
|
||||
if (amount.greaterThan(creations[index].toString())) {
|
||||
logger.error(
|
||||
`The amount (${amount} GDD) to be created exceeds the amount (${creations[index]} GDD) still available for this month.`,
|
||||
)
|
||||
throw new Error(
|
||||
`The amount (${amount} GDD) to be created exceeds the amount (${creations[index]} GDD) still available for this month.`,
|
||||
throw new LogError(
|
||||
'The amount to be created exceeds the amount still available for this month',
|
||||
amount,
|
||||
creations[index],
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -126,19 +122,16 @@ export const isStartEndDateValid = (
|
||||
endDate: string | null | undefined,
|
||||
): void => {
|
||||
if (!startDate) {
|
||||
logger.error('Start-Date is not initialized. A Start-Date must be set!')
|
||||
throw new Error('Start-Date is not initialized. A Start-Date must be set!')
|
||||
throw new LogError('A Start-Date must be set')
|
||||
}
|
||||
|
||||
if (!endDate) {
|
||||
logger.error('End-Date is not initialized. An End-Date must be set!')
|
||||
throw new Error('End-Date is not initialized. An End-Date must be set!')
|
||||
throw new LogError('An End-Date must be set')
|
||||
}
|
||||
|
||||
// check if endDate is before startDate
|
||||
if (new Date(endDate).getTime() - new Date(startDate).getTime() < 0) {
|
||||
logger.error(`The value of validFrom must before or equals the validTo!`)
|
||||
throw new Error(`The value of validFrom must before or equals the validTo!`)
|
||||
throw new LogError(`The value of validFrom must before or equals the validTo`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,7 +143,7 @@ export const updateCreations = (
|
||||
const index = getCreationIndex(contribution.contributionDate.getMonth(), timezoneOffset)
|
||||
|
||||
if (index < 0) {
|
||||
throw new Error('You cannot create GDD for a month older than the last three months.')
|
||||
throw new LogError('You cannot create GDD for a month older than the last three months')
|
||||
}
|
||||
creations[index] = creations[index].plus(contribution.amount.toString())
|
||||
return creations
|
||||
|
||||
24
backend/src/graphql/resolver/util/findContributions.ts
Normal file
24
backend/src/graphql/resolver/util/findContributions.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ContributionStatus } from '@enum/ContributionStatus'
|
||||
import { Order } from '@enum/Order'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
import { In } from '@dbTools/typeorm'
|
||||
|
||||
export const findContributions = async (
|
||||
order: Order,
|
||||
currentPage: number,
|
||||
pageSize: number,
|
||||
withDeleted: boolean,
|
||||
statusFilter?: ContributionStatus[],
|
||||
): Promise<[DbContribution[], number]> =>
|
||||
DbContribution.findAndCount({
|
||||
where: {
|
||||
...(statusFilter && statusFilter.length && { contributionStatus: In(statusFilter) }),
|
||||
},
|
||||
withDeleted: withDeleted,
|
||||
order: {
|
||||
createdAt: order,
|
||||
},
|
||||
relations: ['user'],
|
||||
skip: (currentPage - 1) * pageSize,
|
||||
take: pageSize,
|
||||
})
|
||||
@ -1,4 +1,5 @@
|
||||
import CONFIG from '@/config'
|
||||
import LogError from '@/server/LogError'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
import { User } from '@entity/User'
|
||||
import { PasswordEncryptionType } from '@enum/PasswordEncryptionType'
|
||||
@ -16,11 +17,10 @@ export const SecretKeyCryptographyCreateKey = (salt: string, password: string):
|
||||
const configLoginAppSecret = Buffer.from(CONFIG.LOGIN_APP_SECRET, 'hex')
|
||||
const configLoginServerKey = Buffer.from(CONFIG.LOGIN_SERVER_KEY, 'hex')
|
||||
if (configLoginServerKey.length !== sodium.crypto_shorthash_KEYBYTES) {
|
||||
logger.error(
|
||||
`ServerKey has an invalid size. The size must be ${sodium.crypto_shorthash_KEYBYTES} bytes.`,
|
||||
)
|
||||
throw new Error(
|
||||
`ServerKey has an invalid size. The size must be ${sodium.crypto_shorthash_KEYBYTES} bytes.`,
|
||||
throw new LogError(
|
||||
'ServerKey has an invalid size',
|
||||
configLoginServerKey.length,
|
||||
sodium.crypto_shorthash_KEYBYTES,
|
||||
)
|
||||
}
|
||||
|
||||
@ -52,20 +52,13 @@ export const SecretKeyCryptographyCreateKey = (salt: string, password: string):
|
||||
|
||||
export const getUserCryptographicSalt = (dbUser: User): string => {
|
||||
switch (dbUser.passwordEncryptionType) {
|
||||
case PasswordEncryptionType.NO_PASSWORD: {
|
||||
logger.error('Password not set for user ' + dbUser.id)
|
||||
throw new Error('Password not set for user ' + dbUser.id) // user has no password
|
||||
}
|
||||
case PasswordEncryptionType.EMAIL: {
|
||||
case PasswordEncryptionType.NO_PASSWORD:
|
||||
throw new LogError('User has no password set', dbUser.id)
|
||||
case PasswordEncryptionType.EMAIL:
|
||||
return dbUser.emailContact.email
|
||||
break
|
||||
}
|
||||
case PasswordEncryptionType.GRADIDO_ID: {
|
||||
case PasswordEncryptionType.GRADIDO_ID:
|
||||
return dbUser.gradidoID
|
||||
break
|
||||
}
|
||||
default:
|
||||
logger.error(`Unknown password encryption type: ${dbUser.passwordEncryptionType}`)
|
||||
throw new Error(`Unknown password encryption type: ${dbUser.passwordEncryptionType}`)
|
||||
throw new LogError('Unknown password encryption type', dbUser.passwordEncryptionType)
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ export const nMonthsBefore = (date: Date, months = 1): string => {
|
||||
export const creationFactory = async (
|
||||
client: ApolloServerTestClient,
|
||||
creation: CreationInterface,
|
||||
): Promise<Contribution | void> => {
|
||||
): Promise<Contribution> => {
|
||||
const { mutate } = client
|
||||
await mutate({ mutation: login, variables: { email: creation.email, password: 'Aa12345_' } })
|
||||
|
||||
@ -51,6 +51,7 @@ export const creationFactory = async (
|
||||
await confirmedContribution.save()
|
||||
}
|
||||
}
|
||||
return confirmedContribution
|
||||
} else {
|
||||
return contribution
|
||||
}
|
||||
|
||||
@ -126,16 +126,6 @@ export const unDeleteUser = gql`
|
||||
}
|
||||
`
|
||||
|
||||
export const adminCreateContributions = gql`
|
||||
mutation ($pendingCreations: [AdminCreateContributionArgs!]!) {
|
||||
adminCreateContributions(pendingCreations: $pendingCreations) {
|
||||
success
|
||||
successfulContribution
|
||||
failedContribution
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const adminUpdateContribution = gql`
|
||||
mutation ($id: Int!, $email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
|
||||
adminUpdateContribution(
|
||||
@ -272,6 +262,12 @@ export const deleteContribution = gql`
|
||||
}
|
||||
`
|
||||
|
||||
export const denyContribution = gql`
|
||||
mutation ($id: Int!) {
|
||||
denyContribution(id: $id)
|
||||
}
|
||||
`
|
||||
|
||||
export const createContributionMessage = gql`
|
||||
mutation ($contributionId: Float!, $message: String!) {
|
||||
createContributionMessage(contributionId: $contributionId, message: $message) {
|
||||
|
||||
@ -166,6 +166,15 @@ export const listContributions = gql`
|
||||
id
|
||||
amount
|
||||
memo
|
||||
createdAt
|
||||
contributionDate
|
||||
confirmedAt
|
||||
confirmedBy
|
||||
deletedAt
|
||||
state
|
||||
messagesCount
|
||||
deniedAt
|
||||
deniedBy
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,6 +186,40 @@ query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC, $statusF
|
||||
contributionCount
|
||||
contributionList {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
amount
|
||||
memo
|
||||
createdAt
|
||||
confirmedAt
|
||||
confirmedBy
|
||||
contributionDate
|
||||
state
|
||||
messagesCount
|
||||
deniedAt
|
||||
deniedBy
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
// from admin interface
|
||||
|
||||
export const adminListAllContributions = gql`
|
||||
query (
|
||||
$currentPage: Int = 1
|
||||
$pageSize: Int = 25
|
||||
$order: Order = DESC
|
||||
$statusFilter: [ContributionStatus!]
|
||||
) {
|
||||
adminListAllContributions(
|
||||
currentPage: $currentPage
|
||||
pageSize: $pageSize
|
||||
order: $order
|
||||
statusFilter: $statusFilter
|
||||
) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
amount
|
||||
@ -189,24 +232,7 @@ query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC, $statusF
|
||||
messagesCount
|
||||
deniedAt
|
||||
deniedBy
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
// from admin interface
|
||||
|
||||
export const listUnconfirmedContributions = gql`
|
||||
query {
|
||||
listUnconfirmedContributions {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
email
|
||||
amount
|
||||
memo
|
||||
date
|
||||
moderator
|
||||
creation
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -3,6 +3,7 @@ import { User as dbUser } from '@entity/User'
|
||||
import { Transaction as dbTransaction } from '@entity/Transaction'
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { ExpressContext } from 'apollo-server-express'
|
||||
import LogError from './LogError'
|
||||
|
||||
export interface Context {
|
||||
token: string | null
|
||||
@ -35,7 +36,7 @@ const context = (args: ExpressContext): Context => {
|
||||
|
||||
export const getUser = (context: Context): dbUser => {
|
||||
if (context.user) return context.user
|
||||
throw new Error('No user given in context!')
|
||||
throw new LogError('No user given in context')
|
||||
}
|
||||
|
||||
export const getClientTimezoneOffset = (context: Context): number => {
|
||||
@ -45,7 +46,7 @@ export const getClientTimezoneOffset = (context: Context): number => {
|
||||
) {
|
||||
return context.clientTimezoneOffset
|
||||
}
|
||||
throw new Error('No valid client time zone offset in context!')
|
||||
throw new LogError('No valid client time zone offset in context')
|
||||
}
|
||||
|
||||
export default context
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import CONFIG from '@/config'
|
||||
import { Decay } from '@model/Decay'
|
||||
import LogError from '@/server/LogError'
|
||||
|
||||
// TODO: externalize all those definitions and functions into an external decay library
|
||||
|
||||
@ -22,7 +23,7 @@ function calculateDecay(
|
||||
const startBlockMs = startBlock.getTime()
|
||||
|
||||
if (toMs < fromMs) {
|
||||
throw new Error('to < from, reverse decay calculation is invalid')
|
||||
throw new LogError('calculateDecay: to < from, reverse decay calculation is invalid')
|
||||
}
|
||||
|
||||
// Initialize with no decay
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import connection from '@/typeorm/connection'
|
||||
import { getKlickTippUser } from '@/apis/KlicktippController'
|
||||
import { User } from '@entity/User'
|
||||
import LogError from '@/server/LogError'
|
||||
|
||||
export async function retrieveNotRegisteredEmails(): Promise<string[]> {
|
||||
const con = await connection()
|
||||
if (!con) {
|
||||
throw new Error('No connection to database')
|
||||
throw new LogError('No connection to database')
|
||||
}
|
||||
const users = await User.find({ relations: ['emailContact'] })
|
||||
const notRegisteredUser = []
|
||||
|
||||
@ -57,10 +57,15 @@ EMAIL_CODE_REQUEST_TIME=10
|
||||
WEBHOOK_ELOPAGE_SECRET=secret
|
||||
|
||||
# Federation
|
||||
# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen
|
||||
# on an hash created from this topic
|
||||
FEDERATION_DHT_CONFIG_VERSION=v2.2023-02-07
|
||||
# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen on an hash created from this topic
|
||||
# FEDERATION_DHT_TOPIC=GRADIDO_HUB
|
||||
# FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f
|
||||
FEDERATION_COMMUNITY_URL=http://stage1.gradido.net
|
||||
# the api port is the baseport, which will be added with the api-version, e.g. 1_0 = 5010
|
||||
FEDERATION_COMMUNITY_API_PORT=5000
|
||||
|
||||
|
||||
|
||||
# database
|
||||
DATABASE_CONFIG_VERSION=v1.2022-03-18
|
||||
|
||||
@ -137,6 +137,9 @@ envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env
|
||||
# Configure admin
|
||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env
|
||||
|
||||
# Configure dht-node
|
||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env
|
||||
|
||||
# create cronjob to delete yarn output in /tmp
|
||||
# crontab -e
|
||||
# hourly job: 0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null
|
||||
|
||||
@ -93,10 +93,12 @@ cp -f $PROJECT_ROOT/database/.env $PROJECT_ROOT/database/.env.bak
|
||||
cp -f $PROJECT_ROOT/backend/.env $PROJECT_ROOT/backend/.env.bak
|
||||
cp -f $PROJECT_ROOT/frontend/.env $PROJECT_ROOT/frontend/.env.bak
|
||||
cp -f $PROJECT_ROOT/admin/.env $PROJECT_ROOT/admin/.env.bak
|
||||
cp -f $PROJECT_ROOT/dht-node/.env $PROJECT_ROOT/dht-node/.env.bak
|
||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env
|
||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env
|
||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env
|
||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env
|
||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env
|
||||
|
||||
# Install & build database
|
||||
echo 'Updating database' >> $UPDATE_HTML
|
||||
@ -152,6 +154,25 @@ pm2 delete gradido-admin
|
||||
pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||
pm2 save
|
||||
|
||||
# Install & build dht-node
|
||||
echo 'Updating dht-node' >> $UPDATE_HTML
|
||||
cd $PROJECT_ROOT/dht-node
|
||||
# TODO maybe handle this differently?
|
||||
unset NODE_ENV
|
||||
yarn install
|
||||
yarn build
|
||||
# TODO maybe handle this differently?
|
||||
export NODE_ENV=production
|
||||
pm2 delete gradido-dht-node
|
||||
if [ ! -z $FEDERATION_DHT_TOPIC ]; then
|
||||
pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||
else
|
||||
echo "====================================================================="
|
||||
echo "WARNING: FEDERATION_DHT_TOPIC not configured. DHT-Node not started..."
|
||||
echo "====================================================================="
|
||||
fi
|
||||
pm2 save
|
||||
|
||||
# let nginx showing gradido
|
||||
echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML
|
||||
ln -s /etc/nginx/sites-available/gradido.conf /etc/nginx/sites-enabled/
|
||||
|
||||
@ -11,9 +11,9 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.dht-node.log
|
||||
# LOG_LEVEL=info
|
||||
|
||||
# Federation
|
||||
# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen
|
||||
# on an hash created from this topic
|
||||
# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen on an hash created from this topic
|
||||
FEDERATION_DHT_TOPIC=GRADIDO_HUB
|
||||
# FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f
|
||||
# FEDERATION_COMMUNITY_URL=http://localhost
|
||||
# FEDERATION_COMMUNITY_API_PORT=5000
|
||||
# FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f
|
||||
FEDERATION_COMMUNITY_URL=http://localhost
|
||||
# the api port is the dht baseport, which will be added with the supported api-versions, e.g. 1_0 = 5010
|
||||
FEDERATION_COMMUNITY_API_PORT=5000
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
CONFIG_VERSION=$BACKEND_CONFIG_VERSION
|
||||
CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION
|
||||
|
||||
# Database
|
||||
DB_HOST=localhost
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
"pattern": "yyyy-MM-dd",
|
||||
"layout":
|
||||
{
|
||||
"type": "pattern", "pattern": "%d{ISO8601} %c [%X{user}] [%f : %l] - %m"
|
||||
"type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m"
|
||||
},
|
||||
"keepFileExt" : true,
|
||||
"fileNameSep" : "_",
|
||||
@ -21,7 +21,7 @@
|
||||
"pattern": "yyyy-MM-dd",
|
||||
"layout":
|
||||
{
|
||||
"type": "pattern", "pattern": "%d{ISO8601} %c [%X{user}] [%f : %l] - %m"
|
||||
"type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m"
|
||||
},
|
||||
"keepFileExt" : true,
|
||||
"fileNameSep" : "_",
|
||||
|
||||
@ -31,8 +31,8 @@ export const startDHT = async (topic: string): Promise<void> => {
|
||||
logger.info(`keyPairDHT: publicKey=${keyPair.publicKey.toString('hex')}`)
|
||||
logger.debug(`keyPairDHT: secretKey=${keyPair.secretKey.toString('hex')}`)
|
||||
|
||||
const ownApiVersions = writeHomeCommunityEnries(keyPair.publicKey)
|
||||
logger.debug(`ApiList: ${JSON.stringify(ownApiVersions)}`)
|
||||
const ownApiVersions = await writeHomeCommunityEnries(keyPair.publicKey)
|
||||
logger.info(`ApiList: ${JSON.stringify(ownApiVersions)}`)
|
||||
|
||||
const node = new DHT({ keyPair })
|
||||
|
||||
|
||||
@ -123,10 +123,6 @@ Zusätzlich wird als Parameter ein *creationDate* vom User mitgeliefert, das dem
|
||||
|
||||
nothing to do
|
||||
|
||||
#### + adminCreateContributions
|
||||
|
||||
Hier wird eine Liste von übergebenen Contributions über den internen Aufruf von *adminCreateContribution()* verarbeitet. Da dort eine Berücksichtigung des User-TimeOffsets notwendig ist, muss hier die UserTime entsprechen im Context weitergereicht werden.
|
||||
|
||||
#### - adminDeleteContribution
|
||||
|
||||
nothing to do
|
||||
|
||||
BIN
frontend/public/img/brand/gradido-logo.png
Normal file
BIN
frontend/public/img/brand/gradido-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
@ -8,8 +8,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DashboardLayout from '@/layouts/DashboardLayout.vue'
|
||||
import AuthLayout from '@/layouts/AuthLayout.vue'
|
||||
import DashboardLayout from '@/layouts/DashboardLayout'
|
||||
import AuthLayout from '@/layouts/AuthLayout'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
|
||||
@ -3,16 +3,16 @@
|
||||
<b-navbar :toggleable="false" class="pr-4">
|
||||
<b-navbar-brand class="d-none d-lg-block">
|
||||
<b-img
|
||||
class="imgLogo position-absolute ml--3 mt-lg--2 mt-3 p-2 zindex1000"
|
||||
class="position-absolute ml--3 mt-lg--2 mt-3 p-2 zindex1000"
|
||||
:src="logo"
|
||||
width="200"
|
||||
alt="..."
|
||||
alt="Logo"
|
||||
/>
|
||||
<b-img
|
||||
class="imgLogoBack mt--3 ml--3"
|
||||
src="/img/template/gradido_background_header.png"
|
||||
class="mt--3 ml--3"
|
||||
:src="background_header"
|
||||
width="230"
|
||||
alt="start background image"
|
||||
alt="Background Image"
|
||||
></b-img>
|
||||
</b-navbar-brand>
|
||||
<b-img class="sheet-img position-absolute d-block d-lg-none zindex1000" :src="sheet"></b-img>
|
||||
@ -35,7 +35,8 @@ export default {
|
||||
mixins: [authLinks],
|
||||
data() {
|
||||
return {
|
||||
logo: '/img/brand/green.png',
|
||||
background_header: '/img/template/gradido_background_header.png',
|
||||
logo: '/img/brand/gradido-logo.png',
|
||||
sheet: '/img/template/Blaetter.png',
|
||||
}
|
||||
},
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import ContributionMessagesList from './ContributionMessagesList.vue'
|
||||
import ContributionMessagesList from './ContributionMessagesList'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -23,8 +23,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ContributionMessagesListItem from '@/components/ContributionMessages/ContributionMessagesListItem.vue'
|
||||
import ContributionMessagesFormular from '@/components/ContributionMessages/ContributionMessagesFormular.vue'
|
||||
import ContributionMessagesListItem from '@/components/ContributionMessages/ContributionMessagesListItem'
|
||||
import ContributionMessagesFormular from '@/components/ContributionMessages/ContributionMessagesFormular'
|
||||
|
||||
export default {
|
||||
name: 'ContributionMessagesList',
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import ContributionMessagesList from './ContributionMessagesList.vue'
|
||||
import ContributionMessagesListItem from './ContributionMessagesListItem.vue'
|
||||
import ContributionMessagesList from './ContributionMessagesList'
|
||||
import ContributionMessagesListItem from './ContributionMessagesListItem'
|
||||
|
||||
const localVue = global.localVue
|
||||
let wrapper
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
<script>
|
||||
import Avatar from 'vue-avatar'
|
||||
import ParseMessage from '@/components/ContributionMessages/ParseMessage.vue'
|
||||
import ParseMessage from '@/components/ContributionMessages/ParseMessage'
|
||||
|
||||
export default {
|
||||
name: 'ContributionMessagesListItem',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import ContributionForm from './ContributionForm.vue'
|
||||
import ContributionForm from './ContributionForm'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -88,9 +88,9 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import InputHour from '@/components/Inputs/InputHour.vue'
|
||||
import InputAmount from '@/components/Inputs/InputAmount.vue'
|
||||
import InputTextarea from '@/components/Inputs/InputTextarea.vue'
|
||||
import InputHour from '@/components/Inputs/InputHour'
|
||||
import InputAmount from '@/components/Inputs/InputAmount'
|
||||
import InputTextarea from '@/components/Inputs/InputTextarea'
|
||||
|
||||
export default {
|
||||
name: 'ContributionForm',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import ContributionList from './ContributionList.vue'
|
||||
import ContributionList from './ContributionList'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ContributionListItem from '@/components/Contributions/ContributionListItem.vue'
|
||||
import ContributionListItem from '@/components/Contributions/ContributionListItem'
|
||||
|
||||
export default {
|
||||
name: 'ContributionList',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import ContributionListItem from './ContributionListItem.vue'
|
||||
import ContributionListItem from './ContributionListItem'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -104,7 +104,7 @@
|
||||
<script>
|
||||
import Avatar from 'vue-avatar'
|
||||
import CollapseIcon from '../TransactionRows/CollapseIcon'
|
||||
import ContributionMessagesList from '@/components/ContributionMessages/ContributionMessagesList.vue'
|
||||
import ContributionMessagesList from '@/components/ContributionMessages/ContributionMessagesList'
|
||||
import { listContributionMessages } from '../../graphql/queries.js'
|
||||
|
||||
export default {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import OpenCreationsAmount from './OpenCreationsAmount.vue'
|
||||
import OpenCreationsAmount from './OpenCreationsAmount'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import TransactionLink from '@/components/TransactionLinks/TransactionLink.vue'
|
||||
import TransactionLink from '@/components/TransactionLinks/TransactionLink'
|
||||
export default {
|
||||
name: 'CollapseLinksList',
|
||||
components: {
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import DurationRow from '@/components/TransactionRows/DurationRow.vue'
|
||||
import DurationRow from '@/components/TransactionRows/DurationRow'
|
||||
|
||||
export default {
|
||||
name: 'DecayInformation-StartBlock',
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import DurationRow from '@/components/TransactionRows/DurationRow.vue'
|
||||
import DurationRow from '@/components/TransactionRows/DurationRow'
|
||||
|
||||
export default {
|
||||
name: 'DecayInformation-Long',
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import TransactionForm from './TransactionForm.vue'
|
||||
import TransactionForm from './TransactionForm'
|
||||
import flushPromises from 'flush-promises'
|
||||
import { SEND_TYPES } from '@/pages/Send.vue'
|
||||
import DashboardLayout from '@/layouts/DashboardLayout.vue'
|
||||
import { SEND_TYPES } from '@/pages/Send'
|
||||
import DashboardLayout from '@/layouts/DashboardLayout'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -120,10 +120,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { SEND_TYPES } from '@/pages/Send.vue'
|
||||
import InputEmail from '@/components/Inputs/InputEmail.vue'
|
||||
import InputAmount from '@/components/Inputs/InputAmount.vue'
|
||||
import InputTextarea from '@/components/Inputs/InputTextarea.vue'
|
||||
import { SEND_TYPES } from '@/pages/Send'
|
||||
import InputEmail from '@/components/Inputs/InputEmail'
|
||||
import InputAmount from '@/components/Inputs/InputAmount'
|
||||
import InputTextarea from '@/components/Inputs/InputTextarea'
|
||||
|
||||
export default {
|
||||
name: 'TransactionForm',
|
||||
|
||||
@ -19,8 +19,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ClipboardCopy from '../ClipboardCopy.vue'
|
||||
import FigureQrCode from '../QrCode/FigureQrCode.vue'
|
||||
import ClipboardCopy from '../ClipboardCopy'
|
||||
import FigureQrCode from '../QrCode/FigureQrCode'
|
||||
|
||||
export default {
|
||||
name: 'TransactionResultLink',
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Transaction from '@/components/Transaction.vue'
|
||||
import Transaction from '@/components/Transaction'
|
||||
|
||||
export default {
|
||||
name: 'GdtTransactionList',
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import RedeemInformation from '@/components/LinkInformations/RedeemInformation.vue'
|
||||
import RedeemInformation from '@/components/LinkInformations/RedeemInformation'
|
||||
import { authLinks } from '@/mixins/authLinks'
|
||||
|
||||
export default {
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import RedeemInformation from '@/components/LinkInformations/RedeemInformation.vue'
|
||||
import RedeemInformation from '@/components/LinkInformations/RedeemInformation'
|
||||
|
||||
export default {
|
||||
name: 'RedeemSelfCreator',
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import RedeemInformation from '@/components/LinkInformations/RedeemInformation.vue'
|
||||
import RedeemInformation from '@/components/LinkInformations/RedeemInformation'
|
||||
|
||||
export default {
|
||||
name: 'RedeemValid',
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import VueRouter from 'vue-router'
|
||||
import AuthNavbar from './Navbar.vue'
|
||||
import AuthNavbar from './Navbar'
|
||||
|
||||
const localVue = global.localVue
|
||||
localVue.use(VueRouter)
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
<b-navbar toggleable="lg" class="pr-4">
|
||||
<b-navbar-brand>
|
||||
<b-img
|
||||
class="imgLogo mt-lg--2 mt-3 mb-3 d-none d-lg-block zindex10"
|
||||
class="mt-lg--2 mt-3 mb-3 d-none d-lg-block zindex10"
|
||||
:src="logo"
|
||||
width=""
|
||||
alt="..."
|
||||
width="200"
|
||||
alt="Logo"
|
||||
/>
|
||||
<div v-b-toggle.sidebar-mobile variant="link" class="d-block d-lg-none">
|
||||
<span class="navbar-toggler-icon h2"></span>
|
||||
@ -60,7 +60,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
logo: '/img/brand/green.png',
|
||||
logo: '/img/brand/gradido-logo.png',
|
||||
sheet: '/img/template/Blaetter.png',
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Sidebar from './Sidebar.vue'
|
||||
import Sidebar from './Sidebar'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Sidebar from '@/components/Menu/Sidebar.vue'
|
||||
import Sidebar from '@/components/Menu/Sidebar'
|
||||
|
||||
export default {
|
||||
name: 'MobileSidebar',
|
||||
|
||||
@ -2,19 +2,19 @@
|
||||
<div class="nav-community container">
|
||||
<b-row class="nav-row">
|
||||
<b-col cols="12" lg="4" md="4" class="px-0">
|
||||
<b-btn active-class="btn-active" block variant="link" to="/community#edit">
|
||||
<b-btn to="contribute" active-class="btn-active" block variant="link">
|
||||
<b-icon icon="pencil" class="mr-2" />
|
||||
{{ $t('community.submitContribution') }}
|
||||
</b-btn>
|
||||
</b-col>
|
||||
<b-col cols="12" lg="4" md="4" class="px-0">
|
||||
<b-btn active-class="btn-active" block variant="link" to="/community#my">
|
||||
<b-btn to="contributions" active-class="btn-active" block variant="link">
|
||||
<b-icon icon="person" class="mr-2" />
|
||||
{{ $t('community.myContributions') }}
|
||||
</b-btn>
|
||||
</b-col>
|
||||
<b-col cols="12" lg="4" md="4" class="px-0">
|
||||
<b-btn active-class="btn-active" block variant="link" to="/community#all">
|
||||
<b-btn to="community" active-class="btn-active" block variant="link">
|
||||
<b-icon icon="people" class="mr-2" />
|
||||
{{ $t('community.community') }}
|
||||
</b-btn>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user