Skip to content

Commit 5fc6fae

Browse files
gnyiriGergely Nyirimutambarafbolmstenyoganandaness
authored
feat: add configurable email templates (#1173)
Co-authored-by: Gergely Nyiri <gergely.nyiri@eli-alps.hu> Co-authored-by: Farai Mutambara <71100224+mutambaraf@users.noreply.github.com> Co-authored-by: Fredrik Bolmsten <fredrik.bolmsten@ess.eu> Co-authored-by: Yoganandan Pandiyan <132274772+yoganandaness@users.noreply.github.com>
1 parent 06bc94d commit 5fc6fae

83 files changed

Lines changed: 2169 additions & 307 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test-build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ jobs:
476476
EMAIL_AUTH_HOST: exchsmtp.stfc.ac.uk
477477
EMAIL_TEMPLATE_PATH: /config/emails/
478478
EMAIL_FOOTER_IMAGE_PATH: /config/logos/STFC-Logo-small.png
479+
SKIP_SMTP_EMAIL_SENDING: true
479480
EXTERNAL_AUTH_LOGIN_URL: http://localhost:9003/auth/Login.aspx
480481
EXTERNAL_AUTH_LOGOUT_URL: http://localhost:9003/auth/Login.aspx
481482
EXTERNAL_UOWS_API_URL: http://localhost:1080/users-service
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
DO
2+
$$
3+
BEGIN
4+
IF register_patch('CreateEmailTemplatesTable.sql', 'Gergely Nyiri', 'Create email templates table', '2025-07-15') THEN
5+
CREATE TABLE IF NOT EXISTS email_templates (
6+
email_template_id serial PRIMARY KEY,
7+
created_by INT NOT NULL REFERENCES users(user_id),
8+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
9+
name varchar(100) NOT NULL UNIQUE,
10+
description varchar(255) NOT NULL,
11+
use_template_file boolean DEFAULT FALSE,
12+
subject varchar(160),
13+
body text
14+
);
15+
END IF;
16+
END;
17+
$$
18+
LANGUAGE plpgsql;

apps/backend/package-lock.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/backend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
"@types/content-disposition": "^0.5.4",
9595
"@types/cors": "^2.8.13",
9696
"@types/cron": "^1.7.3",
97+
"@types/ejs": "^3.1.5",
9798
"@types/email-templates": "^8.0.4",
9899
"@types/express": "^4.17.13",
99100
"@types/express-jwt": "^6.0.4",
@@ -106,6 +107,7 @@
106107
"@types/node": "^22.13.10",
107108
"@types/pg": "^8.11.5",
108109
"@types/pg-large-object": "^2.0.7",
110+
"@types/pug": "^2.0.10",
109111
"@types/sanitize-html": "^2.6.2",
110112
"@types/simple-oauth2": "^4.1.1",
111113
"@types/sinon": "^9.0.11",

apps/backend/src/asyncJobs/jobs/checkInviteReminderJob.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import 'reflect-metadata';
21
import { faker } from '@faker-js/faker';
2+
import 'reflect-metadata';
33
import sinon from 'sinon';
44
import { container } from 'tsyringe';
55

66
import { Tokens } from '../../config/Tokens';
7-
import { EmailTemplateId } from '../../eventHandlers/email/essEmailHandler';
7+
import { EmailTemplateId } from '../../eventHandlers/email/emailTemplateId';
88
import { Invite } from '../../models/Invite';
99
import { RoleClaim } from '../../models/RoleClaim';
1010
import { SettingsId } from '../../models/Settings';

apps/backend/src/asyncJobs/jobs/checkInviteReminderJob.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const checkInviteReminder = async () => {
124124
try {
125125
await mailService.sendMail({
126126
content: {
127-
template_id: templateId,
127+
template: templateId,
128128
},
129129
substitution_data: {
130130
email: invite.email,

apps/backend/src/buildContext.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import PDFServices from './middlewares/factory/factoryServices';
77
import AdminMutations from './mutations/AdminMutations';
88
import CallMutations from './mutations/CallMutations';
99
import DataAccessUsersMutations from './mutations/DataAccessUsersMutations';
10+
import EmailTemplateMutations from './mutations/EmailTemplateMutations';
1011
import ExperimentMutations from './mutations/ExperimentMutation';
1112
import ExperimentSafetyPdfTemplateMutations from './mutations/ExperimentSafetyPdfTemplateMutations';
1213
import FapMutations from './mutations/FapMutations';
@@ -35,6 +36,7 @@ import WorkflowMutations from './mutations/WorkflowMutations';
3536
import AdminQueries from './queries/AdminQueries';
3637
import CallQueries from './queries/CallQueries';
3738
import DataAccessUsersQueries from './queries/DataAccessUsersQueries';
39+
import EmailTemplateQueries from './queries/EmailTemplateQueries';
3840
import EventLogQueries from './queries/EventLogQueries';
3941
import ExperimentQueries from './queries/ExperimentQueries';
4042
import ExperimentSafetyPdfTemplateQueries from './queries/ExperimentSafetyPdfTemplateQueries';
@@ -103,6 +105,7 @@ const context: BasicResolverContext = {
103105
settings: container.resolve(SettingsQueries),
104106
tag: container.resolve(TagQueries),
105107
experiment: container.resolve(ExperimentQueries),
108+
emailTemplate: container.resolve(EmailTemplateQueries),
106109
},
107110
mutations: {
108111
admin: container.resolve(AdminMutations),
@@ -135,6 +138,7 @@ const context: BasicResolverContext = {
135138
workflow: container.resolve(WorkflowMutations),
136139
tag: container.resolve(TagMutations),
137140
experiment: container.resolve(ExperimentMutations),
141+
emailTemplate: container.resolve(EmailTemplateMutations),
138142
},
139143
clients: {
140144
scheduler: async () => {

apps/backend/src/config/Tokens.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export const Tokens = {
99
DataAccessUsersDataSource: Symbol('DataAccessUsersDataSource'),
1010
DataAccessUsersAuthorization: Symbol('DataAccessUsersAuthorization'),
1111
EmailEventHandler: Symbol('EmailEventHandler'),
12+
EmailTemplateDataSource: Symbol('EmailTemplateDataSource'),
1213
EventBus: Symbol('EventBus'),
1314
EventLogsDataSource: Symbol('EventLogsDataSource'),
1415
FeedbackDataSource: Symbol('FeedbackDataSource'),

apps/backend/src/config/dependencyConfigDefault.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { PostgresAdminDataSourceWithAutoUpgrade } from '../datasources/postgres/
1414
import PostgresCallDataSource from '../datasources/postgres/CallDataSource';
1515
import PostgresCoProposerClaimDataSource from '../datasources/postgres/CoProposerClaimDataSource';
1616
import PostgresDataAccessUsersDataSource from '../datasources/postgres/DataAccessUsersDataSource';
17+
import PostgresEmailTemplateDataSource from '../datasources/postgres/EmailTemplateDataSource';
1718
import PostgresEventLogsDataSource from '../datasources/postgres/EventLogsDataSource';
1819
import PostgresExperimentDataSource from '../datasources/postgres/ExperimentDataSource';
1920
import PostgresExperimentSafetyPdfTemplateDataSource from '../datasources/postgres/ExperimentSafetyPdfTemplateDataSource';
@@ -122,6 +123,7 @@ mapClass(Tokens.WorkflowDataSource, PostgresWorkflowDataSource);
122123
mapClass(Tokens.StatusDataSource, PostgresStatusDataSource);
123124
mapClass(Tokens.ExperimentDataSource, PostgresExperimentDataSource);
124125
mapClass(Tokens.TagDataSource, PostgresTagDataSource);
126+
mapClass(Tokens.EmailTemplateDataSource, PostgresEmailTemplateDataSource);
125127

126128
mapClass(Tokens.UserAuthorization, OAuthAuthorization);
127129
mapClass(Tokens.ProposalAuthorization, ProposalAuthorization);

apps/backend/src/config/dependencyConfigE2E.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import PostgresAdminDataSource from '../datasources/postgres/AdminDataSource';
1010
import PostgresCallDataSource from '../datasources/postgres/CallDataSource';
1111
import PostgresCoProposerClaimDataSource from '../datasources/postgres/CoProposerClaimDataSource';
1212
import PostgresDataAccessUsersDataSource from '../datasources/postgres/DataAccessUsersDataSource';
13+
import PostgresEmailTemplateDataSource from '../datasources/postgres/EmailTemplateDataSource';
1314
import PostgresEventLogsDataSource from '../datasources/postgres/EventLogsDataSource';
1415
import PostgresExperimentDataSource from '../datasources/postgres/ExperimentDataSource';
1516
import PostgresExperimentSafetyPdfTemplateDataSource from '../datasources/postgres/ExperimentSafetyPdfTemplateDataSource';
@@ -112,6 +113,7 @@ mapClass(Tokens.StatusActionsLogsDataSource, StatusActionsLogsDataSource);
112113
mapClass(Tokens.WorkflowDataSource, PostgresWorkflowDataSource);
113114
mapClass(Tokens.StatusDataSource, PostgresStatusDataSource);
114115
mapClass(Tokens.TagDataSource, PostgresTagDataSource);
116+
mapClass(Tokens.EmailTemplateDataSource, PostgresEmailTemplateDataSource);
115117

116118
mapClass(Tokens.ExperimentDataSource, PostgresExperimentDataSource);
117119
mapClass(Tokens.UserAuthorization, OAuthAuthorization);

0 commit comments

Comments
 (0)