diff --git a/backend/src/emails/sendEmailVariants.test.ts b/backend/src/emails/sendEmailVariants.test.ts index ddbc387a1..7e499feb9 100644 --- a/backend/src/emails/sendEmailVariants.test.ts +++ b/backend/src/emails/sendEmailVariants.test.ts @@ -10,6 +10,7 @@ import { sendAccountMultiRegistrationEmail, sendContributionConfirmedEmail, sendContributionDeniedEmail, + sendContributionDeletedEmail, sendResetPasswordEmail, sendTransactionLinkRedeemedEmail, sendTransactionReceivedEmail, @@ -438,6 +439,84 @@ describe('sendEmailVariants', () => { }) }) + describe('sendContributionDeletedEmail', () => { + beforeAll(async () => { + result = await sendContributionDeletedEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslated).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'contributionDeleted', + locals: { + firstName: 'Peter', + lastName: 'Lustig', + locale: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + communityURL: CONFIG.COMMUNITY_URL, + }, + }) + }) + + it('has expected result', () => { + expect(result).toMatchObject({ + envelope: { + from: 'info@gradido.net', + to: ['peter@lustig.de'], + }, + message: expect.any(String), + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (do not answer) ', + attachments: [], + subject: 'Gradido: Your common good contribution was deleted', + html: expect.any(String), + text: expect.stringContaining('GRADIDO: YOUR COMMON GOOD CONTRIBUTION WAS DELETED'), + }), + }) + expect(result.originalMessage.html).toContain('') + expect(result.originalMessage.html).toContain('') + expect(result.originalMessage.html).toContain( + 'Gradido: Your common good contribution was deleted', + ) + expect(result.originalMessage.html).toContain( + '>Gradido: Your common good contribution was deleted', + ) + expect(result.originalMessage.html).toContain('Hello Peter Lustig') + expect(result.originalMessage.html).toContain( + 'Your public good contribution “My contribution.” was deleted by Bibi Bloxberg.', + ) + expect(result.originalMessage.html).toContain( + 'To see your common good contributions and related messages, go to the “Community” menu in your Gradido account and click on the “My contributions to the common good” tab!', + ) + expect(result.originalMessage.html).toContain( + `Link to your account: ${CONFIG.EMAIL_LINK_OVERVIEW}`, + ) + expect(result.originalMessage.html).toContain('Please do not reply to this email!') + expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team') + expect(result.originalMessage.html).toContain('—————') + expect(result.originalMessage.html).toContain( + '
Gradido-Akademie Logo

Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/', + ) + }) + }) + }) + describe('sendResetPasswordEmail', () => { beforeAll(async () => { result = await sendResetPasswordEmail({ diff --git a/backend/src/emails/sendEmailVariants.ts b/backend/src/emails/sendEmailVariants.ts index 681ee56af..4e3881829 100644 --- a/backend/src/emails/sendEmailVariants.ts +++ b/backend/src/emails/sendEmailVariants.ts @@ -103,6 +103,32 @@ export const sendContributionConfirmedEmail = (data: { }) } +export const sendContributionDeletedEmail = (data: { + firstName: string + lastName: string + email: string + language: string + senderFirstName: string + senderLastName: string + contributionMemo: string +}): Promise | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'contributionDeleted', + locals: { + firstName: data.firstName, + lastName: data.lastName, + locale: data.language, + senderFirstName: data.senderFirstName, + senderLastName: data.senderLastName, + contributionMemo: data.contributionMemo, + overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + communityURL: CONFIG.COMMUNITY_URL, + }, + }) +} + export const sendContributionDeniedEmail = (data: { firstName: string lastName: string diff --git a/backend/src/emails/templates/contributionDeleted/html.pug b/backend/src/emails/templates/contributionDeleted/html.pug new file mode 100644 index 000000000..d6b3ea207 --- /dev/null +++ b/backend/src/emails/templates/contributionDeleted/html.pug @@ -0,0 +1,16 @@ +doctype html +html(lang=locale) + head + title= t('emails.contributionDeleted.subject') + body + h1(style='margin-bottom: 24px;')= t('emails.contributionDeleted.subject') + #container.col + include ../hello.pug + p= t('emails.contributionDeleted.commonGoodContributionDeleted', { senderFirstName, senderLastName, contributionMemo }) + p= t('emails.contributionDeleted.toSeeContributionsAndMessages') + p + = t('emails.general.linkToYourAccount') + = " " + a(href=overviewURL) #{overviewURL} + p= t('emails.general.pleaseDoNotReply') + include ../greatingFormularImprint.pug diff --git a/backend/src/emails/templates/contributionDeleted/subject.pug b/backend/src/emails/templates/contributionDeleted/subject.pug new file mode 100644 index 000000000..024588472 --- /dev/null +++ b/backend/src/emails/templates/contributionDeleted/subject.pug @@ -0,0 +1 @@ += t('emails.contributionDeleted.subject') diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 6a1233224..77e86ad46 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -67,6 +67,7 @@ export class EventTransactionReceiveRedeem extends EventBasicTxX {} export class EventContributionCreate extends EventBasicCt {} export class EventAdminContributionCreate extends EventBasicCt {} export class EventAdminContributionDelete extends EventBasicCt {} +export class EventAdminContributionDeny extends EventBasicCt {} export class EventAdminContributionUpdate extends EventBasicCt {} export class EventUserCreateContributionMessage extends EventBasicCtMsg {} export class EventAdminCreateContributionMessage extends EventBasicCtMsg {} @@ -298,6 +299,13 @@ export class Event { return this } + public setEventAdminContributionDeny(ev: EventAdminContributionDeny): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.ADMIN_CONTRIBUTION_DENY + + return this + } + public setEventAdminContributionUpdate(ev: EventAdminContributionUpdate): Event { this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) this.type = EventProtocolType.ADMIN_CONTRIBUTION_UPDATE diff --git a/backend/src/event/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts index b7c2f0151..ccd15d238 100644 --- a/backend/src/event/EventProtocolType.ts +++ b/backend/src/event/EventProtocolType.ts @@ -35,6 +35,7 @@ export enum EventProtocolType { CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE', ADMIN_CONTRIBUTION_CREATE = 'ADMIN_CONTRIBUTION_CREATE', ADMIN_CONTRIBUTION_DELETE = 'ADMIN_CONTRIBUTION_DELETE', + ADMIN_CONTRIBUTION_DENY = 'ADMIN_CONTRIBUTION_DENY', ADMIN_CONTRIBUTION_UPDATE = 'ADMIN_CONTRIBUTION_UPDATE', USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE', ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE', diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index d48502c69..03ad002ad 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -22,11 +22,7 @@ import { listContributions, listUnconfirmedContributions, } from '@/seeds/graphql/queries' -import { - // sendAccountActivationEmail, - sendContributionConfirmedEmail, - // sendContributionRejectedEmail, -} from '@/emails/sendEmailVariants' +import { sendContributionConfirmedEmail } from '@/emails/sendEmailVariants' import { cleanDB, resetToken, @@ -47,7 +43,6 @@ import { EventProtocolType } from '@/event/EventProtocolType' import { logger, i18n as localization } from '@test/testSetup' import { UserInputError } from 'apollo-server-express' -// mock account activation email to avoid console spam // mock account activation email to avoid console spam jest.mock('@/emails/sendEmailVariants', () => { const originalModule = jest.requireActual('@/emails/sendEmailVariants') diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 205d7086e..c46a49555 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -44,12 +44,14 @@ import { EventContributionConfirm, EventAdminContributionCreate, EventAdminContributionDelete, + EventAdminContributionDeny, EventAdminContributionUpdate, } from '@/event/Event' import { writeEvent } from '@/event/EventProtocolEmitter' import { calculateDecay } from '@/util/decay' import { sendContributionConfirmedEmail, + sendContributionDeletedEmail, sendContributionDeniedEmail, } from '@/emails/sendEmailVariants' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' @@ -548,7 +550,7 @@ export class ContributionResolver { eventAdminContributionDelete.amount = contribution.amount eventAdminContributionDelete.contributionId = contribution.id await writeEvent(event.setEventAdminContributionDelete(eventAdminContributionDelete)) - sendContributionDeniedEmail({ + sendContributionDeletedEmail({ firstName: user.firstName, lastName: user.lastName, email: user.emailContact.email, @@ -764,6 +766,13 @@ export class ContributionResolver { contributionToUpdate.deniedAt = new Date() const res = await contributionToUpdate.save() + const event = new Event() + const eventAdminContributionDeny = new EventAdminContributionDeny() + eventAdminContributionDeny.userId = contributionToUpdate.userId + eventAdminContributionDeny.amount = contributionToUpdate.amount + eventAdminContributionDeny.contributionId = contributionToUpdate.id + await writeEvent(event.setEventAdminContributionDeny(eventAdminContributionDeny)) + sendContributionDeniedEmail({ firstName: user.firstName, lastName: user.lastName, diff --git a/backend/src/locales/de.json b/backend/src/locales/de.json index 38b53508b..304ae2adc 100644 --- a/backend/src/locales/de.json +++ b/backend/src/locales/de.json @@ -23,8 +23,13 @@ "commonGoodContributionConfirmed": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde soeben von {senderFirstName} {senderLastName} bestätigt und in deinem Gradido-Konto gutgeschrieben.", "subject": "Gradido: Dein Gemeinwohl-Beitrag wurde bestätigt" }, - "contributionRejected": { - "commonGoodContributionRejected": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde von {senderFirstName} {senderLastName} abgelehnt.", + "contributionDeleted": { + "commonGoodContributionDeleted": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde von {senderFirstName} {senderLastName} gelöscht.", + "subject": "Gradido: Dein Gemeinwohl-Beitrag wurde gelöscht", + "toSeeContributionsAndMessages": "Um deine Gemeinwohl-Beiträge und dazugehörige Nachrichten zu sehen, gehe in deinem Gradido-Konto ins Menü „Gemeinschaft“ auf den Tab „Meine Beiträge zum Gemeinwohl“!" + }, + "contributionDenied": { + "commonGoodContributionDenied": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde von {senderFirstName} {senderLastName} abgelehnt.", "subject": "Gradido: Dein Gemeinwohl-Beitrag wurde abgelehnt", "toSeeContributionsAndMessages": "Um deine Gemeinwohl-Beiträge und dazugehörige Nachrichten zu sehen, gehe in deinem Gradido-Konto ins Menü „Gemeinschaft“ auf den Tab „Meine Beiträge zum Gemeinwohl“!" }, diff --git a/backend/src/locales/en.json b/backend/src/locales/en.json index 5cde70d26..bdc92b2cf 100644 --- a/backend/src/locales/en.json +++ b/backend/src/locales/en.json @@ -23,6 +23,11 @@ "commonGoodContributionConfirmed": "Your public good contribution “{contributionMemo}” has just been confirmed by {senderFirstName} {senderLastName} and credited to your Gradido account.", "subject": "Gradido: Your contribution to the common good was confirmed" }, + "contributionDeleted": { + "commonGoodContributionDeleted": "Your public good contribution “{contributionMemo}” was deleted by {senderFirstName} {senderLastName}.", + "subject": "Gradido: Your common good contribution was deleted", + "toSeeContributionsAndMessages": "To see your common good contributions and related messages, go to the “Community” menu in your Gradido account and click on the “My contributions to the common good” tab!" + }, "contributionDenied": { "commonGoodContributionDenied": "Your public good contribution “{contributionMemo}” was rejected by {senderFirstName} {senderLastName}.", "subject": "Gradido: Your common good contribution was rejected",