From 2146c98ee46e4cadd7a40d3b693ce2631d8e679d Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 9 Mar 2023 20:42:07 +0100 Subject: [PATCH 01/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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/47] 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 6d18fce4e8d2991744a837c1ed09b3142a940a80 Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 23 Mar 2023 15:41:13 +0100 Subject: [PATCH 17/47] remove toggle and add confirm modal to user (un)deletion in admin interface --- admin/src/components/DeletedUserFormular.vue | 54 +++++++++++++++++--- admin/src/locales/de.json | 10 ++++ admin/src/locales/en.json | 10 ++++ 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/admin/src/components/DeletedUserFormular.vue b/admin/src/components/DeletedUserFormular.vue index 576ac9f93..bdffc2e54 100644 --- a/admin/src/components/DeletedUserFormular.vue +++ b/admin/src/components/DeletedUserFormular.vue @@ -4,19 +4,36 @@ {{ $t('removeNotSelf') }}
- -
{{ item.deletedAt ? $t('undelete_user') : $t('delete_user') }}
-
-
- + {{ $t('delete_user') }} - + {{ $t('undelete_user') }}
+ +

{{ modalQuestion }}

+