From 4e72aafe4d787287429d8e90d0cfe91d68096b97 Mon Sep 17 00:00:00 2001 From: elweyn Date: Sun, 18 Sep 2022 11:22:25 +0200 Subject: [PATCH 01/72] Change the query so that we only look on the contributions table. --- .../src/graphql/resolver/util/creations.ts | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index ad15ebec6..3a6a14fda 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -43,39 +43,54 @@ export const getUserCreations = async ( const dateFilter = 'last_day(curdate() - interval 3 month) + interval 1 day' logger.trace('getUserCreations dateFilter', dateFilter) - const unionString = includePending - ? ` - UNION - SELECT contribution_date AS date, amount AS amount, user_id AS userId FROM contributions - WHERE user_id IN (${ids.toString()}) - AND contribution_date >= ${dateFilter} - AND confirmed_at IS NULL AND deleted_at IS NULL` - : '' - - const unionQuery = await queryRunner.manager.query(` - SELECT MONTH(date) AS month, sum(amount) AS sum, userId AS id FROM - (SELECT creation_date AS date, amount AS amount, user_id AS userId FROM transactions - WHERE user_id IN (${ids.toString()}) - AND type_id = ${TransactionTypeId.CREATION} - AND creation_date >= ${dateFilter} - ${unionString}) AS result - GROUP BY month, userId - ORDER BY date DESC - `) - + /** + SELECT MONTH(contribution_date) as month, user_id, created_at, sum(amount), confirmed_at, deleted_at + FROM `contributions` + where user_id = 776 + and contribution_date >= last_day(curdate() - interval 3 month) + interval 1 day + and deleted_at IS NULL + if(!includePending) and confirmed_at IS NOT NULL + group by month, user_id; + */ + const bookedCreationQuery = queryRunner.manager + .createQueryBuilder(Contribution, 'c') + .select('month(contribution_date)', 'month') + .addSelect('user_id', 'userId') + .addSelect('sum(amount)', 'sum') + .where(`user_id in (${ids.toString()})`) + .andWhere(`contribution_date >= ${dateFilter}`) + .andWhere('deleted_at IS NULL') + .groupBy('month') + .addGroupBy('userId') + if (!includePending) { + bookedCreationQuery.andWhere('confirmed_at IS NOT NULL') + } + const bookedCreation = await bookedCreationQuery.getRawMany() + // eslint-disable-next-line no-console + console.log('openCreation', bookedCreation) await queryRunner.release() return ids.map((id) => { return { id, creations: months.map((month) => { - const creation = unionQuery.find( - (raw: { month: string; id: string; creation: number[] }) => - parseInt(raw.month) === month && parseInt(raw.id) === id, + const creation = bookedCreation.find( + (raw: { month: string; userId: string; creation: number[] }) => + parseInt(raw.month) === month && parseInt(raw.userId) === id, ) return MAX_CREATION_AMOUNT.minus(creation ? creation.sum : 0) }), } + // const creations = months.map((month) => { + // const creation = openCreation.find( + // (raw: { month: string; userId: string; creation: number[] }) => + // parseInt(raw.month) === month && parseInt(raw.userId) === id, + // ) + // return MAX_CREATION_AMOUNT.minus(creation ? creation.sum : 0) + // }) + // // eslint-disable-next-line no-console + // console.log('id: ', id, 'creations: ', creations.toString()) + // return { id, creations } }) } From e097c30003ce5162616e5df3fb6294dfaeeaa710 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 21 Sep 2022 11:47:24 +0200 Subject: [PATCH 02/72] Add denied_at is null to query, change variable name of query. --- backend/src/graphql/resolver/util/creations.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index 3a6a14fda..6135d282a 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -1,4 +1,3 @@ -import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' import { backendLogger as logger } from '@/server/logger' import { getConnection } from '@dbTools/typeorm' import { Contribution } from '@entity/Contribution' @@ -49,10 +48,11 @@ export const getUserCreations = async ( where user_id = 776 and contribution_date >= last_day(curdate() - interval 3 month) + interval 1 day and deleted_at IS NULL + and denied_at IS NULL if(!includePending) and confirmed_at IS NOT NULL group by month, user_id; */ - const bookedCreationQuery = queryRunner.manager + const sumAmountContributionPerUserAndLast3MonthQuery = queryRunner.manager .createQueryBuilder(Contribution, 'c') .select('month(contribution_date)', 'month') .addSelect('user_id', 'userId') @@ -60,21 +60,22 @@ export const getUserCreations = async ( .where(`user_id in (${ids.toString()})`) .andWhere(`contribution_date >= ${dateFilter}`) .andWhere('deleted_at IS NULL') + .andWhere('denied_at IS NULL') .groupBy('month') .addGroupBy('userId') if (!includePending) { - bookedCreationQuery.andWhere('confirmed_at IS NOT NULL') + sumAmountContributionPerUserAndLast3MonthQuery.andWhere('confirmed_at IS NOT NULL') } - const bookedCreation = await bookedCreationQuery.getRawMany() - // eslint-disable-next-line no-console - console.log('openCreation', bookedCreation) + const sumAmountContributionPerUserAndLast3Month = + await sumAmountContributionPerUserAndLast3MonthQuery.getRawMany() + await queryRunner.release() return ids.map((id) => { return { id, creations: months.map((month) => { - const creation = bookedCreation.find( + const creation = sumAmountContributionPerUserAndLast3Month.find( (raw: { month: string; userId: string; creation: number[] }) => parseInt(raw.month) === month && parseInt(raw.userId) === id, ) From 2ca9945a1b1675ffe402b9734d225840bdb6ce5e Mon Sep 17 00:00:00 2001 From: joseji Date: Wed, 28 Sep 2022 11:09:14 +0200 Subject: [PATCH 03/72] added missing events --- backend/src/graphql/resolver/AdminResolver.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index e9ee0b55b..4bf2794dc 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -66,6 +66,8 @@ import { ContributionMessageType } from '@enum/MessageType' import { ContributionMessage } from '@model/ContributionMessage' import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' import { sendAddedContributionMessageEmail } from '@/mailer/sendAddedContributionMessageEmail' +import { eventProtocol } from '@/event/EventProtocolEmitter' +import { Event, EventContributionConfirm, EventContributionCreate, EventContributionLinkDefine, EventSendConfirmationEmail } from '@/event/Event' // const EMAIL_OPT_IN_REGISTER = 1 // const EMAIL_OPT_UNKNOWN = 3 // elopage? @@ -241,6 +243,8 @@ export class AdminResolver { logger.error('Contribution could not be saved, Email is not activated') throw new Error('Contribution could not be saved, Email is not activated') } + + const event = new Event() const moderator = getUser(context) logger.trace('moderator: ', moderator.id) const creations = await getUserCreation(emailContact.userId) @@ -260,6 +264,13 @@ export class AdminResolver { logger.trace('contribution to save', contribution) await Contribution.save(contribution) + + const eventCreateContribution = new EventContributionCreate() + eventCreateContribution.userId = moderator.id + eventCreateContribution.amount = amount + eventCreateContribution.contributionId = contribution.id + await eventProtocol.writeEvent(event.setEventContributionCreate(eventCreateContribution)) + return getUserCreation(emailContact.userId) } @@ -495,6 +506,13 @@ export class AdminResolver { contributionAmount: contribution.amount, overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, }) + + const event = new Event() + const eventContributionConfirm = new EventContributionConfirm() + eventContributionConfirm.xUserId = user.id + eventContributionConfirm.amount = contribution.amount + eventContributionConfirm.contributionId = contribution.id + await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm)) } catch (e) { await queryRunner.rollbackTransaction() logger.error(`Creation was not successful: ${e}`) @@ -558,6 +576,13 @@ export class AdminResolver { // In case EMails are disabled log the activation link for the user if (!emailSent) { logger.info(`Account confirmation link: ${activationLink}`) + } else { + const event = new Event() + const eventSendConfirmationEmail = new EventSendConfirmationEmail() + eventSendConfirmationEmail.userId = user.id + await eventProtocol.writeEvent( + event.setEventSendConfirmationEmail(eventSendConfirmationEmail), + ) } return true @@ -660,6 +685,13 @@ export class AdminResolver { dbContributionLink.maxAmountPerMonth = maxAmountPerMonth dbContributionLink.maxPerCycle = maxPerCycle await dbContributionLink.save() + + const event = new Event() + const eventContributionLinkDefine = new EventContributionLinkDefine() + await eventProtocol.writeEvent( + event.setEventContributionLinkDefine(eventContributionLinkDefine), + ) + logger.debug(`createContributionLink successful!`) return new ContributionLink(dbContributionLink) } From 33eeab344f6e2b479452ab51599b17d5eb045026 Mon Sep 17 00:00:00 2001 From: joseji Date: Wed, 28 Sep 2022 11:14:16 +0200 Subject: [PATCH 04/72] added missing error logs --- backend/src/graphql/resolver/AdminResolver.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 4bf2794dc..660f5ab31 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -148,11 +148,13 @@ export class AdminResolver { const user = await dbUser.findOne({ id: userId }) // user exists ? if (!user) { + logger.error(`Could not find user with userId: ${userId}`) throw new Error(`Could not find user with userId: ${userId}`) } // administrator user changes own role? const moderatorUser = getUser(context) if (moderatorUser.id === userId) { + logger.error('Administrator can not change his own role!') throw new Error('Administrator can not change his own role!') } // change isAdmin @@ -161,6 +163,7 @@ export class AdminResolver { if (isAdmin === true) { user.isAdmin = new Date() } else { + logger.error('User is already a usual user!') throw new Error('User is already a usual user!') } break @@ -168,6 +171,7 @@ export class AdminResolver { if (isAdmin === false) { user.isAdmin = null } else { + logger.error('User is already admin!') throw new Error('User is already admin!') } break @@ -186,11 +190,13 @@ export class AdminResolver { const user = await dbUser.findOne({ id: userId }) // user exists ? if (!user) { + logger.error(`Could not find user with userId: ${userId}`) throw new Error(`Could not find user with userId: ${userId}`) } // moderator user disabled own account? const moderatorUser = getUser(context) if (moderatorUser.id === userId) { + logger.error('Moderator can not delete his own account!') throw new Error('Moderator can not delete his own account!') } // soft-delete user @@ -204,9 +210,11 @@ export class AdminResolver { async unDeleteUser(@Arg('userId', () => Int) userId: number): Promise { const user = await dbUser.findOne({ id: userId }, { withDeleted: true }) if (!user) { + logger.error(`Could not find user with userId: ${userId}`) throw new Error(`Could not find user with userId: ${userId}`) } if (!user.deletedAt) { + logger.error('User is not deleted') throw new Error('User is not deleted') } await user.recover() @@ -781,9 +789,11 @@ export class AdminResolver { relations: ['user'], }) if (!contribution) { + logger.error('Contribution not found') throw new Error('Contribution not found') } if (contribution.userId === user.id) { + logger.error('Admin can not answer on own contribution') throw new Error('Admin can not answer on own contribution') } if (!contribution.user.emailContact) { From 0f1f9baa8dd0f836a0f1112a98865118968f5647 Mon Sep 17 00:00:00 2001 From: joseji Date: Wed, 28 Sep 2022 11:57:49 +0200 Subject: [PATCH 05/72] added tests for events --- .../graphql/resolver/AdminResolver.test.ts | 27 ++++++++++++++++++ backend/src/graphql/resolver/AdminResolver.ts | 28 +++++++++---------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index b1b4e469e..c132cb10f 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -41,6 +41,8 @@ import { Contribution } from '@entity/Contribution' import { Transaction as DbTransaction } from '@entity/Transaction' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' +import { EventProtocol } from '@entity/EventProtocol' +import { EventProtocolType } from '@/event/EventProtocolType' // mock account activation email to avoid console spam jest.mock('@/mailer/sendAccountActivationEmail', () => { @@ -1037,6 +1039,15 @@ describe('AdminResolver', () => { }), ) }) + + it('stores the create contribution event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.CONTRIBUTION_CREATE, + userId: admin.id, + }), + ) + }) }) describe('second creation surpasses the available amount ', () => { @@ -1451,6 +1462,14 @@ describe('AdminResolver', () => { ) }) + it('stores the contribution confirm event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.CONTRIBUTION_CONFIRM, + }), + ) + }) + it('creates a transaction', async () => { const transaction = await DbTransaction.find() expect(transaction[0].amount.toString()).toBe('450') @@ -1475,6 +1494,14 @@ describe('AdminResolver', () => { }), ) }) + + it('stores the send confirmation email event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.SEND_CONFIRMATION_EMAIL, + }), + ) + }) }) describe('confirm two creations one after the other quickly', () => { diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 660f5ab31..b03da9dc4 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -67,7 +67,12 @@ import { ContributionMessage } from '@model/ContributionMessage' import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' import { sendAddedContributionMessageEmail } from '@/mailer/sendAddedContributionMessageEmail' import { eventProtocol } from '@/event/EventProtocolEmitter' -import { Event, EventContributionConfirm, EventContributionCreate, EventContributionLinkDefine, EventSendConfirmationEmail } from '@/event/Event' +import { + Event, + EventContributionConfirm, + EventContributionCreate, + EventSendConfirmationEmail, +} from '@/event/Event' // const EMAIL_OPT_IN_REGISTER = 1 // const EMAIL_OPT_UNKNOWN = 3 // elopage? @@ -514,13 +519,6 @@ export class AdminResolver { contributionAmount: contribution.amount, overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, }) - - const event = new Event() - const eventContributionConfirm = new EventContributionConfirm() - eventContributionConfirm.xUserId = user.id - eventContributionConfirm.amount = contribution.amount - eventContributionConfirm.contributionId = contribution.id - await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm)) } catch (e) { await queryRunner.rollbackTransaction() logger.error(`Creation was not successful: ${e}`) @@ -528,6 +526,13 @@ export class AdminResolver { } finally { await queryRunner.release() } + + const event = new Event() + const eventContributionConfirm = new EventContributionConfirm() + eventContributionConfirm.userId = user.id + eventContributionConfirm.amount = contribution.amount + eventContributionConfirm.contributionId = contribution.id + await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm)) return true } @@ -693,13 +698,6 @@ export class AdminResolver { dbContributionLink.maxAmountPerMonth = maxAmountPerMonth dbContributionLink.maxPerCycle = maxPerCycle await dbContributionLink.save() - - const event = new Event() - const eventContributionLinkDefine = new EventContributionLinkDefine() - await eventProtocol.writeEvent( - event.setEventContributionLinkDefine(eventContributionLinkDefine), - ) - logger.debug(`createContributionLink successful!`) return new ContributionLink(dbContributionLink) } From a756f0a4cc7c078e106f5c2515864d4196703cdf Mon Sep 17 00:00:00 2001 From: joseji Date: Wed, 28 Sep 2022 12:47:00 +0200 Subject: [PATCH 06/72] all tests completed --- .../graphql/resolver/AdminResolver.test.ts | 189 ++++++++++++++++++ .../src/graphql/resolver/util/creations.ts | 2 +- 2 files changed, 190 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index c132cb10f..6576a7d04 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -43,6 +43,7 @@ import { ContributionLink as DbContributionLink } from '@entity/ContributionLink import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' import { EventProtocol } from '@entity/EventProtocol' import { EventProtocolType } from '@/event/EventProtocolType' +import { logger } from '@test/testSetup' // mock account activation email to avoid console spam jest.mock('@/mailer/sendAccountActivationEmail', () => { @@ -144,6 +145,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${admin.id + 1}`) + }) }) describe('change role with success', () => { @@ -196,6 +201,9 @@ describe('AdminResolver', () => { }), ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Administrator can not change his own role!') + }) }) describe('user has already role to be set', () => { @@ -213,6 +221,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User is already admin!') + }) }) describe('to usual user', () => { @@ -229,6 +241,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User is already a usual user!') + }) }) }) }) @@ -297,6 +313,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${admin.id + 1}`) + }) }) describe('delete self', () => { @@ -309,6 +329,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Moderator can not delete his own account!') + }) }) describe('delete with success', () => { @@ -338,6 +362,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${user.id}`) + }) }) }) }) @@ -405,6 +433,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${admin.id + 1}`) + }) }) describe('user to undelete is not deleted', () => { @@ -422,6 +454,10 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User is not deleted') + }) + describe('undelete deleted user', () => { beforeAll(async () => { await mutate({ mutation: deleteUser, variables: { userId: user.id } }) @@ -909,6 +945,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Could not find user with email: bibi@bloxberg.de', + ) + }) }) describe('user to create for is deleted', () => { @@ -928,6 +970,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'This user was deleted. Cannot create a contribution.', + ) + }) }) describe('user to create for has email not confirmed', () => { @@ -947,6 +995,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Contribution could not be saved, Email is not activated', + ) + }) }) describe('valid user to create for', () => { @@ -967,6 +1021,13 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'No information for available creations with the given creationDate=', + new Date('not-valid').toString(), + ) + }) }) describe('date of creation is four months ago', () => { @@ -987,6 +1048,13 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'No information for available creations with the given creationDate=', + variables.creationDate, + ) + }) }) describe('date of creation is in the future', () => { @@ -1007,6 +1075,13 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'No information for available creations with the given creationDate=', + variables.creationDate, + ) + }) }) describe('amount of creation is too high', () => { @@ -1024,6 +1099,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount (2000 GDD) to be created exceeds the amount (1000 GDD) still available for this month.', + ) + }) }) describe('creation is valid', () => { @@ -1065,6 +1146,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount (1000 GDD) to be created exceeds the amount (800 GDD) still available for this month.', + ) + }) }) }) }) @@ -1143,6 +1230,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Could not find UserContact with email: bob@baumeister.de', + ) + }) }) describe('user for creation to update is deleted', () => { @@ -1164,6 +1257,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User was deleted (stephen@hawking.uk)') + }) }) describe('creation does not exist', () => { @@ -1185,6 +1282,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('No contribution found to given id.') + }) }) describe('user email does not match creation user', () => { @@ -1210,6 +1311,12 @@ describe('AdminResolver', () => { }), ) }) + + 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', () => { @@ -1235,6 +1342,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount (1900 GDD) to be created exceeds the amount (500 GDD) still available for this month.', + ) + }) }) describe('creation update is successful changing month', () => { @@ -1371,6 +1484,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution not found for given id: -1') + }) }) describe('creation id does exist', () => { @@ -1407,6 +1524,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution not found for given id: -1') + }) }) describe('confirm own creation', () => { @@ -1434,6 +1555,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Moderator can not confirm own contribution') + }) }) describe('confirm creation for other user', () => { @@ -2041,6 +2166,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Start-Date is not initialized. A Start-Date must be set!', + ) + }) + it('returns an error if missing endDate', async () => { await expect( mutate({ @@ -2057,6 +2188,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'End-Date is not initialized. An End-Date must be set!', + ) + }) + it('returns an error if endDate is before startDate', async () => { await expect( mutate({ @@ -2076,6 +2213,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of validFrom must before or equals the validTo!`, + ) + }) + it('returns an error if name is an empty string', async () => { await expect( mutate({ @@ -2092,6 +2235,10 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('The name must be initialized!') + }) + it('returns an error if name is shorter than 5 characters', async () => { await expect( mutate({ @@ -2112,6 +2259,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'name' with a length of 3 did not fulfill the requested bounderies min=5 and max=100`, + ) + }) + it('returns an error if name is longer than 100 characters', async () => { await expect( mutate({ @@ -2132,6 +2285,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'name' with a length of 101 did not fulfill the requested bounderies min=5 and max=100`, + ) + }) + it('returns an error if memo is an empty string', async () => { await expect( mutate({ @@ -2148,6 +2307,10 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('The memo must be initialized!') + }) + it('returns an error if memo is shorter than 5 characters', async () => { await expect( mutate({ @@ -2168,6 +2331,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'memo' with a length of 3 did not fulfill the requested bounderies min=5 and max=255`, + ) + }) + it('returns an error if memo is longer than 255 characters', async () => { await expect( mutate({ @@ -2188,6 +2357,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'memo' with a length of 256 did not fulfill the requested bounderies min=5 and max=255`, + ) + }) + it('returns an error if amount is not positive', async () => { await expect( mutate({ @@ -2205,6 +2380,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount=0 must be initialized with a positiv value!', + ) + }) }) describe('listContributionLinks', () => { @@ -2260,6 +2441,10 @@ describe('AdminResolver', () => { }) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution Link not found to given id: -1') + }) + describe('valid id', () => { let linkId: number beforeAll(async () => { @@ -2325,6 +2510,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution Link not found to given id: -1') + }) }) describe('valid id', () => { diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index 4f1cec0e0..9987dfae6 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -21,7 +21,7 @@ export const validateContribution = ( if (index < 0) { logger.error( 'No information for available creations with the given creationDate=', - creationDate, + creationDate.toString(), ) throw new Error('No information for available creations for the given date') } From df2519784211723a52c9415770a0c6c66cc3a4d2 Mon Sep 17 00:00:00 2001 From: joseji Date: Thu, 29 Sep 2022 11:39:01 +0200 Subject: [PATCH 07/72] solved unnecessary date creation regarding one invalid date testing --- backend/src/graphql/resolver/AdminResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index 6576a7d04..53097abbe 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -1025,7 +1025,7 @@ describe('AdminResolver', () => { it('logs the error thrown', () => { expect(logger.error).toBeCalledWith( 'No information for available creations with the given creationDate=', - new Date('not-valid').toString(), + 'Invalid Date', ) }) }) From ce3d9b1708d9ba27f6fabc93fe3787990fa3c32a Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 4 Oct 2022 12:43:51 +0200 Subject: [PATCH 08/72] find link and replace to element --- .../slots/ContributionMessagesListItem.vue | 20 +++++++++++++++++++ .../slots/IsModerator.vue | 2 +- .../slots/IsNotModerator.vue | 2 +- .../ContributionMessagesListItem.vue | 17 +++++++++++++++- .../slots/IsModerator.vue | 2 +- .../slots/IsNotModerator.vue | 2 +- 6 files changed, 40 insertions(+), 5 deletions(-) diff --git a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue index fa5bdd940..c0bb7558c 100644 --- a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue +++ b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue @@ -23,5 +23,25 @@ export default { }, }, }, + data() { + return { + pattern: + // eslint-disable-next-line no-useless-escape + /(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*))/gi, + messageObject: this.message, + } + }, + methods: { + linkify(inputText) { + // console.log(inputText.match(this.pattern)) + this.messageObject.message = inputText.replace( + this.pattern, + "$1", + ) + }, + }, + created() { + this.linkify(this.messageObject.message) + }, } diff --git a/admin/src/components/ContributionMessages/slots/IsModerator.vue b/admin/src/components/ContributionMessages/slots/IsModerator.vue index 0224e042f..6363e4aa2 100644 --- a/admin/src/components/ContributionMessages/slots/IsModerator.vue +++ b/admin/src/components/ContributionMessages/slots/IsModerator.vue @@ -5,7 +5,7 @@ {{ message.userFirstName }} {{ message.userLastName }} {{ $d(new Date(message.createdAt), 'short') }} {{ $t('moderator') }} -
{{ message.message }}
+
diff --git a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue b/admin/src/components/ContributionMessages/slots/IsNotModerator.vue index 64946c557..f45d4f890 100644 --- a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue +++ b/admin/src/components/ContributionMessages/slots/IsNotModerator.vue @@ -4,7 +4,7 @@ {{ message.userFirstName }} {{ message.userLastName }} {{ $d(new Date(message.createdAt), 'short') }} -
{{ message.message }}
+
diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue b/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue index 5fde8f825..9e0b49313 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue @@ -1,6 +1,6 @@ @@ -25,6 +25,9 @@ export default { }, data() { return { + // eslint-disable-next-line no-useless-escape + pattern: /(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*))/gi, + messageObject: this.message, storeName: `${this.$store.state.firstName} ${this.$store.state.lastName}`, moderationName: `${this.message.userFirstName} ${this.message.userLastName}`, } @@ -34,5 +37,17 @@ export default { return this.storeName === this.moderationName }, }, + methods: { + linkify(inputText) { + // console.log(inputText.match(this.pattern)) + this.messageObject.message = inputText.replace( + this.pattern, + "$1", + ) + }, + }, + created() { + this.linkify(this.messageObject.message) + }, } diff --git a/frontend/src/components/ContributionMessages/slots/IsModerator.vue b/frontend/src/components/ContributionMessages/slots/IsModerator.vue index 343b92d97..d0810d9fb 100644 --- a/frontend/src/components/ContributionMessages/slots/IsModerator.vue +++ b/frontend/src/components/ContributionMessages/slots/IsModerator.vue @@ -4,7 +4,7 @@ {{ message.userFirstName }} {{ message.userLastName }} {{ $d(new Date(message.createdAt), 'short') }} {{ $t('community.moderator') }} -
{{ message.message }}
+
- diff --git a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue b/admin/src/components/ContributionMessages/slots/IsNotModerator.vue deleted file mode 100644 index f45d4f890..000000000 --- a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/frontend/src/components/ContributionMessages/slots/IsModerator.vue b/frontend/src/components/ContributionMessages/slots/IsModerator.vue deleted file mode 100644 index d0810d9fb..000000000 --- a/frontend/src/components/ContributionMessages/slots/IsModerator.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/frontend/src/components/ContributionMessages/slots/IsNotModerator.vue b/frontend/src/components/ContributionMessages/slots/IsNotModerator.vue deleted file mode 100644 index c726cb8ef..000000000 --- a/frontend/src/components/ContributionMessages/slots/IsNotModerator.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - From cb39745b2324bbf2312435ee5fe207be0f6cec54 Mon Sep 17 00:00:00 2001 From: ogerly Date: Sat, 15 Oct 2022 07:54:58 +0200 Subject: [PATCH 22/72] change linkify to computed --- .../slots/ContributionMessagesListItem.vue | 32 ++++++------------- .../ContributionMessagesListItem.vue | 26 +++++---------- 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue index 70ca24cc4..5eae5d7cd 100644 --- a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue +++ b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue @@ -1,21 +1,24 @@ From 208cb30274f6403ffd70d68cc360c0d959311111 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 31 Oct 2022 15:03:19 +0100 Subject: [PATCH 61/72] the last and current month is displayed cleanly again. --- .../Contributions/ContributionForm.spec.js | 16 ++++++++-------- .../Contributions/ContributionForm.vue | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.spec.js b/frontend/src/components/Contributions/ContributionForm.spec.js index 8f35948f9..e85a94884 100644 --- a/frontend/src/components/Contributions/ContributionForm.spec.js +++ b/frontend/src/components/Contributions/ContributionForm.spec.js @@ -109,8 +109,8 @@ describe('ContributionForm', () => { }) describe('minimalDate', () => { - it('has "2020-06-01T00:00:00.000Z"', () => { - expect(wrapper.vm.minimalDate.toISOString()).toBe('2020-06-01T00:00:00.000Z') + it('has "2020-05-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2020-05-01T00:00:00.000Z') }) }) @@ -136,8 +136,8 @@ describe('ContributionForm', () => { }) describe('minimalDate', () => { - it('has "2020-06-01T00:00:00.000Z"', () => { - expect(wrapper.vm.minimalDate.toISOString()).toBe('2020-06-01T00:00:00.000Z') + it('has "2020-05-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2020-05-01T00:00:00.000Z') }) }) @@ -159,8 +159,8 @@ describe('ContributionForm', () => { }) describe('minimalDate', () => { - it('has "2019-12-01T00:00:00.000Z"', () => { - expect(wrapper.vm.minimalDate.toISOString()).toBe('2019-12-01T00:00:00.000Z') + it('has "2019-11-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2019-11-01T00:00:00.000Z') }) }) @@ -186,8 +186,8 @@ describe('ContributionForm', () => { }) describe('minimalDate', () => { - it('has "2019-12-01T00:00:00.000Z"', () => { - expect(wrapper.vm.minimalDate.toISOString()).toBe('2019-12-01T00:00:00.000Z') + it('has "2019-11-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2019-11-01T00:00:00.000Z') }) }) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index 71593f2b1..bb8a1902f 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -134,7 +134,7 @@ export default { // sets the date to the 1st of the previous month let date = new Date(this.maximalDate) // has to be a new object, because of 'setMonth' changes the objects date date = new Date(date.setMonth(date.getMonth() - 1)) - return new Date(date.getFullYear(), date.getMonth(), 1) + return new Date(date.getFullYear(), date.getMonth() - 1) }, disabled() { return ( From 9d01155d919b109540a55c97862dc2dc9d7ed74e Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 1 Nov 2022 10:16:30 +0100 Subject: [PATCH 62/72] github test workflow: add e2e testing job --- .github/workflows/test.yml | 67 +++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 34ebeff11..d89de5d7f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,9 @@ name: gradido test CI -on: [push] +on: + push: + branches: + - 2283-feature-implement-fullstack-tests-as-github-workflow jobs: ############################################################################## @@ -553,3 +556,65 @@ jobs: run: docker-compose -f docker-compose.yml run -T database yarn up - name: database | reset run: docker-compose -f docker-compose.yml run -T database yarn reset + + ############################################################################## + # JOB: END-TO-END TESTS ##################################################### + ############################################################################## + end-to-end-tests: + name: End-to-End Tests + runs-on: ubuntu-latest + # needs: [build_test_mariadb, build_test_database_up, build_test_backend, build_test_admin, build_test_frontend, build_test_nginx] + steps: + ########################################################################## + # CHECKOUT CODE ########################################################## + ########################################################################## + - name: Checkout code + uses: actions/checkout@v3 + ########################################################################## + # BOOT UP THE TEST SYSTEM ################################################ + ########################################################################## + - name: Boot up test system | docker-compose mariadb + run: docker-compose up --detach mariadb + + - name: Sleep for 30 seconds + run: sleep 30s + + - name: Boot up test system | docker-compose database + run: docker-compose up --detach --no-deps database + + - name: Boot up test system | docker-compose backend + run: docker-compose up --detach --no-deps backend + + - name: Sleep for 90 seconds + run: sleep 90s + + - name: Boot up test system | seed backend + run: | + sudo chown runner:docker -R * + cd database + yarn && yarn dev_reset + cd ../backend + yarn && yarn seed + cd .. + + - name: Boot up test system | docker-compose frontends + run: docker-compose up --detach --no-deps frontend admin nginx + + - name: Sleep for 2.5 minutes + run: sleep 150s + + ########################################################################## + # END-TO-END TESTS ####################################################### + ########################################################################## + - name: End-to-end tests | run tests + id: e2e-tests + run: | + cd e2e-tests/cypress/tests/ + yarn + yarn run cypress run --spec cypress/e2e/User.Authentication.feature + - name: End-to-end tests | if tests failed, upload screenshots + if: steps.e2e-tests.outcome == 'failure' + uses: actions/upload-artifact@v3 + with: + name: cypress-screenshots + path: /home/runner/work/gradido/gradido/e2e-tests/cypress/tests/cypress/screenshots/ From 1be1339992456377b9afc0ea4c0d0e78a3d83eb8 Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 1 Nov 2022 10:32:28 +0100 Subject: [PATCH 63/72] github test workflow: rename branch for triggering --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d89de5d7f..9afee6075 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,7 +3,7 @@ name: gradido test CI on: push: branches: - - 2283-feature-implement-fullstack-tests-as-github-workflow + - 2283-feature-fullstack-tests-as-github-workflow jobs: ############################################################################## From 720c064c4d78efd55ef3106d43cebbbc658b5f10 Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 1 Nov 2022 10:56:15 +0100 Subject: [PATCH 64/72] github test workflow: add job dependencies to e2e tests job --- .github/workflows/test.yml | 47 +++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9afee6075..a971eee4e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -563,7 +563,7 @@ jobs: end-to-end-tests: name: End-to-End Tests runs-on: ubuntu-latest - # needs: [build_test_mariadb, build_test_database_up, build_test_backend, build_test_admin, build_test_frontend, build_test_nginx] + needs: [build_test_mariadb, build_test_database_up, build_test_backend, build_test_admin, build_test_frontend, build_test_nginx] steps: ########################################################################## # CHECKOUT CODE ########################################################## @@ -571,6 +571,51 @@ jobs: - name: Checkout code uses: actions/checkout@v3 ########################################################################## + # DOWNLOAD DOCKER IMAGES ################################################# + ########################################################################## + - name: Download Docker Image (Mariadb) + uses: actions/download-artifact@v3 + with: + name: docker-mariadb-test + path: /tmp + - name: Load Docker Image (Mariadb) + run: docker load < /tmp/mariadb.tar + - name: Download Docker Image (Database Up) + uses: actions/download-artifact@v3 + with: + name: docker-database-test_up + path: /tmp + - name: Load Docker Image (Database Up) + run: docker load < /tmp/database_up.tar + - name: Download Docker Image (Backend) + uses: actions/download-artifact@v3 + with: + name: docker-backend-test + path: /tmp + - name: Load Docker Image (Backend) + run: docker load < /tmp/backend.tar + - name: Download Docker Image (Frontend) + uses: actions/download-artifact@v3 + with: + name: docker-frontend-test + path: /tmp + - name: Load Docker Image (Frontend) + run: docker load < /tmp/frontend.tar + - name: Download Docker Image (Admin Interface) + uses: actions/download-artifact@v3 + with: + name: docker-admin-test + path: /tmp + - name: Load Docker Image (Admin Interface) + run: docker load < /tmp/nginx.tar + - name: Download Docker Image (Nginx) + uses: actions/download-artifact@v3 + with: + name: docker-nginx-test + path: /tmp + - name: Load Docker Image (Nginx) + run: docker load < /tmp/nginx.tar + ########################################################################## # BOOT UP THE TEST SYSTEM ################################################ ########################################################################## - name: Boot up test system | docker-compose mariadb From 9cd0f450594acce14cf7939fd1e357b1cd162626 Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 1 Nov 2022 11:08:06 +0100 Subject: [PATCH 65/72] github test workflow: fix typos --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a971eee4e..96d0ce9a1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -311,7 +311,7 @@ jobs: # JOB: LOCALES ADMIN ######################################################### ############################################################################## locales_admin: - name: Locales - Admin + name: Locales - Admin Interface runs-on: ubuntu-latest needs: [build_test_admin] steps: @@ -607,7 +607,7 @@ jobs: name: docker-admin-test path: /tmp - name: Load Docker Image (Admin Interface) - run: docker load < /tmp/nginx.tar + run: docker load < /tmp/admin.tar - name: Download Docker Image (Nginx) uses: actions/download-artifact@v3 with: From 6c8d9966491bef65cd65c497ff7dd1b3fe7402df Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 1 Nov 2022 11:24:50 +0100 Subject: [PATCH 66/72] more tests, 31st, 28st, 29.02.2024 --- .../Contributions/ContributionForm.spec.js | 85 +++++++++++++++++-- .../Contributions/ContributionForm.vue | 6 +- 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.spec.js b/frontend/src/components/Contributions/ContributionForm.spec.js index e85a94884..3af716d36 100644 --- a/frontend/src/components/Contributions/ContributionForm.spec.js +++ b/frontend/src/components/Contributions/ContributionForm.spec.js @@ -109,8 +109,8 @@ describe('ContributionForm', () => { }) describe('minimalDate', () => { - it('has "2020-05-01T00:00:00.000Z"', () => { - expect(wrapper.vm.minimalDate.toISOString()).toBe('2020-05-01T00:00:00.000Z') + it('has "2020-06-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2020-06-01T00:00:00.000Z') }) }) @@ -136,8 +136,8 @@ describe('ContributionForm', () => { }) describe('minimalDate', () => { - it('has "2020-05-01T00:00:00.000Z"', () => { - expect(wrapper.vm.minimalDate.toISOString()).toBe('2020-05-01T00:00:00.000Z') + it('has "2020-06-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2020-06-01T00:00:00.000Z') }) }) @@ -159,8 +159,8 @@ describe('ContributionForm', () => { }) describe('minimalDate', () => { - it('has "2019-11-01T00:00:00.000Z"', () => { - expect(wrapper.vm.minimalDate.toISOString()).toBe('2019-11-01T00:00:00.000Z') + it('has "2019-12-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2019-12-01T00:00:00.000Z') }) }) @@ -186,8 +186,8 @@ describe('ContributionForm', () => { }) describe('minimalDate', () => { - it('has "2019-11-01T00:00:00.000Z"', () => { - expect(wrapper.vm.minimalDate.toISOString()).toBe('2019-11-01T00:00:00.000Z') + it('has "2019-12-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2019-12-01T00:00:00.000Z') }) }) @@ -198,6 +198,75 @@ describe('ContributionForm', () => { }) }) }) + + describe('date with the 31st day of the month', () => { + describe('same month', () => { + beforeEach(async () => { + await wrapper.setData({ + maximalDate: new Date('2022-10-31T00:00:00.000Z'), + form: { date: new Date('2022-10-31T00:00:00.000Z') }, + }) + }) + + describe('minimalDate', () => { + it('has "2022-09-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2022-09-01T00:00:00.000Z') + }) + }) + + describe('isThisMonth', () => { + it('has true', () => { + expect(wrapper.vm.isThisMonth).toBe(true) + }) + }) + }) + }) + + describe('date with the 28th day of the month', () => { + describe('same month', () => { + beforeEach(async () => { + await wrapper.setData({ + maximalDate: new Date('2023-02-28T00:00:00.000Z'), + form: { date: new Date('2023-02-28T00:00:00.000Z') }, + }) + }) + + describe('minimalDate', () => { + it('has "2023-01-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2023-01-01T00:00:00.000Z') + }) + }) + + describe('isThisMonth', () => { + it('has true', () => { + expect(wrapper.vm.isThisMonth).toBe(true) + }) + }) + }) + }) + + describe('date with 29.02.2024 leap year', () => { + describe('same month', () => { + beforeEach(async () => { + await wrapper.setData({ + maximalDate: new Date('2024-02-29T00:00:00.000Z'), + form: { date: new Date('2024-02-29T00:00:00.000Z') }, + }) + }) + + describe('minimalDate', () => { + it('has "2024-01-01T00:00:00.000Z"', () => { + expect(wrapper.vm.minimalDate.toISOString()).toBe('2024-01-01T00:00:00.000Z') + }) + }) + + describe('isThisMonth', () => { + it('has true', () => { + expect(wrapper.vm.isThisMonth).toBe(true) + }) + }) + }) + }) }) describe('set contrubtion', () => { diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index bb8a1902f..3884fd5b4 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -131,10 +131,8 @@ export default { }, computed: { minimalDate() { - // sets the date to the 1st of the previous month - let date = new Date(this.maximalDate) // has to be a new object, because of 'setMonth' changes the objects date - date = new Date(date.setMonth(date.getMonth() - 1)) - return new Date(date.getFullYear(), date.getMonth() - 1) + const date = new Date(this.maximalDate) + return new Date(date.setMonth(date.getMonth() - 1, 1)) }, disabled() { return ( From 7f565078bd7cbce43ace7e05797a6a50eb12605c Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 1 Nov 2022 11:28:19 +0100 Subject: [PATCH 67/72] github test workflow: ountcomment container dependencies --- .github/workflows/test.yml | 86 +++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 96d0ce9a1..15bdc8c50 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -563,7 +563,7 @@ jobs: end-to-end-tests: name: End-to-End Tests runs-on: ubuntu-latest - needs: [build_test_mariadb, build_test_database_up, build_test_backend, build_test_admin, build_test_frontend, build_test_nginx] + # needs: [build_test_mariadb, build_test_database_up, build_test_backend, build_test_admin, build_test_frontend, build_test_nginx] steps: ########################################################################## # CHECKOUT CODE ########################################################## @@ -573,48 +573,48 @@ jobs: ########################################################################## # DOWNLOAD DOCKER IMAGES ################################################# ########################################################################## - - name: Download Docker Image (Mariadb) - uses: actions/download-artifact@v3 - with: - name: docker-mariadb-test - path: /tmp - - name: Load Docker Image (Mariadb) - run: docker load < /tmp/mariadb.tar - - name: Download Docker Image (Database Up) - uses: actions/download-artifact@v3 - with: - name: docker-database-test_up - path: /tmp - - name: Load Docker Image (Database Up) - run: docker load < /tmp/database_up.tar - - name: Download Docker Image (Backend) - uses: actions/download-artifact@v3 - with: - name: docker-backend-test - path: /tmp - - name: Load Docker Image (Backend) - run: docker load < /tmp/backend.tar - - name: Download Docker Image (Frontend) - uses: actions/download-artifact@v3 - with: - name: docker-frontend-test - path: /tmp - - name: Load Docker Image (Frontend) - run: docker load < /tmp/frontend.tar - - name: Download Docker Image (Admin Interface) - uses: actions/download-artifact@v3 - with: - name: docker-admin-test - path: /tmp - - name: Load Docker Image (Admin Interface) - run: docker load < /tmp/admin.tar - - name: Download Docker Image (Nginx) - uses: actions/download-artifact@v3 - with: - name: docker-nginx-test - path: /tmp - - name: Load Docker Image (Nginx) - run: docker load < /tmp/nginx.tar + # - name: Download Docker Image (Mariadb) + # uses: actions/download-artifact@v3 + # with: + # name: docker-mariadb-test + # path: /tmp + # - name: Load Docker Image (Mariadb) + # run: docker load < /tmp/mariadb.tar + # - name: Download Docker Image (Database Up) + # uses: actions/download-artifact@v3 + # with: + # name: docker-database-test_up + # path: /tmp + # - name: Load Docker Image (Database Up) + # run: docker load < /tmp/database_up.tar + # - name: Download Docker Image (Backend) + # uses: actions/download-artifact@v3 + # with: + # name: docker-backend-test + # path: /tmp + # - name: Load Docker Image (Backend) + # run: docker load < /tmp/backend.tar + # - name: Download Docker Image (Frontend) + # uses: actions/download-artifact@v3 + # with: + # name: docker-frontend-test + # path: /tmp + # - name: Load Docker Image (Frontend) + # run: docker load < /tmp/frontend.tar + # - name: Download Docker Image (Admin Interface) + # uses: actions/download-artifact@v3 + # with: + # name: docker-admin-test + # path: /tmp + # - name: Load Docker Image (Admin Interface) + # run: docker load < /tmp/admin.tar + # - name: Download Docker Image (Nginx) + # uses: actions/download-artifact@v3 + # with: + # name: docker-nginx-test + # path: /tmp + # - name: Load Docker Image (Nginx) + # run: docker load < /tmp/nginx.tar ########################################################################## # BOOT UP THE TEST SYSTEM ################################################ ########################################################################## From 63c0bf8e520bd0376859d27737c7c03fbfaf1fb5 Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 1 Nov 2022 11:30:00 +0100 Subject: [PATCH 68/72] github test workflow: remove branch from trigger info --- .github/workflows/test.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 15bdc8c50..dc9e1d513 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,9 +1,6 @@ name: gradido test CI -on: - push: - branches: - - 2283-feature-fullstack-tests-as-github-workflow +on: push jobs: ############################################################################## From c7c25f2077ebafb576b4ef2cd1301dc3f61fa833 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 1 Nov 2022 13:44:09 +0100 Subject: [PATCH 69/72] more tests for all nav-items --- admin/src/components/NavBar.spec.js | 34 +++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/admin/src/components/NavBar.spec.js b/admin/src/components/NavBar.spec.js index 0d9d22905..56e02fbac 100644 --- a/admin/src/components/NavBar.spec.js +++ b/admin/src/components/NavBar.spec.js @@ -7,6 +7,10 @@ const apolloMutateMock = jest.fn() const storeDispatchMock = jest.fn() const routerPushMock = jest.fn() +const stubs = { + RouterLink: true, +} + const mocks = { $t: jest.fn((t) => t), $apollo: { @@ -28,7 +32,7 @@ describe('NavBar', () => { let wrapper const Wrapper = () => { - return mount(NavBar, { mocks, localVue }) + return mount(NavBar, { mocks, localVue, stubs }) } describe('mount', () => { @@ -41,13 +45,35 @@ describe('NavBar', () => { }) }) + describe('Navbar Menu', () => { + it('has a link to overview', () => { + expect(wrapper.findAll('.nav-item').at(0).find('a').attributes('href')).toBe('/') + }) + it('has a link to /user', () => { + expect(wrapper.findAll('.nav-item').at(1).find('a').attributes('href')).toBe('/user') + }) + it('has a link to /creation', () => { + expect(wrapper.findAll('.nav-item').at(2).find('a').attributes('href')).toBe('/creation') + }) + it('has a link to /creation-confirm', () => { + expect(wrapper.findAll('.nav-item').at(3).find('a').attributes('href')).toBe( + '/creation-confirm', + ) + }) + it('has a link to /contribution-link', () => { + expect(wrapper.findAll('.nav-item').at(4).find('a').attributes('href')).toBe( + '/contribution-link', + ) + }) + }) + describe('wallet', () => { const assignLocationSpy = jest.fn() beforeEach(async () => { - await wrapper.findAll('a').at(6).trigger('click') + await wrapper.findAll('.nav-item').at(5).find('a').trigger('click') }) - it.skip('changes widnow location to wallet', () => { + it.skip('changes window location to wallet', () => { expect(assignLocationSpy).toBeCalledWith('valid-token') }) @@ -63,7 +89,7 @@ describe('NavBar', () => { window.location = { assign: windowLocationMock, } - await wrapper.findAll('a').at(7).trigger('click') + await wrapper.findAll('.nav-item').at(6).find('a').trigger('click') }) it('redirects to /logout', () => { From fdd3b0f4fdc5fe7a00aa3958ad5b3cb705c659d4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 1 Nov 2022 14:30:43 +0100 Subject: [PATCH 70/72] fix: Release Statistic Query Runner --- backend/src/graphql/resolver/StatisticsResolver.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/graphql/resolver/StatisticsResolver.ts b/backend/src/graphql/resolver/StatisticsResolver.ts index b0c061d91..7bfae319e 100644 --- a/backend/src/graphql/resolver/StatisticsResolver.ts +++ b/backend/src/graphql/resolver/StatisticsResolver.ts @@ -63,6 +63,8 @@ export class StatisticsResolver { .where('transaction.decay IS NOT NULL') .getRawOne() + await queryRunner.release() + return { totalUsers, activeUsers, From de1a305880f7f326cd94ef21b9344ee4d1596b10 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 1 Nov 2022 14:51:56 +0100 Subject: [PATCH 71/72] rename ContributionLink to ContributionLinks --- admin/src/components/NavBar.spec.js | 4 ++-- admin/src/components/NavBar.vue | 4 +++- .../{ContributionLink.spec.js => ContributionLinks.spec.js} | 6 +++--- .../pages/{ContributionLink.vue => ContributionLinks.vue} | 0 admin/src/router/router.test.js | 6 +++--- admin/src/router/routes.js | 4 ++-- 6 files changed, 13 insertions(+), 11 deletions(-) rename admin/src/pages/{ContributionLink.spec.js => ContributionLinks.spec.js} (89%) rename admin/src/pages/{ContributionLink.vue => ContributionLinks.vue} (100%) diff --git a/admin/src/components/NavBar.spec.js b/admin/src/components/NavBar.spec.js index 56e02fbac..8956564bd 100644 --- a/admin/src/components/NavBar.spec.js +++ b/admin/src/components/NavBar.spec.js @@ -60,9 +60,9 @@ describe('NavBar', () => { '/creation-confirm', ) }) - it('has a link to /contribution-link', () => { + it('has a link to /contribution-links', () => { expect(wrapper.findAll('.nav-item').at(4).find('a').attributes('href')).toBe( - '/contribution-link', + '/contribution-links', ) }) }) diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index 48833d15d..f8dd008d1 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -19,7 +19,9 @@ > {{ $store.state.openCreations }} {{ $t('navbar.open_creation') }} - {{ $t('navbar.automaticContributions') }} + + {{ $t('navbar.automaticContributions') }} + {{ $t('navbar.my-account') }} {{ $t('navbar.logout') }} diff --git a/admin/src/pages/ContributionLink.spec.js b/admin/src/pages/ContributionLinks.spec.js similarity index 89% rename from admin/src/pages/ContributionLink.spec.js rename to admin/src/pages/ContributionLinks.spec.js index 944c1d052..fb60a99cf 100644 --- a/admin/src/pages/ContributionLink.spec.js +++ b/admin/src/pages/ContributionLinks.spec.js @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils' -import ContributionLink from './ContributionLink.vue' +import ContributionLinks from './ContributionLinks.vue' import { listContributionLinks } from '@/graphql/listContributionLinks.js' const localVue = global.localVue @@ -34,12 +34,12 @@ const mocks = { }, } -describe('ContributionLink', () => { +describe('ContributionLinks', () => { // eslint-disable-next-line no-unused-vars let wrapper const Wrapper = () => { - return mount(ContributionLink, { localVue, mocks }) + return mount(ContributionLinks, { localVue, mocks }) } describe('mount', () => { diff --git a/admin/src/pages/ContributionLink.vue b/admin/src/pages/ContributionLinks.vue similarity index 100% rename from admin/src/pages/ContributionLink.vue rename to admin/src/pages/ContributionLinks.vue diff --git a/admin/src/router/router.test.js b/admin/src/router/router.test.js index bf2e724d2..22273c15b 100644 --- a/admin/src/router/router.test.js +++ b/admin/src/router/router.test.js @@ -81,9 +81,9 @@ describe('router', () => { }) }) - describe('contribution-link', () => { - it('loads the "ContributionLink" component', async () => { - const component = await routes.find((r) => r.path === '/contribution-link').component() + describe('contribution-links', () => { + it('loads the "ContributionLinks" component', async () => { + const component = await routes.find((r) => r.path === '/contribution-links').component() expect(component.default.name).toBe('ContributionLinks') }) }) diff --git a/admin/src/router/routes.js b/admin/src/router/routes.js index caf1030a1..ee82f128e 100644 --- a/admin/src/router/routes.js +++ b/admin/src/router/routes.js @@ -24,8 +24,8 @@ const routes = [ component: () => import('@/pages/CreationConfirm.vue'), }, { - path: '/contribution-link', - component: () => import('@/pages/ContributionLink.vue'), + path: '/contribution-links', + component: () => import('@/pages/ContributionLinks.vue'), }, { path: '*', From 7f56eb2f75c40f6f90791a49741d24e75937c470 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 1 Nov 2022 15:48:31 +0100 Subject: [PATCH 72/72] release: Version 1.13.3 --- CHANGELOG.md | 13 +++++++++++++ admin/package.json | 2 +- backend/package.json | 2 +- database/package.json | 2 +- frontend/package.json | 2 +- package.json | 2 +- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa516f827..754566658 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,21 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.13.3](https://github.com/gradido/gradido/compare/1.13.2...1.13.3) + +- 2294 contribution links on its own page [`#2312`](https://github.com/gradido/gradido/pull/2312) +- fix: Change Orange Color [`#2302`](https://github.com/gradido/gradido/pull/2302) +- fix: Release Statistic Query Runner [`#2320`](https://github.com/gradido/gradido/pull/2320) +- bug: 2295 remove horizontal scrollbar in admin overview [`#2311`](https://github.com/gradido/gradido/pull/2311) +- 2292 community information contact [`#2313`](https://github.com/gradido/gradido/pull/2313) +- bug: 2315 Contribution Month and TEST FAIL in MASTER [`#2316`](https://github.com/gradido/gradido/pull/2316) +- 2291 add button for close contribution messages box [`#2314`](https://github.com/gradido/gradido/pull/2314) + #### [1.13.2](https://github.com/gradido/gradido/compare/1.13.1...1.13.2) +> 28 October 2022 + +- release: Version 1.13.2 [`#2307`](https://github.com/gradido/gradido/pull/2307) - fix: 🍰 Links In Contribution Messages Target Blank [`#2306`](https://github.com/gradido/gradido/pull/2306) - fix: Link in Contribution Messages [`#2305`](https://github.com/gradido/gradido/pull/2305) - Refactor: 🍰 Change the query so that we only look on the ``contributions`` table. [`#2217`](https://github.com/gradido/gradido/pull/2217) diff --git a/admin/package.json b/admin/package.json index 05972bb33..370f504b8 100644 --- a/admin/package.json +++ b/admin/package.json @@ -3,7 +3,7 @@ "description": "Administraion Interface for Gradido", "main": "index.js", "author": "Moriz Wahl", - "version": "1.13.2", + "version": "1.13.3", "license": "Apache-2.0", "private": false, "scripts": { diff --git a/backend/package.json b/backend/package.json index 45ae2897f..77d3b8064 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "gradido-backend", - "version": "1.13.2", + "version": "1.13.3", "description": "Gradido unified backend providing an API-Service for Gradido Transactions", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/backend", diff --git a/database/package.json b/database/package.json index f24bb4150..096c7a9bd 100644 --- a/database/package.json +++ b/database/package.json @@ -1,6 +1,6 @@ { "name": "gradido-database", - "version": "1.13.2", + "version": "1.13.3", "description": "Gradido Database Tool to execute database migrations", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/database", diff --git a/frontend/package.json b/frontend/package.json index ff3237b35..4e983d716 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "bootstrap-vue-gradido-wallet", - "version": "1.13.2", + "version": "1.13.3", "private": true, "scripts": { "start": "node run/server.js", diff --git a/package.json b/package.json index 95fdb714e..8e5fcfc70 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gradido", - "version": "1.13.2", + "version": "1.13.3", "description": "Gradido", "main": "index.js", "repository": "git@github.com:gradido/gradido.git",