From 2146c98ee46e4cadd7a40d3b693ce2631d8e679d Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 9 Mar 2023 20:42:07 +0100 Subject: [PATCH 01/24] Add moderatorId for contribution object. --- admin/src/components/Tables/OpenCreationsTable.vue | 3 ++- admin/src/graphql/adminListAllContributions.js | 1 + backend/src/graphql/model/Contribution.ts | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index a17d3a185..b76decdb5 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -27,9 +27,10 @@ @@ -119,6 +119,7 @@ import { toggleRowDetails } from '../../mixins/toggleRowDetails' import RowDetails from '../RowDetails' import EditCreationFormular from '../EditCreationFormular' import ContributionMessagesList from '../ContributionMessages/ContributionMessagesList' +import { openCreations } from '../../graphql/openCreations' const iconMap = { IN_PROGRESS: 'question-square', @@ -187,6 +188,22 @@ export default { updateState(id) { this.$emit('update-state', id) }, + getOpenCreations(userId) { + this.$apollo + .query({ + query: openCreations, + variables: { + userId, + }, + }) + .then(({ data: { openCreations } }) => { + console.log(openCreations.map((obj) => obj.amount)) + return openCreations.map((obj) => obj.amount) + }) + .catch((error) => { + console.log(error) + }) + }, }, } diff --git a/admin/src/graphql/adminListAllContributions.js b/admin/src/graphql/adminListAllContributions.js index 851cff7b8..9f360f6dc 100644 --- a/admin/src/graphql/adminListAllContributions.js +++ b/admin/src/graphql/adminListAllContributions.js @@ -31,6 +31,7 @@ export const adminListAllContributions = gql` deletedAt deletedBy moderatorId + userId } } } diff --git a/admin/src/graphql/adminUpdateContribution.js b/admin/src/graphql/adminUpdateContribution.js index b7c834109..7738640e7 100644 --- a/admin/src/graphql/adminUpdateContribution.js +++ b/admin/src/graphql/adminUpdateContribution.js @@ -1,14 +1,8 @@ import gql from 'graphql-tag' export const adminUpdateContribution = gql` - mutation ($id: Int!, $email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) { - adminUpdateContribution( - id: $id - email: $email - amount: $amount - memo: $memo - creationDate: $creationDate - ) { + mutation ($id: Int!, $amount: Decimal!, $memo: String!, $creationDate: String!) { + adminUpdateContribution(id: $id, amount: $amount, memo: $memo, creationDate: $creationDate) { amount date memo diff --git a/admin/src/graphql/openCreations.js b/admin/src/graphql/openCreations.js index f6da9600c..010ed62df 100644 --- a/admin/src/graphql/openCreations.js +++ b/admin/src/graphql/openCreations.js @@ -2,7 +2,7 @@ import gql from 'graphql-tag' export const openCreations = gql` query ($userId: Int) { - openCreations(userId: $userID) { + openCreations(userId: $userId) { year month amount diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index 55caf8677..faea501bb 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -44,7 +44,7 @@ :fields="fields" @show-overlay="showOverlay" @update-state="updateStatus" - @update-contributions="$apollo.queries.AllContributions.refetch()" + @update-contributions="$apollo.queries.ListAllContributions.refetch()" /> Date: Fri, 10 Mar 2023 11:36:08 +0100 Subject: [PATCH 05/24] remove email from admin update contribution --- .../arg/AdminUpdateContributionArgs.ts | 3 -- backend/src/graphql/model/Contribution.ts | 6 +++- .../graphql/resolver/ContributionResolver.ts | 28 ++++++------------- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/backend/src/graphql/arg/AdminUpdateContributionArgs.ts b/backend/src/graphql/arg/AdminUpdateContributionArgs.ts index 392365b38..65f1cf3f3 100644 --- a/backend/src/graphql/arg/AdminUpdateContributionArgs.ts +++ b/backend/src/graphql/arg/AdminUpdateContributionArgs.ts @@ -6,9 +6,6 @@ export default class AdminUpdateContributionArgs { @Field(() => Int) id: number - @Field(() => String) - email: string - @Field(() => Decimal) amount: Decimal diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index 69b372e40..989dd32b2 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -22,6 +22,7 @@ export class Contribution { this.deletedAt = contribution.deletedAt this.deletedBy = contribution.deletedBy this.moderatorId = contribution.moderatorId + this.userId = contribution.userId } @Field(() => Number) @@ -69,8 +70,11 @@ export class Contribution { @Field(() => String) state: string - @Field(() => Number, { nullable: true }) + @Field(() => Int, { nullable: true }) moderatorId: number | null + + @Field(() => Int, { nullable: true }) + userId: number | null } @ObjectType() diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 2469f60ba..561d5c88c 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -313,41 +313,27 @@ export class ContributionResolver { @Authorized([RIGHTS.ADMIN_UPDATE_CONTRIBUTION]) @Mutation(() => AdminUpdateContribution) async adminUpdateContribution( - @Args() { id, email, amount, memo, creationDate }: AdminUpdateContributionArgs, + @Args() { id, amount, memo, creationDate }: AdminUpdateContributionArgs, @Ctx() context: Context, ): Promise { const clientTimezoneOffset = getClientTimezoneOffset(context) - const emailContact = await UserContact.findOne({ - where: { email }, - withDeleted: true, - relations: ['user'], - }) - if (!emailContact || !emailContact.user) { - throw new LogError('Could not find User', email) - } - if (emailContact.deletedAt || emailContact.user.deletedAt) { - throw new LogError('User was deleted', email) - } const moderator = getUser(context) const contributionToUpdate = await DbContribution.findOne({ where: { id, confirmedAt: IsNull(), deniedAt: IsNull() }, }) + if (!contributionToUpdate) { throw new LogError('Contribution not found', id) } - if (contributionToUpdate.userId !== emailContact.user.id) { - throw new LogError('User of the pending contribution and send user does not correspond') - } - if (contributionToUpdate.moderatorId === null) { throw new LogError('An admin is not allowed to update an user contribution') } const creationDateObj = new Date(creationDate) - let creations = await getUserCreation(emailContact.user.id, clientTimezoneOffset) + let creations = await getUserCreation(contributionToUpdate.userId, clientTimezoneOffset) // TODO: remove this restriction if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) { @@ -371,9 +357,13 @@ export class ContributionResolver { result.memo = contributionToUpdate.memo result.date = contributionToUpdate.contributionDate - result.creation = await getUserCreation(emailContact.user.id, clientTimezoneOffset) + result.creation = await getUserCreation(contributionToUpdate.userId, clientTimezoneOffset) - await EVENT_ADMIN_CONTRIBUTION_UPDATE(emailContact.user.id, contributionToUpdate.id, amount) + await EVENT_ADMIN_CONTRIBUTION_UPDATE( + contributionToUpdate.userId, + contributionToUpdate.id, + amount, + ) return result } From 5ac70867dfca0e51a5915adfecfdfb4712a260a4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 10 Mar 2023 11:54:28 +0100 Subject: [PATCH 06/24] admin open creations query --- backend/src/auth/RIGHTS.ts | 1 + .../graphql/resolver/ContributionResolver.ts | 24 ++++++++----------- .../src/graphql/resolver/util/creations.ts | 18 +++++++++++++- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index 8b0e82c86..22be48e40 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -54,4 +54,5 @@ export enum RIGHTS { UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK', ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE', DENY_CONTRIBUTION = 'DENY_CONTRIBUTION', + ADMIN_OPEN_CREATIONS = 'ADMIN_OPEN_CREATIONS', } diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 561d5c88c..49ab5fd15 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -27,11 +27,11 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { - getCreationDates, getUserCreation, validateContribution, updateCreations, isValidDateString, + getOpenCreations, } from './util/creations' import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { @@ -570,21 +570,17 @@ export class ContributionResolver { @Authorized([RIGHTS.OPEN_CREATIONS]) @Query(() => [OpenCreation]) - async openCreations( - @Arg('userId', () => Int, { nullable: true }) userId: number | null, + async openCreations(@Ctx() context: Context): Promise { + return getOpenCreations(getUser(context).id, getClientTimezoneOffset(context)) + } + + @Authorized([RIGHTS.ADMIN_OPEN_CREATIONS]) + @Query(() => [OpenCreation]) + async adminOpenCreations( + @Arg('userId', () => Int) userId: number, @Ctx() context: Context, ): Promise { - const id = userId || getUser(context).id - const clientTimezoneOffset = getClientTimezoneOffset(context) - const creationDates = getCreationDates(clientTimezoneOffset) - const creations = await getUserCreation(id, clientTimezoneOffset) - return creationDates.map((date, index) => { - return { - month: date.getMonth(), - year: date.getFullYear(), - amount: creations[index], - } - }) + return getOpenCreations(userId, getClientTimezoneOffset(context)) } @Authorized([RIGHTS.DENY_CONTRIBUTION]) diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index b9ba2e69f..8453781ca 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -4,6 +4,7 @@ import { getConnection } from '@dbTools/typeorm' import { Contribution } from '@entity/Contribution' import Decimal from 'decimal.js-light' import { FULL_CREATION_AVAILABLE, MAX_CREATION_AMOUNT } from '../const/const' +import { OpenCreation } from '@model/OpenCreation' interface CreationMap { id: number @@ -100,7 +101,7 @@ const getCreationMonths = (timezoneOffset: number): number[] => { return getCreationDates(timezoneOffset).map((date) => date.getMonth() + 1) } -export const getCreationDates = (timezoneOffset: number): Date[] => { +const getCreationDates = (timezoneOffset: number): Date[] => { const clientNow = new Date() clientNow.setTime(clientNow.getTime() - timezoneOffset * 60 * 1000) logger.info( @@ -152,3 +153,18 @@ export const updateCreations = ( export const isValidDateString = (dateString: string): boolean => { return new Date(dateString).toString() !== 'Invalid Date' } + +export const getOpenCreations = async ( + id: number, + timezoneOffset: number, +): Promise => { + const creations = await getUserCreation(id, timezoneOffset) + const creationDates = getCreationDates(timezoneOffset) + return creationDates.map((date, index) => { + return { + month: date.getMonth(), + year: date.getFullYear(), + amount: creations[index], + } + }) +} From e07da27414d630e41ab103a05c62953a3ef3e5ed Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 10 Mar 2023 12:48:27 +0100 Subject: [PATCH 07/24] get it working again --- admin/src/components/CreationFormular.vue | 9 +++--- admin/src/components/EditCreationFormular.vue | 17 +++++----- .../components/Tables/OpenCreationsTable.vue | 18 ----------- admin/src/graphql/adminOpenCreations.js | 11 +++++++ admin/src/graphql/openCreations.js | 11 ------- admin/src/mixins/creationMonths.js | 31 ++++++++++++++++--- 6 files changed, 50 insertions(+), 47 deletions(-) create mode 100644 admin/src/graphql/adminOpenCreations.js delete mode 100644 admin/src/graphql/openCreations.js diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue index 137b46400..c6bade1a1 100644 --- a/admin/src/components/CreationFormular.vue +++ b/admin/src/components/CreationFormular.vue @@ -117,10 +117,6 @@ export default { return {} }, }, - creation: { - type: Array, - required: true, - }, }, data() { return { @@ -129,6 +125,7 @@ export default { rangeMin: 0, rangeMax: 1000, selected: '', + userId: this.item.userId, } }, methods: { @@ -167,6 +164,10 @@ export default { this.$refs.creationForm.reset() this.value = 0 }) + .finally(() => { + this.$apollo.queries.OpenCreations.refetch() + this.selected = '' + }) }, }, watch: { diff --git a/admin/src/components/EditCreationFormular.vue b/admin/src/components/EditCreationFormular.vue index fbc60df15..1d22460c7 100644 --- a/admin/src/components/EditCreationFormular.vue +++ b/admin/src/components/EditCreationFormular.vue @@ -75,7 +75,6 @@ diff --git a/admin/src/graphql/adminOpenCreations.js b/admin/src/graphql/adminOpenCreations.js new file mode 100644 index 000000000..0e766c0f7 --- /dev/null +++ b/admin/src/graphql/adminOpenCreations.js @@ -0,0 +1,11 @@ +import gql from 'graphql-tag' + +export const adminOpenCreations = gql` + query ($userId: Int!) { + adminOpenCreations(userId: $userId) { + year + month + amount + } + } +` diff --git a/admin/src/graphql/openCreations.js b/admin/src/graphql/openCreations.js deleted file mode 100644 index 010ed62df..000000000 --- a/admin/src/graphql/openCreations.js +++ /dev/null @@ -1,11 +0,0 @@ -import gql from 'graphql-tag' - -export const openCreations = gql` - query ($userId: Int) { - openCreations(userId: $userId) { - year - month - amount - } - } -` diff --git a/admin/src/mixins/creationMonths.js b/admin/src/mixins/creationMonths.js index c26dc5b02..57e0ab17e 100644 --- a/admin/src/mixins/creationMonths.js +++ b/admin/src/mixins/creationMonths.js @@ -1,9 +1,11 @@ +import { adminOpenCreations } from '../graphql/adminOpenCreations' + export const creationMonths = { - props: { - creation: { - type: Array, - default: () => [1000, 1000, 1000], - }, + data() { + return { + creation: [1000, 1000, 1000], + userId: 0, + } }, computed: { creationDates() { @@ -38,4 +40,23 @@ export const creationMonths = { return this.creationDates.map((date) => this.$d(date, 'monthShort')).join(' | ') }, }, + apollo: { + OpenCreations: { + query() { + return adminOpenCreations + }, + variables() { + return { + userId: this.userId, + } + }, + fetchPolicy: 'no-cache', + update({ adminOpenCreations }) { + this.creation = adminOpenCreations.map((obj) => obj.amount) + }, + error({ message }) { + this.toastError(message) + }, + }, + }, } From edd42f02edc4ab67e1b47b2a13221461347999b3 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 10 Mar 2023 14:08:08 +0100 Subject: [PATCH 08/24] fix edit contribution formular, remove unused methods --- .../components/EditCreationFormular.spec.js | 120 ++++++++++-------- admin/src/components/EditCreationFormular.vue | 12 +- .../Tables/OpenCreationsTable.spec.js | 6 +- .../components/Tables/OpenCreationsTable.vue | 22 +--- admin/src/graphql/adminUpdateContribution.js | 1 - 5 files changed, 76 insertions(+), 85 deletions(-) diff --git a/admin/src/components/EditCreationFormular.spec.js b/admin/src/components/EditCreationFormular.spec.js index 4a304dc79..ee0458ba2 100644 --- a/admin/src/components/EditCreationFormular.spec.js +++ b/admin/src/components/EditCreationFormular.spec.js @@ -1,19 +1,18 @@ import { mount } from '@vue/test-utils' import EditCreationFormular from './EditCreationFormular' import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup' +import VueApollo from 'vue-apollo' +import { createMockClient } from 'mock-apollo-client' +import { adminOpenCreations } from '../graphql/adminOpenCreations' +import { adminUpdateContribution } from '../graphql/adminUpdateContribution' + +const mockClient = createMockClient() +const apolloProvider = new VueApollo({ + defaultClient: mockClient, +}) const localVue = global.localVue - -const apolloMutateMock = jest.fn().mockResolvedValue({ - data: { - adminUpdateContribution: { - creation: [0, 0, 0], - amount: 500, - date: new Date(), - memo: 'Test Schöpfung 2', - }, - }, -}) +localVue.use(VueApollo) const stateCommitMock = jest.fn() @@ -23,22 +22,18 @@ const mocks = { const date = new Date(d) return date.toISOString().split('T')[0] }), - $apollo: { - mutate: apolloMutateMock, - }, $store: { commit: stateCommitMock, }, } -const now = new Date(Date.now()) +const now = new Date() const getCreationDate = (sub) => { const date = sub === 0 ? now : new Date(now.getFullYear(), now.getMonth() - sub, 1, 0) return date.toISOString().split('T')[0] } const propsData = { - creation: [200, 400, 600], creationUserData: { memo: 'Test schöpfung 1', amount: 100, @@ -46,20 +41,65 @@ const propsData = { }, item: { id: 0, - email: 'bob@baumeister.de', + amount: '300', + contributionDate: `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`, }, } +const data = () => { + return { creation: ['1000', '1000', '400'] } +} + describe('EditCreationFormular', () => { let wrapper + const adminUpdateContributionMock = jest.fn() + const adminOpenCreationsMock = jest.fn() + mockClient.setRequestHandler( + adminOpenCreations, + adminOpenCreationsMock.mockResolvedValue({ + data: { + adminOpenCreations: [ + { + month: new Date(now.getFullYear(), now.getMonth() - 2).getMonth(), + year: new Date(now.getFullYear(), now.getMonth() - 2).getFullYear(), + amount: '1000', + }, + { + month: new Date(now.getFullYear(), now.getMonth() - 1).getMonth(), + year: new Date(now.getFullYear(), now.getMonth() - 1).getFullYear(), + amount: '1000', + }, + { + month: now.getMonth(), + year: now.getFullYear(), + amount: '400', + }, + ], + }, + }), + ) + mockClient.setRequestHandler( + adminUpdateContribution, + adminUpdateContributionMock.mockResolvedValue({ + data: { + adminUpdateContribution: { + amount: '600', + date: new Date(), + memo: 'This is my memo', + }, + }, + }), + ) + const Wrapper = () => { - return mount(EditCreationFormular, { localVue, mocks, propsData }) + return mount(EditCreationFormular, { localVue, mocks, propsData, data, apolloProvider }) } describe('mount', () => { - beforeEach(() => { + beforeEach(async () => { wrapper = Wrapper() + await wrapper.vm.$nextTick() }) it('has a DIV element with the class.component-edit-creation-formular', () => { @@ -89,42 +129,16 @@ describe('EditCreationFormular', () => { }) it('calls the API', () => { - expect(apolloMutateMock).toBeCalledWith( - expect.objectContaining({ - variables: { - id: 0, - email: 'bob@baumeister.de', - creationDate: getCreationDate(0), - amount: 500, - memo: 'Test Schöpfung 2', - }, - }), - ) - }) - - it('emits update-user-data', () => { - expect(wrapper.emitted('update-user-data')).toEqual([ - [ - { - id: 0, - email: 'bob@baumeister.de', - }, - [0, 0, 0], - ], - ]) + expect(adminUpdateContributionMock).toBeCalledWith({ + id: 0, + creationDate: getCreationDate(0), + amount: 500, + memo: 'Test Schöpfung 2', + }) }) it('emits update-creation-data', () => { - expect(wrapper.emitted('update-creation-data')).toEqual([ - [ - { - amount: 500, - date: expect.any(Date), - memo: 'Test Schöpfung 2', - row: expect.any(Object), - }, - ], - ]) + expect(wrapper.emitted('update-creation-data')).toBeTruthy() }) it('toasts a success message', () => { @@ -134,7 +148,7 @@ describe('EditCreationFormular', () => { describe('change and save memo and value with error', () => { beforeEach(async () => { - apolloMutateMock.mockRejectedValue({ message: 'Oh no!' }) + adminUpdateContributionMock.mockRejectedValue({ message: 'Oh no!' }) await wrapper.find('input[type="number"]').setValue(500) await wrapper.find('textarea').setValue('Test Schöpfung 2') await wrapper.find('.test-submit').trigger('click') diff --git a/admin/src/components/EditCreationFormular.vue b/admin/src/components/EditCreationFormular.vue index 1d22460c7..994a734f6 100644 --- a/admin/src/components/EditCreationFormular.vue +++ b/admin/src/components/EditCreationFormular.vue @@ -108,6 +108,7 @@ export default { }, methods: { submitCreation() { + // console.log('submitCreation', this.selected) this.$apollo .mutate({ mutation: adminUpdateContribution, @@ -119,12 +120,7 @@ export default { }, }) .then((result) => { - this.$emit('update-creation-data', { - amount: Number(result.data.adminUpdateContribution.amount), - date: result.data.adminUpdateContribution.date, - memo: result.data.adminUpdateContribution.memo, - row: this.row, - }) + this.$emit('update-creation-data') this.toastSuccess( this.$t('creation_form.toasted_update', { value: this.value, @@ -151,7 +147,9 @@ export default { computed: { creationIndex() { const month = this.$d(new Date(this.item.contributionDate), 'month') - return this.radioOptions.findIndex((obj) => obj.item.short === month) + return this.radioOptions.findIndex((obj) => { + return obj.item.short === month + }) }, selectedComputed() { return this.radioOptions[this.creationIndex].item diff --git a/admin/src/components/Tables/OpenCreationsTable.spec.js b/admin/src/components/Tables/OpenCreationsTable.spec.js index 6542dab31..4cd40017c 100644 --- a/admin/src/components/Tables/OpenCreationsTable.spec.js +++ b/admin/src/components/Tables/OpenCreationsTable.spec.js @@ -17,7 +17,7 @@ const propsData = { amount: 300, memo: 'Aktives Grundeinkommen für Januar 2022', date: '2022-01-01T00:00:00.000Z', - moderator: 1, + moderatorId: 1, creation: [700, 1000, 1000], __typename: 'PendingCreation', }, @@ -29,7 +29,7 @@ const propsData = { amount: 210, memo: 'Aktives Grundeinkommen für Januar 2022', date: '2022-01-01T00:00:00.000Z', - moderator: null, + moderatorId: null, creation: [790, 1000, 1000], __typename: 'PendingCreation', }, @@ -41,7 +41,7 @@ const propsData = { amount: 330, memo: 'Aktives Grundeinkommen für Januar 2022', date: '2022-01-01T00:00:00.000Z', - moderator: 1, + moderatorId: 1, creation: [670, 1000, 1000], __typename: 'PendingCreation', }, diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index 3b89a7d8c..9e0f3c747 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -96,7 +96,7 @@ :item="row.item" :row="row" :creationUserData="creationUserData" - @update-creation-data="updateCreationData" + @update-creation-data="$emit('update-contributions')" />
@@ -145,16 +145,6 @@ export default { required: true, }, }, - data() { - return { - creationUserData: { - amount: null, - date: null, - memo: null, - moderator: null, - }, - } - }, methods: { myself(item) { return ( @@ -173,16 +163,6 @@ export default { if (item.state === 'IN_PROGRESS') return 'table-primary' if (item.state === 'PENDING') return 'table-primary' }, - updateCreationData(data) { - const row = data.row - this.$emit('update-contributions', data) - delete data.row - this.creationUserData = { ...this.creationUserData, ...data } - row.toggleDetails() - }, - updateUserData(rowItem, newCreation) { - rowItem.creation = newCreation - }, updateState(id) { this.$emit('update-state', id) }, diff --git a/admin/src/graphql/adminUpdateContribution.js b/admin/src/graphql/adminUpdateContribution.js index 7738640e7..c52a0cbc4 100644 --- a/admin/src/graphql/adminUpdateContribution.js +++ b/admin/src/graphql/adminUpdateContribution.js @@ -6,7 +6,6 @@ export const adminUpdateContribution = gql` amount date memo - creation } } ` From 0f01027f6b8ae8cfc44c143511b18f05969d7d45 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 10 Mar 2023 14:11:17 +0100 Subject: [PATCH 09/24] fix open creation tests. remove tests for removed methods --- .../Tables/OpenCreationsTable.spec.js | 44 ------------------- 1 file changed, 44 deletions(-) diff --git a/admin/src/components/Tables/OpenCreationsTable.spec.js b/admin/src/components/Tables/OpenCreationsTable.spec.js index 4cd40017c..cfb91be0d 100644 --- a/admin/src/components/Tables/OpenCreationsTable.spec.js +++ b/admin/src/components/Tables/OpenCreationsTable.spec.js @@ -5,7 +5,6 @@ const localVue = global.localVue const apolloMutateMock = jest.fn().mockResolvedValue({}) const apolloQueryMock = jest.fn().mockResolvedValue({}) -const toggleDetailsMock = jest.fn() const propsData = { items: [ @@ -132,14 +131,6 @@ describe('OpenCreationsTable', () => { }) }) - describe('call updateUserData', () => { - it('user creations has updated data', async () => { - wrapper.vm.updateUserData(propsData.items[0], [444, 555, 666]) - await wrapper.vm.$nextTick() - expect(wrapper.vm.items[0].creation).toEqual([444, 555, 666]) - }) - }) - describe('call updateState', () => { beforeEach(() => { wrapper.vm.updateState(4) @@ -149,40 +140,5 @@ describe('OpenCreationsTable', () => { expect(wrapper.vm.$root.$emit('update-state', 4)).toBeTruthy() }) }) - - describe('call updateCreationData', () => { - const date = new Date() - beforeEach(() => { - wrapper.vm.updateCreationData({ - amount: Number(80.0), - date: date, - memo: 'Test memo', - row: { - item: {}, - detailsShowing: false, - toggleDetails: toggleDetailsMock, - }, - }) - }) - - it('emits update-state', () => { - expect( - wrapper.vm.$emit('update-contributions', { - amount: Number(80.0), - date: date, - memo: 'Test memo', - row: { - item: {}, - detailsShowing: false, - toggleDetails: toggleDetailsMock, - }, - }), - ).toBeTruthy() - }) - - it('calls toggleDetails', () => { - expect(toggleDetailsMock).toBeCalled() - }) - }) }) }) From cef0e00f6eec4451997a517cb6a0b496d8c87ef4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 10 Mar 2023 14:22:07 +0100 Subject: [PATCH 10/24] fix tests --- admin/src/components/CreationFormular.spec.js | 79 +++++++++++++------ admin/src/components/CreationFormular.vue | 3 +- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/admin/src/components/CreationFormular.spec.js b/admin/src/components/CreationFormular.spec.js index 5dba2d931..c22b319a9 100644 --- a/admin/src/components/CreationFormular.spec.js +++ b/admin/src/components/CreationFormular.spec.js @@ -2,14 +2,18 @@ import { mount } from '@vue/test-utils' import CreationFormular from './CreationFormular' import { adminCreateContribution } from '../graphql/adminCreateContribution' import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup' +import VueApollo from 'vue-apollo' +import { createMockClient } from 'mock-apollo-client' +import { adminOpenCreations } from '../graphql/adminOpenCreations' + +const mockClient = createMockClient() +const apolloProvider = new VueApollo({ + defaultClient: mockClient, +}) const localVue = global.localVue +localVue.use(VueApollo) -const apolloMutateMock = jest.fn().mockResolvedValue({ - data: { - adminCreateContribution: [0, 0, 0], - }, -}) const stateCommitMock = jest.fn() const mocks = { @@ -18,9 +22,6 @@ const mocks = { const date = new Date(d) return date.toISOString().split('T')[0] }), - $apollo: { - mutate: apolloMutateMock, - }, $store: { commit: stateCommitMock, }, @@ -31,7 +32,8 @@ const propsData = { creation: [], } -const now = new Date(Date.now()) +const now = new Date() + const getCreationDate = (sub) => { const date = sub === 0 ? now : new Date(now.getFullYear(), now.getMonth() - sub, 1, 0) return date.toISOString().split('T')[0] @@ -40,8 +42,43 @@ const getCreationDate = (sub) => { describe('CreationFormular', () => { let wrapper + const adminOpenCreationsMock = jest.fn() + const adminCreateContributionMock = jest.fn() + mockClient.setRequestHandler( + adminOpenCreations, + adminOpenCreationsMock.mockResolvedValue({ + data: { + adminOpenCreations: [ + { + month: new Date(now.getFullYear(), now.getMonth() - 2).getMonth(), + year: new Date(now.getFullYear(), now.getMonth() - 2).getFullYear(), + amount: '200', + }, + { + month: new Date(now.getFullYear(), now.getMonth() - 1).getMonth(), + year: new Date(now.getFullYear(), now.getMonth() - 1).getFullYear(), + amount: '400', + }, + { + month: now.getMonth(), + year: now.getFullYear(), + amount: '600', + }, + ], + }, + }), + ) + mockClient.setRequestHandler( + adminCreateContribution, + adminCreateContributionMock.mockResolvedValue({ + data: { + adminCreateContribution: [0, 0, 0], + }, + }), + ) + const Wrapper = () => { - return mount(CreationFormular, { localVue, mocks, propsData }) + return mount(CreationFormular, { localVue, mocks, propsData, apolloProvider }) } describe('mount', () => { @@ -107,17 +144,11 @@ describe('CreationFormular', () => { }) it('sends ... to apollo', () => { - expect(apolloMutateMock).toBeCalledWith( - expect.objectContaining({ - mutation: adminCreateContribution, - variables: { - email: 'benjamin@bluemchen.de', - creationDate: getCreationDate(2), - amount: 90, - memo: 'Test create coins', - }, - }), - ) + expect(adminCreateContributionMock).toBeCalledWith({ + creationDate: getCreationDate(2), + amount: 90, + memo: 'Test create coins', + }) }) it('emits update-user-data', () => { @@ -144,7 +175,7 @@ describe('CreationFormular', () => { describe('sendForm with server error', () => { beforeEach(async () => { - apolloMutateMock.mockRejectedValueOnce({ message: 'Ouch!' }) + adminCreateContributionMock.mockRejectedValueOnce({ message: 'Ouch!' }) await wrapper.find('.test-submit').trigger('click') }) @@ -212,7 +243,7 @@ describe('CreationFormular', () => { }) it('sends ... to apollo', () => { - expect(apolloMutateMock).toBeCalled() + expect(adminCreateContributionMock).toBeCalled() }) }) @@ -275,7 +306,7 @@ describe('CreationFormular', () => { }) it('sends mutation to apollo', () => { - expect(apolloMutateMock).toBeCalled() + expect(adminCreateContributionMock).toBeCalled() }) it('toast success message', () => { diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue index c6bade1a1..aeaa84cc6 100644 --- a/admin/src/components/CreationFormular.vue +++ b/admin/src/components/CreationFormular.vue @@ -133,14 +133,13 @@ export default { // do we want to reset the memo everytime the month changes? this.text = this.$t('creation_form.creation_for') + ' ' + name.short + ' ' + name.year this.rangeMin = 0 - this.rangeMax = name.creation + this.rangeMax = Number(name.creation) }, submitCreation() { this.$apollo .mutate({ mutation: adminCreateContribution, variables: { - email: this.item.email, creationDate: this.selected.date, amount: Number(this.value), memo: this.text, From d56390bad0396058a4b1e31c7e4f6f216a8cae3a Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 10 Mar 2023 14:22:45 +0100 Subject: [PATCH 11/24] remove creation from admin update contribution --- backend/src/graphql/resolver/ContributionResolver.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 49ab5fd15..b9c73cec5 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -357,8 +357,6 @@ export class ContributionResolver { result.memo = contributionToUpdate.memo result.date = contributionToUpdate.contributionDate - result.creation = await getUserCreation(contributionToUpdate.userId, clientTimezoneOffset) - await EVENT_ADMIN_CONTRIBUTION_UPDATE( contributionToUpdate.userId, contributionToUpdate.id, From 3d41f1d9f36b7e32b4febc9d7864d29bb8339196 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 10 Mar 2023 14:24:34 +0100 Subject: [PATCH 12/24] moderator to moderatorId --- admin/src/pages/Overview.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/src/pages/Overview.spec.js b/admin/src/pages/Overview.spec.js index beb5bc2dd..23585611c 100644 --- a/admin/src/pages/Overview.spec.js +++ b/admin/src/pages/Overview.spec.js @@ -42,7 +42,7 @@ const defaultData = () => { amount: 500, memo: 'Danke für alles', date: new Date(), - moderator: 1, + moderatorId: 1, state: 'PENDING', creation: [500, 500, 500], messagesCount: 0, @@ -64,7 +64,7 @@ const defaultData = () => { amount: 1000000, memo: 'Gut Ergattert', date: new Date(), - moderator: 1, + moderatorId: 1, state: 'PENDING', creation: [500, 500, 500], messagesCount: 0, From d9f5c1e89e252f49aa3f2e06bca5259b74e104b6 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 10 Mar 2023 14:28:27 +0100 Subject: [PATCH 13/24] use moderator id to identify myself --- admin/src/components/Tables/OpenCreationsTable.spec.js | 2 +- admin/src/components/Tables/OpenCreationsTable.vue | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/admin/src/components/Tables/OpenCreationsTable.spec.js b/admin/src/components/Tables/OpenCreationsTable.spec.js index cfb91be0d..8f91aca03 100644 --- a/admin/src/components/Tables/OpenCreationsTable.spec.js +++ b/admin/src/components/Tables/OpenCreationsTable.spec.js @@ -82,7 +82,7 @@ const mocks = { $store: { state: { moderator: { - id: 0, + id: 1, name: 'test moderator', }, }, diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index 9e0f3c747..9d93eba60 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -147,10 +147,7 @@ export default { }, methods: { myself(item) { - return ( - `${item.firstName} ${item.lastName}` === - `${this.$store.state.moderator.firstName} ${this.$store.state.moderator.lastName}` - ) + return item.userId === this.$store.state.moderator.id }, getStatusIcon(status) { return iconMap[status] ? iconMap[status] : 'default-icon' From f8cc681e06102b2d4e827c736e966c78f65c1311 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 10 Mar 2023 15:26:07 +0100 Subject: [PATCH 14/24] fix unit tests --- .../resolver/ContributionResolver.test.ts | 18 +++--------------- backend/src/seeds/graphql/mutations.ts | 11 ++--------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 274067ba0..944d9a03c 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -434,7 +434,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: pendingContribution.data.createContribution.id, - email: 'bibi@bloxberg.de', amount: 10.0, memo: 'Test env contribution', creationDate: new Date().toString(), @@ -1667,7 +1666,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: 1, - email: 'bibi@bloxberg.de', amount: new Decimal(300), memo: 'Danke Bibi!', creationDate: contributionDateFormatter(new Date()), @@ -1746,7 +1744,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: 1, - email: 'bibi@bloxberg.de', amount: new Decimal(300), memo: 'Danke Bibi!', creationDate: contributionDateFormatter(new Date()), @@ -2076,7 +2073,7 @@ describe('ContributionResolver', () => { // stephen@hawking.uk: [1000, 1000, 1000] - deleted // garrick@ollivander.com: [1000, 1000, 1000] - not activated - describe('user for creation to update does not exist', () => { + describe.skip('user for creation to update does not exist', () => { it('throws an error', async () => { jest.clearAllMocks() await expect( @@ -2084,7 +2081,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: 1, - email: 'bob@baumeister.de', amount: new Decimal(300), memo: 'Danke Bibi!', creationDate: contributionDateFormatter(new Date()), @@ -2102,7 +2098,7 @@ describe('ContributionResolver', () => { }) }) - describe('user for creation to update is deleted', () => { + describe.skip('user for creation to update is deleted', () => { it('throws an error', async () => { jest.clearAllMocks() await expect( @@ -2110,7 +2106,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: 1, - email: 'stephen@hawking.uk', amount: new Decimal(300), memo: 'Danke Bibi!', creationDate: contributionDateFormatter(new Date()), @@ -2136,7 +2131,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: -1, - email: 'bibi@bloxberg.de', amount: new Decimal(300), memo: 'Danke Bibi!', creationDate: contributionDateFormatter(new Date()), @@ -2154,7 +2148,7 @@ describe('ContributionResolver', () => { }) }) - describe('user email does not match creation user', () => { + describe.skip('user email does not match creation user', () => { it('throws an error', async () => { jest.clearAllMocks() await expect( @@ -2162,7 +2156,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: creation ? creation.id : -1, - email: 'bibi@bloxberg.de', amount: new Decimal(300), memo: 'Danke Bibi!', creationDate: creation @@ -2197,7 +2190,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: creation ? creation.id : -1, - email: 'peter@lustig.de', amount: new Decimal(1900), memo: 'Danke Peter!', creationDate: creation @@ -2233,7 +2225,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: creation ? creation.id : -1, - email: 'peter@lustig.de', amount: new Decimal(300), memo: 'Danke Peter!', creationDate: creation @@ -2248,7 +2239,6 @@ describe('ContributionResolver', () => { date: expect.any(String), memo: 'Danke Peter!', amount: '300', - creation: ['1000', '700', '500'], }, }, }), @@ -2274,7 +2264,6 @@ describe('ContributionResolver', () => { mutation: adminUpdateContribution, variables: { id: creation ? creation.id : -1, - email: 'peter@lustig.de', amount: new Decimal(200), memo: 'Das war leider zu Viel!', creationDate: creation @@ -2289,7 +2278,6 @@ describe('ContributionResolver', () => { date: expect.any(String), memo: 'Das war leider zu Viel!', amount: '200', - creation: ['1000', '800', '1000'], }, }, }), diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 69d6d16d8..94b840815 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -127,18 +127,11 @@ export const unDeleteUser = gql` ` export const adminUpdateContribution = gql` - mutation ($id: Int!, $email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) { - adminUpdateContribution( - id: $id - email: $email - amount: $amount - memo: $memo - creationDate: $creationDate - ) { + mutation ($id: Int!, $amount: Decimal!, $memo: String!, $creationDate: String!) { + adminUpdateContribution(id: $id, amount: $amount, memo: $memo, creationDate: $creationDate) { amount date memo - creation } } ` From c140e04310d5b7c8577818d7c55b02d6d64219c4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 21 Mar 2023 14:47:33 +0100 Subject: [PATCH 15/24] ass user relation to allow event --- backend/src/graphql/resolver/ContributionResolver.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index ea84e3ba9..0f7663ddf 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -322,7 +322,8 @@ export class ContributionResolver { const moderator = getUser(context) const contributionToUpdate = await DbContribution.findOne({ - where: { id, confirmedAt: IsNull(), deniedAt: IsNull(), relations: ['user'] }, + where: { id, confirmedAt: IsNull(), deniedAt: IsNull() }, + relations: ['user'], }) if (!contributionToUpdate) { From b64c080447120919951ef1afe2b50f9f4619727b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 23 Mar 2023 13:27:47 +0100 Subject: [PATCH 16/24] changes requested --- admin/src/components/EditCreationFormular.vue | 1 - .../resolver/ContributionResolver.test.ts | 33 ------------------- .../graphql/resolver/ContributionResolver.ts | 3 +- 3 files changed, 1 insertion(+), 36 deletions(-) diff --git a/admin/src/components/EditCreationFormular.vue b/admin/src/components/EditCreationFormular.vue index 994a734f6..6dbe22ebb 100644 --- a/admin/src/components/EditCreationFormular.vue +++ b/admin/src/components/EditCreationFormular.vue @@ -108,7 +108,6 @@ export default { }, methods: { submitCreation() { - // console.log('submitCreation', this.selected) this.$apollo .mutate({ mutation: adminUpdateContribution, diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 19d19080a..5a6e6d7c6 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2152,39 +2152,6 @@ describe('ContributionResolver', () => { }) }) - describe.skip('user email does not match creation user', () => { - it('throws an error', async () => { - jest.clearAllMocks() - await expect( - mutate({ - mutation: adminUpdateContribution, - variables: { - id: creation ? creation.id : -1, - amount: new Decimal(300), - memo: 'Danke Bibi!', - creationDate: creation - ? contributionDateFormatter(creation.contributionDate) - : contributionDateFormatter(new Date()), - }, - }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [ - new GraphQLError( - 'User of the pending contribution and send user does not correspond', - ), - ], - }), - ) - }) - - it('logs the error thrown', () => { - expect(logger.error).toBeCalledWith( - 'User of the pending contribution and send user does not correspond', - ) - }) - }) - describe('creation update is not valid', () => { // as this test has not clearly defined that date, it is a false positive it('throws an error', async () => { diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 2a9d96790..ab1c25d2e 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -321,7 +321,6 @@ export class ContributionResolver { const contributionToUpdate = await DbContribution.findOne({ where: { id, confirmedAt: IsNull(), deniedAt: IsNull() }, - relations: ['user'], }) if (!contributionToUpdate) { @@ -358,7 +357,7 @@ export class ContributionResolver { result.date = contributionToUpdate.contributionDate await EVENT_ADMIN_CONTRIBUTION_UPDATE( - contributionToUpdate.user, + { id: contributionToUpdate.userId } as DbUser, moderator, contributionToUpdate, amount, From a81b364fef2a20900c1e75aaad97579006ae2738 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 28 Mar 2023 12:57:34 +0200 Subject: [PATCH 17/24] fix admin create contribution --- admin/src/components/CreationFormular.spec.js | 1 + admin/src/components/CreationFormular.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/admin/src/components/CreationFormular.spec.js b/admin/src/components/CreationFormular.spec.js index c22b319a9..8f8cc03b0 100644 --- a/admin/src/components/CreationFormular.spec.js +++ b/admin/src/components/CreationFormular.spec.js @@ -145,6 +145,7 @@ describe('CreationFormular', () => { it('sends ... to apollo', () => { expect(adminCreateContributionMock).toBeCalledWith({ + email: 'benjamin@bluemchen.de', creationDate: getCreationDate(2), amount: 90, memo: 'Test create coins', diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue index aeaa84cc6..df8611c3b 100644 --- a/admin/src/components/CreationFormular.vue +++ b/admin/src/components/CreationFormular.vue @@ -140,6 +140,7 @@ export default { .mutate({ mutation: adminCreateContribution, variables: { + email: this.item.email, creationDate: this.selected.date, amount: Number(this.value), memo: this.text, From a4c82ae1456360b7c164731b21ab5ae6e997a315 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 28 Mar 2023 13:06:37 +0200 Subject: [PATCH 18/24] remove skipped tests as thay are depreciated --- .../resolver/ContributionResolver.test.ts | 50 ------------------- 1 file changed, 50 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 3c9241d7d..dcd24529e 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2077,56 +2077,6 @@ describe('ContributionResolver', () => { // stephen@hawking.uk: [1000, 1000, 1000] - deleted // garrick@ollivander.com: [1000, 1000, 1000] - not activated - describe.skip('user for creation to update does not exist', () => { - it('throws an error', async () => { - jest.clearAllMocks() - await expect( - mutate({ - mutation: adminUpdateContribution, - variables: { - id: 1, - amount: new Decimal(300), - memo: 'Danke Bibi!', - creationDate: contributionDateFormatter(new Date()), - }, - }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('Could not find User')], - }), - ) - }) - - it('logs the error "Could not find User"', () => { - expect(logger.error).toBeCalledWith('Could not find User', 'bob@baumeister.de') - }) - }) - - describe.skip('user for creation to update is deleted', () => { - it('throws an error', async () => { - jest.clearAllMocks() - await expect( - mutate({ - mutation: adminUpdateContribution, - variables: { - id: 1, - amount: new Decimal(300), - memo: 'Danke Bibi!', - creationDate: contributionDateFormatter(new Date()), - }, - }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('User was deleted')], - }), - ) - }) - - it('logs the error "User was deleted"', () => { - expect(logger.error).toBeCalledWith('User was deleted', 'stephen@hawking.uk') - }) - }) - describe('creation does not exist', () => { it('throws an error', async () => { jest.clearAllMocks() From cdfcaefa840b589f98937adf5644c802901605ae Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 30 Mar 2023 15:50:20 +0200 Subject: [PATCH 19/24] show moderator id --- admin/src/pages/CreationConfirm.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index 46995e9f7..3c1a1e67e 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -212,7 +212,7 @@ export default { return this.formatDateOrDash(value) }, }, - { key: 'moderator', label: this.$t('moderator') }, + { key: 'moderatorId', label: this.$t('moderator') }, { key: 'editCreation', label: this.$t('chat') }, { key: 'confirm', label: this.$t('save') }, ], From 64d896f9734bfa5c005289d6353b98d9d06a8d6e Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 30 Mar 2023 16:14:36 +0200 Subject: [PATCH 20/24] do not allow user to edit admin contributions --- .../Contributions/ContributionListItem.vue | 14 +++++++++----- frontend/src/graphql/queries.js | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionListItem.vue b/frontend/src/components/Contributions/ContributionListItem.vue index 56546d183..27e8459bd 100644 --- a/frontend/src/components/Contributions/ContributionListItem.vue +++ b/frontend/src/components/Contributions/ContributionListItem.vue @@ -47,7 +47,7 @@
{{ amount | GDD }}
-
+
@@ -58,7 +58,7 @@ >
@@ -69,7 +69,7 @@
-
+
{{ $t('moderatorChat') }}
@@ -180,6 +179,11 @@ export default { required: false, default: false, }, + moderatorId: { + type: Number, + required: false, + default: 0, + }, }, data() { return { diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 7193eded0..87e861752 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -187,6 +187,7 @@ export const listContributions = gql` messagesCount deniedAt deniedBy + moderatorId } } } From 43e2f5fbc839921b5b0fe3deadc85c15baeb104f Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 30 Mar 2023 16:40:07 +0200 Subject: [PATCH 21/24] do not allow user to edit admin contributions --- .../src/graphql/resolver/BalanceResolver.ts | 1 - .../resolver/CommunityResolver.test.ts | 2 +- .../resolver/ContributionLinkResolver.test.ts | 2 +- .../resolver/ContributionLinkResolver.ts | 6 +- .../resolver/ContributionResolver.test.ts | 68 +++++++++++++++---- .../graphql/resolver/ContributionResolver.ts | 9 ++- .../resolver/TransactionLinkResolver.test.ts | 6 +- .../resolver/TransactionLinkResolver.ts | 8 +-- .../resolver/TransactionResolver.test.ts | 4 +- .../graphql/resolver/TransactionResolver.ts | 8 +-- .../src/graphql/resolver/UserResolver.test.ts | 4 +- backend/src/graphql/resolver/UserResolver.ts | 15 ++-- .../src/graphql/resolver/semaphore.test.ts | 2 +- .../src/graphql/resolver/util/creations.ts | 2 +- backend/src/middleware/klicktippMiddleware.ts | 2 +- backend/src/password/EncryptorUtils.ts | 2 +- backend/src/seeds/factory/contributionLink.ts | 2 +- backend/src/util/communityUser.ts | 2 +- backend/src/util/decay.ts | 2 +- backend/src/util/validate.ts | 2 +- 20 files changed, 97 insertions(+), 52 deletions(-) diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 7600f12b9..31e2384d4 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -9,7 +9,6 @@ import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { GdtResolver } from './GdtResolver' import { getLastTransaction } from './util/getLastTransaction' import { TransactionLinkRepository } from '@repository/TransactionLink' - import { Balance } from '@model/Balance' import { backendLogger as logger } from '@/server/logger' diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index f4352c095..5513a73b8 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -6,8 +6,8 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Community as DbCommunity } from '@entity/Community' -import { getCommunities } from '@/seeds/graphql/queries' import { testEnvironment } from '@test/helpers' +import { getCommunities } from '@/seeds/graphql/queries' let query: any diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 6a69e257e..7dfb44e55 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -9,6 +9,7 @@ import { GraphQLError } from 'graphql' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Event as DbEvent } from '@entity/Event' import { logger } from '@test/testSetup' +import { cleanDB, testEnvironment, resetToken } from '@test/helpers' import { login, createContributionLink, @@ -16,7 +17,6 @@ import { updateContributionLink, } from '@/seeds/graphql/mutations' import { listContributionLinks } from '@/seeds/graphql/queries' -import { cleanDB, testEnvironment, resetToken } from '@test/helpers' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { userFactory } from '@/seeds/factory/user' diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index 55a23187f..4b19c36e1 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -3,20 +3,20 @@ import { Resolver, Args, Arg, Authorized, Mutation, Query, Int, Ctx } from 'type import { MoreThan, IsNull } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' +import { isStartEndDateValid } from './util/creations' import { CONTRIBUTIONLINK_NAME_MAX_CHARS, CONTRIBUTIONLINK_NAME_MIN_CHARS, MEMO_MAX_CHARS, MEMO_MIN_CHARS, } from './const/const' -import { isStartEndDateValid } from './util/creations' -import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' import { ContributionLinkList } from '@model/ContributionLinkList' import { ContributionLink } from '@model/ContributionLink' import ContributionLinkArgs from '@arg/ContributionLinkArgs' -import { RIGHTS } from '@/auth/RIGHTS' import { Order } from '@enum/Order' import Paginated from '@arg/Paginated' +import { RIGHTS } from '@/auth/RIGHTS' // TODO: this is a strange construct import LogError from '@/server/LogError' diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 201d04db1..5570f953f 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -13,6 +13,18 @@ import { Transaction as DbTransaction } from '@entity/Transaction' import { User } from '@entity/User' import { UserInputError } from 'apollo-server-express' import { Event as DbEvent } from '@entity/Event' +import { + cleanDB, + resetToken, + testEnvironment, + contributionDateFormatter, + resetEntity, +} from '@test/helpers' +import { logger, i18n as localization } from '@test/testSetup' +import { UnconfirmedContribution } from '@model/UnconfirmedContribution' +import { ContributionListResult } from '@model/Contribution' +import { ContributionStatus } from '@enum/ContributionStatus' +import { Order } from '@enum/Order' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { stephenHawking } from '@/seeds/users/stephen-hawking' @@ -40,24 +52,12 @@ import { sendContributionDeletedEmail, sendContributionDeniedEmail, } from '@/emails/sendEmailVariants' -import { - cleanDB, - resetToken, - testEnvironment, - contributionDateFormatter, - resetEntity, -} from '@test/helpers' import { userFactory } from '@/seeds/factory/user' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { peterLustig } from '@/seeds/users/peter-lustig' import { EventType } from '@/event/Event' -import { logger, i18n as localization } from '@test/testSetup' import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' -import { UnconfirmedContribution } from '@model/UnconfirmedContribution' -import { ContributionListResult } from '@model/Contribution' -import { ContributionStatus } from '@enum/ContributionStatus' -import { Order } from '@enum/Order' jest.mock('@/emails/sendEmailVariants') @@ -2040,6 +2040,50 @@ describe('ContributionResolver', () => { }), ) }) + + describe('user tries to update admin contribution', () => { + beforeAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + }) + + it('logs and throws "Cannot update contribution of moderator" error', async () => { + jest.clearAllMocks() + const adminContribution = await Contribution.findOne({ + where: { + moderatorId: admin.id, + userId: bibi.id, + }, + }) + await expect( + mutate({ + mutation: updateContribution, + variables: { + contributionId: (adminContribution && adminContribution.id) || -1, + amount: 100.0, + memo: 'Test Test Test', + creationDate: new Date().toString(), + }, + }), + ).resolves.toMatchObject({ + errors: [new GraphQLError('Cannot update contribution of moderator')], + }) + expect(logger.error).toBeCalledWith( + 'Cannot update contribution of moderator', + expect.any(Object), + bibi.id, + ) + }) + }) }) describe('second creation surpasses the available amount ', () => { diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index a9446db7f..f756b3a0d 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -9,9 +9,6 @@ import { UserContact } from '@entity/UserContact' import { User as DbUser } from '@entity/User' import { Transaction as DbTransaction } from '@entity/Transaction' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' -import { getLastTransaction } from './util/getLastTransaction' -import { findContributions } from './util/findContributions' import { getUserCreation, validateContribution, @@ -19,6 +16,9 @@ import { isValidDateString, getOpenCreations, } from './util/creations' +import { findContributions } from './util/findContributions' +import { getLastTransaction } from './util/getLastTransaction' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { AdminUpdateContribution } from '@model/AdminUpdateContribution' import { Contribution, ContributionListResult } from '@model/Contribution' import { Decay } from '@model/Decay' @@ -201,6 +201,9 @@ export class ContributionResolver { user.id, ) } + if (contributionToUpdate.moderatorId) { + throw new LogError('Cannot update contribution of moderator', contributionToUpdate, user.id) + } if ( contributionToUpdate.contributionStatus !== ContributionStatus.IN_PROGRESS && contributionToUpdate.contributionStatus !== ContributionStatus.PENDING diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index fd2a44b4b..4f72276d4 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -14,9 +14,11 @@ import { Transaction } from '@entity/Transaction' import { Event as DbEvent } from '@entity/Event' import { UserContact } from '@entity/UserContact' import { transactionLinkCode } from './TransactionLinkResolver' +import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers' +import { UnconfirmedContribution } from '@model/UnconfirmedContribution' +import { logger } from '@test/testSetup' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' -import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { userFactory } from '@/seeds/factory/user' @@ -33,9 +35,7 @@ import { confirmContribution, } from '@/seeds/graphql/mutations' import { listTransactionLinksAdmin } from '@/seeds/graphql/queries' -import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' -import { logger } from '@test/testSetup' import { EventType } from '@/event/Event' // mock semaphore to allow use fake timers diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 6aa829ac1..3ff6fd36a 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -10,10 +10,10 @@ import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Resolver, Args, Arg, Authorized, Ctx, Mutation, Query, Int } from 'type-graphql' -import { getUserCreation, validateContribution } from './util/creations' -import { executeTransaction } from './TransactionResolver' -import { getLastTransaction } from './util/getLastTransaction' import transactionLinkList from './util/transactionLinkList' +import { getLastTransaction } from './util/getLastTransaction' +import { executeTransaction } from './TransactionResolver' +import { getUserCreation, validateContribution } from './util/creations' import { User } from '@model/User' import { ContributionLink } from '@model/ContributionLink' import { Decay } from '@model/Decay' @@ -25,12 +25,12 @@ import { ContributionCycleType } from '@enum/ContributionCycleType' import TransactionLinkArgs from '@arg/TransactionLinkArgs' import Paginated from '@arg/Paginated' import TransactionLinkFilters from '@arg/TransactionLinkFilters' +import QueryLinkResult from '@union/QueryLinkResult' import { backendLogger as logger } from '@/server/logger' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import { calculateBalance } from '@/util/validate' import { RIGHTS } from '@/auth/RIGHTS' import { calculateDecay } from '@/util/decay' -import QueryLinkResult from '@union/QueryLinkResult' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import LogError from '@/server/LogError' import { diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index f26234363..6d039784e 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -11,6 +11,8 @@ import { User } from '@entity/User' import { GraphQLError } from 'graphql' import { Event as DbEvent } from '@entity/Event' import { findUserByEmail } from './UserResolver' +import { cleanDB, testEnvironment } from '@test/helpers' +import { logger } from '@test/testSetup' import { EventType } from '@/event/Event' import { userFactory } from '@/seeds/factory/user' import { @@ -23,8 +25,6 @@ import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { garrickOllivander } from '@/seeds/users/garrick-ollivander' import { peterLustig } from '@/seeds/users/peter-lustig' import { stephenHawking } from '@/seeds/users/stephen-hawking' -import { cleanDB, testEnvironment } from '@test/helpers' -import { logger } from '@test/testSetup' let mutate: any, query: any, con: any let testEnv: any diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index f38a4a07b..a699e7291 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -9,10 +9,10 @@ import { getCustomRepository, getConnection, In } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' -import { BalanceResolver } from './BalanceResolver' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' -import { findUserByEmail } from './UserResolver' import { getLastTransaction } from './util/getLastTransaction' +import { findUserByEmail } from './UserResolver' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' +import { BalanceResolver } from './BalanceResolver' import { TransactionRepository } from '@repository/Transaction' import { TransactionLinkRepository } from '@repository/TransactionLink' @@ -21,9 +21,9 @@ import { Transaction } from '@model/Transaction' import { TransactionList } from '@model/TransactionList' import { Order } from '@enum/Order' import { TransactionTypeId } from '@enum/TransactionTypeId' -import { calculateBalance } from '@/util/validate' import TransactionSendArgs from '@arg/TransactionSendArgs' import Paginated from '@arg/Paginated' +import { calculateBalance } from '@/util/validate' import { backendLogger as logger } from '@/server/logger' import { Context, getUser } from '@/server/context' diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index aebd0f0eb..1b6239fea 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -15,9 +15,10 @@ import { Event as DbEvent } from '@entity/Event' import { OptInType } from '@enum/OptInType' import { UserContactType } from '@enum/UserContactType' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' -import { objectValuesToArray } from '@/util/utilities' import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers' import { logger, i18n as localization } from '@test/testSetup' +import { ContributionLink } from '@model/ContributionLink' +import { objectValuesToArray } from '@/util/utilities' import { printTimeDuration } from '@/util/time' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' @@ -44,7 +45,6 @@ import { } from '@/emails/sendEmailVariants' import { contributionLinkFactory } from '@/seeds/factory/contributionLink' import { transactionLinkFactory } from '@/seeds/factory/transactionLink' -import { ContributionLink } from '@model/ContributionLink' import { EventType } from '@/event/Event' import { peterLustig } from '@/seeds/users/peter-lustig' import { bobBaumeister } from '@/seeds/users/bob-baumeister' diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 54d4f583f..0c1cefd12 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -21,8 +21,8 @@ import { User as DbUser } from '@entity/User' import { UserContact as DbUserContact } from '@entity/UserContact' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' -import { getUserCreations } from './util/creations' import { FULL_CREATION_AVAILABLE } from './const/const' +import { getUserCreations } from './util/creations' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import { UserRepository } from '@repository/User' @@ -33,18 +33,17 @@ import { OptInType } from '@enum/OptInType' import { Order } from '@enum/Order' import { UserContactType } from '@enum/UserContactType' -import { - sendAccountActivationEmail, - sendAccountMultiRegistrationEmail, - sendResetPasswordEmail, -} from '@/emails/sendEmailVariants' - -import { getTimeDurationObject, printTimeDuration } from '@/util/time' import CreateUserArgs from '@arg/CreateUserArgs' import UnsecureLoginArgs from '@arg/UnsecureLoginArgs' import UpdateUserInfosArgs from '@arg/UpdateUserInfosArgs' import Paginated from '@arg/Paginated' import SearchUsersArgs from '@arg/SearchUsersArgs' +import { getTimeDurationObject, printTimeDuration } from '@/util/time' +import { + sendAccountActivationEmail, + sendAccountMultiRegistrationEmail, + sendResetPasswordEmail, +} from '@/emails/sendEmailVariants' import { backendLogger as logger } from '@/server/logger' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index 6b1976021..cc4d589dc 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -5,12 +5,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Decimal } from 'decimal.js-light' +import { cleanDB, testEnvironment, contributionDateFormatter } from '@test/helpers' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { peterLustig } from '@/seeds/users/peter-lustig' import { creationFactory, nMonthsBefore } from '@/seeds/factory/creation' -import { cleanDB, testEnvironment, contributionDateFormatter } from '@test/helpers' import { confirmContribution, createContribution, diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index 6ebeae8b9..dba0c8c81 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -3,9 +3,9 @@ import { getConnection } from '@dbTools/typeorm' import { Contribution } from '@entity/Contribution' import { Decimal } from 'decimal.js-light' +import { OpenCreation } from '@model/OpenCreation' import { FULL_CREATION_AVAILABLE, MAX_CREATION_AMOUNT } from '@/graphql/resolver/const/const' import { backendLogger as logger } from '@/server/logger' -import { OpenCreation } from '@model/OpenCreation' import LogError from '@/server/LogError' interface CreationMap { diff --git a/backend/src/middleware/klicktippMiddleware.ts b/backend/src/middleware/klicktippMiddleware.ts index 0469b4ccc..568120fe8 100644 --- a/backend/src/middleware/klicktippMiddleware.ts +++ b/backend/src/middleware/klicktippMiddleware.ts @@ -3,8 +3,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ import { MiddlewareFn } from 'type-graphql' -import { /* klicktippSignIn, */ getKlickTippUser } from '@/apis/KlicktippController' import { KlickTipp } from '@model/KlickTipp' +import { /* klicktippSignIn, */ getKlickTippUser } from '@/apis/KlicktippController' import CONFIG from '@/config' import { klickTippLogger as logger } from '@/server/logger' diff --git a/backend/src/password/EncryptorUtils.ts b/backend/src/password/EncryptorUtils.ts index b4531b3bb..ab8a333d2 100644 --- a/backend/src/password/EncryptorUtils.ts +++ b/backend/src/password/EncryptorUtils.ts @@ -2,10 +2,10 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { User } from '@entity/User' +import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import CONFIG from '@/config' import LogError from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' -import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' // eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs const sodium = require('sodium-native') diff --git a/backend/src/seeds/factory/contributionLink.ts b/backend/src/seeds/factory/contributionLink.ts index 5925cdcfe..6e1d9bd50 100644 --- a/backend/src/seeds/factory/contributionLink.ts +++ b/backend/src/seeds/factory/contributionLink.ts @@ -2,8 +2,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/unbound-method */ import { ApolloServerTestClient } from 'apollo-server-testing' -import { login, createContributionLink } from '@/seeds/graphql/mutations' import { ContributionLink } from '@model/ContributionLink' +import { login, createContributionLink } from '@/seeds/graphql/mutations' import { ContributionLinkInterface } from '@/seeds/contributionLink/ContributionLinkInterface' export const contributionLinkFactory = async ( diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index dfa477da9..d086727bf 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -3,9 +3,9 @@ import { SaveOptions, RemoveOptions } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' import { UserContact } from '@entity/UserContact' +import { User } from '@model/User' import { PasswordEncryptionType } from '@/graphql/enum/PasswordEncryptionType' // import { UserContact as EmailContact } from '@entity/UserContact' -import { User } from '@model/User' const communityDbUser: dbUser = { id: -1, diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index d35eb83a4..3c76b0995 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -1,6 +1,6 @@ import { Decimal } from 'decimal.js-light' -import CONFIG from '@/config' import { Decay } from '@model/Decay' +import CONFIG from '@/config' import LogError from '@/server/LogError' // TODO: externalize all those definitions and functions into an external decay library diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index ec28dfa13..aaadbdd31 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -2,9 +2,9 @@ import { Decimal } from 'decimal.js-light' import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { calculateDecay } from './decay' -import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' import { TransactionLinkRepository } from '@repository/TransactionLink' import { Decay } from '@model/Decay' +import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' function isStringBoolean(value: string): boolean { const lowerValue = value.toLowerCase() From 769e36bea5d80dd64472bb382a665362c56eefbf Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 30 Mar 2023 16:55:00 +0200 Subject: [PATCH 22/24] no Float in query --- frontend/src/graphql/queries.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 87e861752..1a37d082b 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -237,7 +237,7 @@ export const searchAdminUsers = gql` ` export const listContributionMessages = gql` - query($contributionId: Float!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) { + query($contributionId: Int!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) { listContributionMessages( contributionId: $contributionId pageSize: $pageSize From 6dff07a7baf761e33bdd6e4828ba4b4d30f8099f Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 30 Mar 2023 18:25:47 +0200 Subject: [PATCH 23/24] Revert "do not allow user to edit admin contributions" This reverts commit 43e2f5fbc839921b5b0fe3deadc85c15baeb104f. --- .../src/graphql/resolver/BalanceResolver.ts | 1 + .../resolver/CommunityResolver.test.ts | 2 +- .../resolver/ContributionLinkResolver.test.ts | 2 +- .../resolver/ContributionLinkResolver.ts | 6 +- .../resolver/ContributionResolver.test.ts | 68 ++++--------------- .../graphql/resolver/ContributionResolver.ts | 9 +-- .../resolver/TransactionLinkResolver.test.ts | 6 +- .../resolver/TransactionLinkResolver.ts | 8 +-- .../resolver/TransactionResolver.test.ts | 4 +- .../graphql/resolver/TransactionResolver.ts | 8 +-- .../src/graphql/resolver/UserResolver.test.ts | 4 +- backend/src/graphql/resolver/UserResolver.ts | 15 ++-- .../src/graphql/resolver/semaphore.test.ts | 2 +- .../src/graphql/resolver/util/creations.ts | 2 +- backend/src/middleware/klicktippMiddleware.ts | 2 +- backend/src/password/EncryptorUtils.ts | 2 +- backend/src/seeds/factory/contributionLink.ts | 2 +- backend/src/util/communityUser.ts | 2 +- backend/src/util/decay.ts | 2 +- backend/src/util/validate.ts | 2 +- 20 files changed, 52 insertions(+), 97 deletions(-) diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 31e2384d4..7600f12b9 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -9,6 +9,7 @@ import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { GdtResolver } from './GdtResolver' import { getLastTransaction } from './util/getLastTransaction' import { TransactionLinkRepository } from '@repository/TransactionLink' + import { Balance } from '@model/Balance' import { backendLogger as logger } from '@/server/logger' diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 5513a73b8..f4352c095 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -6,8 +6,8 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Community as DbCommunity } from '@entity/Community' -import { testEnvironment } from '@test/helpers' import { getCommunities } from '@/seeds/graphql/queries' +import { testEnvironment } from '@test/helpers' let query: any diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 7dfb44e55..6a69e257e 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -9,7 +9,6 @@ import { GraphQLError } from 'graphql' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Event as DbEvent } from '@entity/Event' import { logger } from '@test/testSetup' -import { cleanDB, testEnvironment, resetToken } from '@test/helpers' import { login, createContributionLink, @@ -17,6 +16,7 @@ import { updateContributionLink, } from '@/seeds/graphql/mutations' import { listContributionLinks } from '@/seeds/graphql/queries' +import { cleanDB, testEnvironment, resetToken } from '@test/helpers' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { userFactory } from '@/seeds/factory/user' diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index 4b19c36e1..55a23187f 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -3,20 +3,20 @@ import { Resolver, Args, Arg, Authorized, Mutation, Query, Int, Ctx } from 'type import { MoreThan, IsNull } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' -import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' -import { isStartEndDateValid } from './util/creations' import { CONTRIBUTIONLINK_NAME_MAX_CHARS, CONTRIBUTIONLINK_NAME_MIN_CHARS, MEMO_MAX_CHARS, MEMO_MIN_CHARS, } from './const/const' +import { isStartEndDateValid } from './util/creations' +import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' import { ContributionLinkList } from '@model/ContributionLinkList' import { ContributionLink } from '@model/ContributionLink' import ContributionLinkArgs from '@arg/ContributionLinkArgs' +import { RIGHTS } from '@/auth/RIGHTS' import { Order } from '@enum/Order' import Paginated from '@arg/Paginated' -import { RIGHTS } from '@/auth/RIGHTS' // TODO: this is a strange construct import LogError from '@/server/LogError' diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 5570f953f..201d04db1 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -13,18 +13,6 @@ import { Transaction as DbTransaction } from '@entity/Transaction' import { User } from '@entity/User' import { UserInputError } from 'apollo-server-express' import { Event as DbEvent } from '@entity/Event' -import { - cleanDB, - resetToken, - testEnvironment, - contributionDateFormatter, - resetEntity, -} from '@test/helpers' -import { logger, i18n as localization } from '@test/testSetup' -import { UnconfirmedContribution } from '@model/UnconfirmedContribution' -import { ContributionListResult } from '@model/Contribution' -import { ContributionStatus } from '@enum/ContributionStatus' -import { Order } from '@enum/Order' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { stephenHawking } from '@/seeds/users/stephen-hawking' @@ -52,12 +40,24 @@ import { sendContributionDeletedEmail, sendContributionDeniedEmail, } from '@/emails/sendEmailVariants' +import { + cleanDB, + resetToken, + testEnvironment, + contributionDateFormatter, + resetEntity, +} from '@test/helpers' import { userFactory } from '@/seeds/factory/user' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { peterLustig } from '@/seeds/users/peter-lustig' import { EventType } from '@/event/Event' +import { logger, i18n as localization } from '@test/testSetup' import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' +import { UnconfirmedContribution } from '@model/UnconfirmedContribution' +import { ContributionListResult } from '@model/Contribution' +import { ContributionStatus } from '@enum/ContributionStatus' +import { Order } from '@enum/Order' jest.mock('@/emails/sendEmailVariants') @@ -2040,50 +2040,6 @@ describe('ContributionResolver', () => { }), ) }) - - describe('user tries to update admin contribution', () => { - beforeAll(async () => { - await mutate({ - mutation: login, - variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, - }) - }) - - afterAll(async () => { - await mutate({ - mutation: login, - variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, - }) - }) - - it('logs and throws "Cannot update contribution of moderator" error', async () => { - jest.clearAllMocks() - const adminContribution = await Contribution.findOne({ - where: { - moderatorId: admin.id, - userId: bibi.id, - }, - }) - await expect( - mutate({ - mutation: updateContribution, - variables: { - contributionId: (adminContribution && adminContribution.id) || -1, - amount: 100.0, - memo: 'Test Test Test', - creationDate: new Date().toString(), - }, - }), - ).resolves.toMatchObject({ - errors: [new GraphQLError('Cannot update contribution of moderator')], - }) - expect(logger.error).toBeCalledWith( - 'Cannot update contribution of moderator', - expect.any(Object), - bibi.id, - ) - }) - }) }) describe('second creation surpasses the available amount ', () => { diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index f756b3a0d..a9446db7f 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -9,6 +9,9 @@ import { UserContact } from '@entity/UserContact' import { User as DbUser } from '@entity/User' import { Transaction as DbTransaction } from '@entity/Transaction' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' +import { getLastTransaction } from './util/getLastTransaction' +import { findContributions } from './util/findContributions' import { getUserCreation, validateContribution, @@ -16,9 +19,6 @@ import { isValidDateString, getOpenCreations, } from './util/creations' -import { findContributions } from './util/findContributions' -import { getLastTransaction } from './util/getLastTransaction' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { AdminUpdateContribution } from '@model/AdminUpdateContribution' import { Contribution, ContributionListResult } from '@model/Contribution' import { Decay } from '@model/Decay' @@ -201,9 +201,6 @@ export class ContributionResolver { user.id, ) } - if (contributionToUpdate.moderatorId) { - throw new LogError('Cannot update contribution of moderator', contributionToUpdate, user.id) - } if ( contributionToUpdate.contributionStatus !== ContributionStatus.IN_PROGRESS && contributionToUpdate.contributionStatus !== ContributionStatus.PENDING diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index 4f72276d4..fd2a44b4b 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -14,11 +14,9 @@ import { Transaction } from '@entity/Transaction' import { Event as DbEvent } from '@entity/Event' import { UserContact } from '@entity/UserContact' import { transactionLinkCode } from './TransactionLinkResolver' -import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers' -import { UnconfirmedContribution } from '@model/UnconfirmedContribution' -import { logger } from '@test/testSetup' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' +import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { userFactory } from '@/seeds/factory/user' @@ -35,7 +33,9 @@ import { confirmContribution, } from '@/seeds/graphql/mutations' import { listTransactionLinksAdmin } from '@/seeds/graphql/queries' +import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' +import { logger } from '@test/testSetup' import { EventType } from '@/event/Event' // mock semaphore to allow use fake timers diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 3ff6fd36a..6aa829ac1 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -10,10 +10,10 @@ import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Resolver, Args, Arg, Authorized, Ctx, Mutation, Query, Int } from 'type-graphql' -import transactionLinkList from './util/transactionLinkList' -import { getLastTransaction } from './util/getLastTransaction' -import { executeTransaction } from './TransactionResolver' import { getUserCreation, validateContribution } from './util/creations' +import { executeTransaction } from './TransactionResolver' +import { getLastTransaction } from './util/getLastTransaction' +import transactionLinkList from './util/transactionLinkList' import { User } from '@model/User' import { ContributionLink } from '@model/ContributionLink' import { Decay } from '@model/Decay' @@ -25,12 +25,12 @@ import { ContributionCycleType } from '@enum/ContributionCycleType' import TransactionLinkArgs from '@arg/TransactionLinkArgs' import Paginated from '@arg/Paginated' import TransactionLinkFilters from '@arg/TransactionLinkFilters' -import QueryLinkResult from '@union/QueryLinkResult' import { backendLogger as logger } from '@/server/logger' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import { calculateBalance } from '@/util/validate' import { RIGHTS } from '@/auth/RIGHTS' import { calculateDecay } from '@/util/decay' +import QueryLinkResult from '@union/QueryLinkResult' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import LogError from '@/server/LogError' import { diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index 6d039784e..f26234363 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -11,8 +11,6 @@ import { User } from '@entity/User' import { GraphQLError } from 'graphql' import { Event as DbEvent } from '@entity/Event' import { findUserByEmail } from './UserResolver' -import { cleanDB, testEnvironment } from '@test/helpers' -import { logger } from '@test/testSetup' import { EventType } from '@/event/Event' import { userFactory } from '@/seeds/factory/user' import { @@ -25,6 +23,8 @@ import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { garrickOllivander } from '@/seeds/users/garrick-ollivander' import { peterLustig } from '@/seeds/users/peter-lustig' import { stephenHawking } from '@/seeds/users/stephen-hawking' +import { cleanDB, testEnvironment } from '@test/helpers' +import { logger } from '@test/testSetup' let mutate: any, query: any, con: any let testEnv: any diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index a699e7291..f38a4a07b 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -9,10 +9,10 @@ import { getCustomRepository, getConnection, In } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' -import { getLastTransaction } from './util/getLastTransaction' -import { findUserByEmail } from './UserResolver' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { BalanceResolver } from './BalanceResolver' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' +import { findUserByEmail } from './UserResolver' +import { getLastTransaction } from './util/getLastTransaction' import { TransactionRepository } from '@repository/Transaction' import { TransactionLinkRepository } from '@repository/TransactionLink' @@ -21,9 +21,9 @@ import { Transaction } from '@model/Transaction' import { TransactionList } from '@model/TransactionList' import { Order } from '@enum/Order' import { TransactionTypeId } from '@enum/TransactionTypeId' +import { calculateBalance } from '@/util/validate' import TransactionSendArgs from '@arg/TransactionSendArgs' import Paginated from '@arg/Paginated' -import { calculateBalance } from '@/util/validate' import { backendLogger as logger } from '@/server/logger' import { Context, getUser } from '@/server/context' diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 1b6239fea..aebd0f0eb 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -15,10 +15,9 @@ import { Event as DbEvent } from '@entity/Event' import { OptInType } from '@enum/OptInType' import { UserContactType } from '@enum/UserContactType' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' +import { objectValuesToArray } from '@/util/utilities' import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers' import { logger, i18n as localization } from '@test/testSetup' -import { ContributionLink } from '@model/ContributionLink' -import { objectValuesToArray } from '@/util/utilities' import { printTimeDuration } from '@/util/time' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' @@ -45,6 +44,7 @@ import { } from '@/emails/sendEmailVariants' import { contributionLinkFactory } from '@/seeds/factory/contributionLink' import { transactionLinkFactory } from '@/seeds/factory/transactionLink' +import { ContributionLink } from '@model/ContributionLink' import { EventType } from '@/event/Event' import { peterLustig } from '@/seeds/users/peter-lustig' import { bobBaumeister } from '@/seeds/users/bob-baumeister' diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 0c1cefd12..54d4f583f 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -21,8 +21,8 @@ import { User as DbUser } from '@entity/User' import { UserContact as DbUserContact } from '@entity/UserContact' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' -import { FULL_CREATION_AVAILABLE } from './const/const' import { getUserCreations } from './util/creations' +import { FULL_CREATION_AVAILABLE } from './const/const' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import { UserRepository } from '@repository/User' @@ -33,18 +33,19 @@ import { OptInType } from '@enum/OptInType' import { Order } from '@enum/Order' import { UserContactType } from '@enum/UserContactType' -import CreateUserArgs from '@arg/CreateUserArgs' -import UnsecureLoginArgs from '@arg/UnsecureLoginArgs' -import UpdateUserInfosArgs from '@arg/UpdateUserInfosArgs' -import Paginated from '@arg/Paginated' -import SearchUsersArgs from '@arg/SearchUsersArgs' -import { getTimeDurationObject, printTimeDuration } from '@/util/time' import { sendAccountActivationEmail, sendAccountMultiRegistrationEmail, sendResetPasswordEmail, } from '@/emails/sendEmailVariants' +import { getTimeDurationObject, printTimeDuration } from '@/util/time' +import CreateUserArgs from '@arg/CreateUserArgs' +import UnsecureLoginArgs from '@arg/UnsecureLoginArgs' +import UpdateUserInfosArgs from '@arg/UpdateUserInfosArgs' +import Paginated from '@arg/Paginated' +import SearchUsersArgs from '@arg/SearchUsersArgs' + import { backendLogger as logger } from '@/server/logger' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import CONFIG from '@/config' diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index cc4d589dc..6b1976021 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -5,12 +5,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Decimal } from 'decimal.js-light' -import { cleanDB, testEnvironment, contributionDateFormatter } from '@test/helpers' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { peterLustig } from '@/seeds/users/peter-lustig' import { creationFactory, nMonthsBefore } from '@/seeds/factory/creation' +import { cleanDB, testEnvironment, contributionDateFormatter } from '@test/helpers' import { confirmContribution, createContribution, diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index dba0c8c81..6ebeae8b9 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -3,9 +3,9 @@ import { getConnection } from '@dbTools/typeorm' import { Contribution } from '@entity/Contribution' import { Decimal } from 'decimal.js-light' -import { OpenCreation } from '@model/OpenCreation' import { FULL_CREATION_AVAILABLE, MAX_CREATION_AMOUNT } from '@/graphql/resolver/const/const' import { backendLogger as logger } from '@/server/logger' +import { OpenCreation } from '@model/OpenCreation' import LogError from '@/server/LogError' interface CreationMap { diff --git a/backend/src/middleware/klicktippMiddleware.ts b/backend/src/middleware/klicktippMiddleware.ts index 568120fe8..0469b4ccc 100644 --- a/backend/src/middleware/klicktippMiddleware.ts +++ b/backend/src/middleware/klicktippMiddleware.ts @@ -3,8 +3,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ import { MiddlewareFn } from 'type-graphql' -import { KlickTipp } from '@model/KlickTipp' import { /* klicktippSignIn, */ getKlickTippUser } from '@/apis/KlicktippController' +import { KlickTipp } from '@model/KlickTipp' import CONFIG from '@/config' import { klickTippLogger as logger } from '@/server/logger' diff --git a/backend/src/password/EncryptorUtils.ts b/backend/src/password/EncryptorUtils.ts index ab8a333d2..b4531b3bb 100644 --- a/backend/src/password/EncryptorUtils.ts +++ b/backend/src/password/EncryptorUtils.ts @@ -2,10 +2,10 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { User } from '@entity/User' -import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import CONFIG from '@/config' import LogError from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' +import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' // eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs const sodium = require('sodium-native') diff --git a/backend/src/seeds/factory/contributionLink.ts b/backend/src/seeds/factory/contributionLink.ts index 6e1d9bd50..5925cdcfe 100644 --- a/backend/src/seeds/factory/contributionLink.ts +++ b/backend/src/seeds/factory/contributionLink.ts @@ -2,8 +2,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/unbound-method */ import { ApolloServerTestClient } from 'apollo-server-testing' -import { ContributionLink } from '@model/ContributionLink' import { login, createContributionLink } from '@/seeds/graphql/mutations' +import { ContributionLink } from '@model/ContributionLink' import { ContributionLinkInterface } from '@/seeds/contributionLink/ContributionLinkInterface' export const contributionLinkFactory = async ( diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index d086727bf..dfa477da9 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -3,9 +3,9 @@ import { SaveOptions, RemoveOptions } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' import { UserContact } from '@entity/UserContact' -import { User } from '@model/User' import { PasswordEncryptionType } from '@/graphql/enum/PasswordEncryptionType' // import { UserContact as EmailContact } from '@entity/UserContact' +import { User } from '@model/User' const communityDbUser: dbUser = { id: -1, diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index 3c76b0995..d35eb83a4 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -1,6 +1,6 @@ import { Decimal } from 'decimal.js-light' -import { Decay } from '@model/Decay' 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 diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index aaadbdd31..ec28dfa13 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -2,9 +2,9 @@ import { Decimal } from 'decimal.js-light' import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { calculateDecay } from './decay' +import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' import { TransactionLinkRepository } from '@repository/TransactionLink' import { Decay } from '@model/Decay' -import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' function isStringBoolean(value: string): boolean { const lowerValue = value.toLowerCase() From 695d037a2dfaffe815b1555075a7fe45fa9d4c82 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 30 Mar 2023 18:33:36 +0200 Subject: [PATCH 24/24] do not allow edit contribution for admin contributions in backend --- .../resolver/ContributionResolver.test.ts | 44 +++++++++++++++++++ .../graphql/resolver/ContributionResolver.ts | 3 ++ 2 files changed, 47 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 6d3f29280..490f5a4a7 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2042,6 +2042,50 @@ describe('ContributionResolver', () => { }), ) }) + + describe('user tries to update admin contribution', () => { + beforeAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + }) + + it('logs and throws "Cannot update contribution of moderator" error', async () => { + jest.clearAllMocks() + const adminContribution = await Contribution.findOne({ + where: { + moderatorId: admin.id, + userId: bibi.id, + }, + }) + await expect( + mutate({ + mutation: updateContribution, + variables: { + contributionId: (adminContribution && adminContribution.id) || -1, + amount: 100.0, + memo: 'Test Test Test', + creationDate: new Date().toString(), + }, + }), + ).resolves.toMatchObject({ + errors: [new GraphQLError('Cannot update contribution of moderator')], + }) + expect(logger.error).toBeCalledWith( + 'Cannot update contribution of moderator', + expect.any(Object), + bibi.id, + ) + }) + }) }) describe('second creation surpasses the available amount ', () => { diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 1d3274b79..5969eaef2 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -201,6 +201,9 @@ export class ContributionResolver { user.id, ) } + if (contributionToUpdate.moderatorId) { + throw new LogError('Cannot update contribution of moderator', contributionToUpdate, user.id) + } if ( contributionToUpdate.contributionStatus !== ContributionStatus.IN_PROGRESS && contributionToUpdate.contributionStatus !== ContributionStatus.PENDING