From fa9d0e5790a6d7ba9d4490bc016e0f9afde49ec8 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 16:15:53 +0100 Subject: [PATCH 01/23] Added basic jest packages and scripts ref #4 --- package.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a872e2b..3c3c920 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,10 @@ "licenses:export": "license-exporter --markdown", "release": "release-it --only-version", "translations:sort": "node ./scripts/sort_translations.js", - "test:generate_env": "ts-node ./scripts/create_testenv.ts" + "test": "jest", + "test:generate_env": "ts-node ./scripts/create_testenv.ts", + "test:ci": "npm run test:generate_env && npm run test:ci:run", + "test:ci:run": "start-server-and-test dev http://localhost:4010/api/docs/openapi.json test" }, "repository": { "type": "git", @@ -58,13 +61,16 @@ "devDependencies": { "@odit/license-exporter": "^0.0.10", "@types/express": "^4.17.11", + "@types/jest": "^26.0.20", "@types/node": "^14.14.22", "@types/nodemailer": "^6.4.0", "cp-cli": "^2.0.0", + "jest": "^26.6.3", "nodemon": "^2.0.7", "release-it": "^14.2.2", "rimraf": "^3.0.2", "start-server-and-test": "^1.12.0", + "ts-jest": "^26.5.2", "ts-node": "^9.1.1", "typescript": "^4.1.3" }, @@ -81,4 +87,4 @@ "publish": false } } -} \ No newline at end of file +} -- 2.47.2 From ec939e6c1142e825cdb21555e03d9e026e7cdf3c Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 16:17:05 +0100 Subject: [PATCH 02/23] Added jest config and first tests --- jest.config.js | 4 ++++ src/tests/api_docs.spec.ts | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 jest.config.js create mode 100644 src/tests/api_docs.spec.ts diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..91a2d2c --- /dev/null +++ b/jest.config.js @@ -0,0 +1,4 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; \ No newline at end of file diff --git a/src/tests/api_docs.spec.ts b/src/tests/api_docs.spec.ts new file mode 100644 index 0000000..994a4e8 --- /dev/null +++ b/src/tests/api_docs.spec.ts @@ -0,0 +1,34 @@ +import axios from 'axios'; +import { config } from '../config'; +const base = "http://localhost:" + config.internal_port + +describe('GET /api/docs/openapi.json', () => { + it('OpenAPI Spec is availdable 200', async () => { + const res = await axios.get(base + '/api/docs/openapi.json'); + expect(res.status).toEqual(200); + }); +}); +describe('GET /api/docs/swagger.json', () => { + it('OpenAPI Spec is availdable 200', async () => { + const res = await axios.get(base + '/api/docs/swagger.json'); + expect(res.status).toEqual(200); + }); +}); +describe('GET /api/docs/swaggerui', () => { + it('swaggerui is availdable 200', async () => { + const res = await axios.get(base + '/api/docs/swaggerui'); + expect(res.status).toEqual(200); + }); +}); +describe('GET /api/docs/redoc', () => { + it('redoc is availdable 200', async () => { + const res = await axios.get(base + '/api/docs/redoc'); + expect(res.status).toEqual(200); + }); +}); +describe('GET /api/docs/rapidoc', () => { + it('rapidoc is availdable 200', async () => { + const res = await axios.get(base + '/api/docs/rapidoc'); + expect(res.status).toEqual(200); + }); +}); -- 2.47.2 From f6a53cc3e47308e84cde13640cb3f614642fd4ca Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 16:21:11 +0100 Subject: [PATCH 03/23] Updated api doc tests to listen on the right endpoint ref #4 --- package.json | 3 ++- src/tests/api_docs.spec.ts | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 3c3c920..89e659a 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "test": "jest", "test:generate_env": "ts-node ./scripts/create_testenv.ts", "test:ci": "npm run test:generate_env && npm run test:ci:run", - "test:ci:run": "start-server-and-test dev http://localhost:4010/api/docs/openapi.json test" + "test:ci:run": "start-server-and-test dev http://localhost:4010/docs/openapi.json test" }, "repository": { "type": "git", @@ -64,6 +64,7 @@ "@types/jest": "^26.0.20", "@types/node": "^14.14.22", "@types/nodemailer": "^6.4.0", + "axios": "^0.21.1", "cp-cli": "^2.0.0", "jest": "^26.6.3", "nodemon": "^2.0.7", diff --git a/src/tests/api_docs.spec.ts b/src/tests/api_docs.spec.ts index 994a4e8..9e9444a 100644 --- a/src/tests/api_docs.spec.ts +++ b/src/tests/api_docs.spec.ts @@ -2,33 +2,33 @@ import axios from 'axios'; import { config } from '../config'; const base = "http://localhost:" + config.internal_port -describe('GET /api/docs/openapi.json', () => { +describe('GET /docs/openapi.json', () => { it('OpenAPI Spec is availdable 200', async () => { - const res = await axios.get(base + '/api/docs/openapi.json'); + const res = await axios.get(base + '/docs/openapi.json'); expect(res.status).toEqual(200); }); }); -describe('GET /api/docs/swagger.json', () => { +describe('GET /docs/swagger.json', () => { it('OpenAPI Spec is availdable 200', async () => { - const res = await axios.get(base + '/api/docs/swagger.json'); + const res = await axios.get(base + '/docs/swagger.json'); expect(res.status).toEqual(200); }); }); -describe('GET /api/docs/swaggerui', () => { +describe('GET /docs/swaggerui', () => { it('swaggerui is availdable 200', async () => { - const res = await axios.get(base + '/api/docs/swaggerui'); + const res = await axios.get(base + '/docs/swaggerui'); expect(res.status).toEqual(200); }); }); -describe('GET /api/docs/redoc', () => { +describe('GET /docs/redoc', () => { it('redoc is availdable 200', async () => { - const res = await axios.get(base + '/api/docs/redoc'); + const res = await axios.get(base + '/docs/redoc'); expect(res.status).toEqual(200); }); }); -describe('GET /api/docs/rapidoc', () => { +describe('GET /docs/rapidoc', () => { it('rapidoc is availdable 200', async () => { - const res = await axios.get(base + '/api/docs/rapidoc'); + const res = await axios.get(base + '/docs/rapidoc'); expect(res.status).toEqual(200); }); }); -- 2.47.2 From 38cffc20490fe10b4e4bc4d88a8377562cd1545a Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 16:27:56 +0100 Subject: [PATCH 04/23] Added test watch mode ref #4 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 89e659a..5c44558 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "release": "release-it --only-version", "translations:sort": "node ./scripts/sort_translations.js", "test": "jest", + "test:watch": "jest --watchAll", "test:generate_env": "ts-node ./scripts/create_testenv.ts", "test:ci": "npm run test:generate_env && npm run test:ci:run", "test:ci:run": "start-server-and-test dev http://localhost:4010/docs/openapi.json test" @@ -88,4 +89,4 @@ "publish": false } } -} +} \ No newline at end of file -- 2.47.2 From bf9652dcfed3667f9d2e8cfd933963935a621a88 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 16:31:07 +0100 Subject: [PATCH 05/23] Added test mail tests ref #4 --- src/tests/test_mail.spec.ts | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/tests/test_mail.spec.ts diff --git a/src/tests/test_mail.spec.ts b/src/tests/test_mail.spec.ts new file mode 100644 index 0000000..ff3dac6 --- /dev/null +++ b/src/tests/test_mail.spec.ts @@ -0,0 +1,44 @@ +import axios from 'axios'; +import { config } from '../config'; +const base = "http://localhost:" + config.internal_port + +const axios_config = { + validateStatus: undefined +}; + +describe('POST /test without auth', () => { + it('Post without auth should return 401', async () => { + const res = await axios.post(base + '/test', null, axios_config); + expect(res.status).toEqual(401); + }); +}); + +describe('POST /test with auth', () => { + it('Post with auth and no locale should return 200', async () => { + const res = await axios.post(base + '/test?key=' + config.api_key, null, axios_config); + expect(res.status).toEqual(200); + expect(res.data).toEqual({ + success: true, + message: "Sent!", + locale: "en" + }) + }); + it('Post with auth and locale=en should return 200', async () => { + const res = await axios.post(base + '/test?locale=en&key=' + config.api_key, null, axios_config); + expect(res.status).toEqual(200); + expect(res.data).toEqual({ + success: true, + message: "Sent!", + locale: "en" + }) + }); + it('Post with auth and locale=de should return 200', async () => { + const res = await axios.post(base + '/test?locale=de&key=' + config.api_key, null, axios_config); + expect(res.status).toEqual(200); + expect(res.data).toEqual({ + success: true, + message: "Sent!", + locale: "de" + }) + }); +}); \ No newline at end of file -- 2.47.2 From 46242509637e05e6b258b406d0a2a76e5db9ca03 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 16:37:52 +0100 Subject: [PATCH 06/23] Added reset mail valid tests ref #4 --- src/tests/pw_reset_mail.spec.ts | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/tests/pw_reset_mail.spec.ts diff --git a/src/tests/pw_reset_mail.spec.ts b/src/tests/pw_reset_mail.spec.ts new file mode 100644 index 0000000..d43f3a3 --- /dev/null +++ b/src/tests/pw_reset_mail.spec.ts @@ -0,0 +1,72 @@ +import axios from 'axios'; +import { config } from '../config'; +const base = "http://localhost:" + config.internal_port + +const axios_config = { + validateStatus: undefined +}; + +describe('POST /reset without auth', () => { + it('Post without auth should return 401', async () => { + const res = await axios.post(base + '/reset', null, axios_config); + expect(res.status).toEqual(401); + }); +}); + +describe('POST /reset with auth but wrong body', () => { + it('Post with auth but no body should return 400', async () => { + const res = await axios.post(base + '/reset?key=' + config.api_key, null, axios_config); + expect(res.status).toEqual(400); + }); + it('Post with auth but no mail should return 400', async () => { + const res = await axios.post(base + '/reset?key=' + config.api_key, { resetKey: "test" }, axios_config); + expect(res.status).toEqual(400); + }); + it('Post with auth but no reset key should return 400', async () => { + const res = await axios.post(base + '/reset?key=' + config.api_key, { address: "test@dev.lauf-fuer-kaya.de" }, axios_config); + expect(res.status).toEqual(400); + }); + it('Post with auth but invalid mail should return 400', async () => { + const res = await axios.post(base + '/reset?key=' + config.api_key, { resetKey: "test", address: "testdev.l.de" }, axios_config); + expect(res.status).toEqual(400); + }); +}); + +describe('POST /reset with auth and vaild body', () => { + it('Post with auth, body and no locale should return 200', async () => { + const res = await axios.post(base + '/reset?key=' + config.api_key, { + resetKey: "test", + address: "test@dev.lauf-fuer-kaya.de" + }, axios_config); + expect(res.status).toEqual(200); + expect(res.data).toEqual({ + success: true, + message: "Sent!", + locale: "en" + }) + }); + it('Post with auth, body and locale=en should return 200', async () => { + const res = await axios.post(base + '/reset?locale=en&key=' + config.api_key, { + resetKey: "test", + address: "test@dev.lauf-fuer-kaya.de" + }, axios_config); + expect(res.status).toEqual(200); + expect(res.data).toEqual({ + success: true, + message: "Sent!", + locale: "en" + }) + }); + it('Post with auth, body and locale=de should return 200', async () => { + const res = await axios.post(base + '/reset?locale=de&key=' + config.api_key, { + resetKey: "test", + address: "test@dev.lauf-fuer-kaya.de" + }, axios_config); + expect(res.status).toEqual(200); + expect(res.data).toEqual({ + success: true, + message: "Sent!", + locale: "de" + }) + }); +}); \ No newline at end of file -- 2.47.2 From 3501a4bef1b6ec73ea0be643e1b4e95ee9874ff9 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 16:39:54 +0100 Subject: [PATCH 07/23] Added drone pipeline for automagic tests ref #4 --- .drone.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.drone.yml b/.drone.yml index 9a2a300..fb4006f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,3 +1,23 @@ +--- +kind: pipeline +name: tests:node_latest +clone: + disable: true +steps: + - name: checkout pr + image: alpine/git + commands: + - git clone $DRONE_REMOTE_URL . + - git checkout $DRONE_SOURCE_BRANCH + - name: run tests + image: node:latest + commands: + - yarn + - yarn test:ci +trigger: + event: + - pull_request + --- kind: pipeline type: docker -- 2.47.2 From b3f61f51e367c10e102e1d53e6c41c8280f6c0c3 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 17:35:21 +0100 Subject: [PATCH 08/23] Added basic welcome mails ref #2 --- src/locales/en.json | 40 +-- src/templates/welcome_runner.html | 397 ++++++++++++++++++++++++++++++ src/templates/welcome_runner.txt | 18 ++ 3 files changed, 440 insertions(+), 15 deletions(-) create mode 100644 src/templates/welcome_runner.html create mode 100644 src/templates/welcome_runner.txt diff --git a/src/locales/en.json b/src/locales/en.json index 7f56e85..4829060 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1,16 +1,26 @@ { - "a-password-reset-for-your-account-got-requested": "A password reset for your account got requested.", - "all-rights-reserved": "All rights reserved.", - "if-you-didnt-request-the-reset-please-ignore-this-mail": "If you didn't request the reset please ignore this mail.", - "imprint": "Imprint", - "lfk-mail-test": "{{copyright_owner}} - Mail test", - "lfk-password-reset": "{{copyright_owner}} - Password reset", - "password-reset": "Password reset", - "privacy": "Privacy", - "reset-password": "Reset password", - "test-mail": "Test mail", - "this-is-a-test-mail-triggered-by-an-admin-in-the-lfk-backend": "This is a test mail triggered by an admin in the LfK! backend.", - "this-mail-was-sent-to-recipient_mail-because-someone-request-a-mail-test-for-this-mail-address": "This mail was sent to you because someone request a mail test for this mail address.", - "this-mail-was-sent-to-you-because-someone-request-a-password-reset-for-a-account-linked-to-the-mail-address": "This mail was sent to you because someone request a password reset for a account linked to the mail address.", - "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Your password won't be changed until you click the reset link below and set a new one." -} \ No newline at end of file + "a-password-reset-for-your-account-got-requested": "A password reset for your account got requested.", + "all-rights-reserved": "All rights reserved.", + "if-you-didnt-request-the-reset-please-ignore-this-mail": "If you didn't request the reset please ignore this mail.", + "imprint": "Imprint", + "lfk-mail-test": "{{copyright_owner}} - Mail test", + "lfk-password-reset": "{{copyright_owner}} - Password reset", + "password-reset": "Password reset", + "privacy": "Privacy", + "reset-password": "Reset password", + "test-mail": "Test mail", + "this-is-a-test-mail-triggered-by-an-admin-in-the-lfk-backend": "This is a test mail triggered by an admin in the LfK! backend.", + "this-mail-was-sent-to-recipient_mail-because-someone-request-a-mail-test-for-this-mail-address": "This mail was sent to you because someone request a mail test for this mail address.", + "this-mail-was-sent-to-you-because-someone-request-a-password-reset-for-a-account-linked-to-the-mail-address": "This mail was sent to you because someone request a password reset for a account linked to the mail address.", + "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Your password won't be changed until you click the reset link below and set a new one.", + "event_name-registration": "{{event_name}} Registration", + "welcome": "Welcome", + "thanks-for-registering-and-welcome-to-the-event_name": "Thanks for registering and welcome to the {{event_name}}!", + "we-successfully-processed-your-registration": "We successfully processed your registration.", + "the-only-thing-you-have-to-do-now-is-to-bring-your-registration-code-with-you": "The only thing you have to do now is to bring your registration code with you.", + "you-can-view-your-registration-code-lap-times-and-much-more-by-visiting-our-selfservice": "You can view your registration code, lap times and much more by visiting our selfservice:", + "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website": "If you ever loose the link you can request a new one by visiting our website:", + "view-my-data": "View my data", + "this-mail-was-sent-to-you-because-someone-used-your-mail-address-to-register-themselfes-for-the-event_name": "This mail was sent to you, because someone used your mail address to register themselfes for the {{event_name}}", + "if-you-didnt-register-yourself-you-should-contact-us-to-get-your-data-removed-from-our-systems": "If you didn't register yourself you should contact us to get your data removed from our systems:" +} diff --git a/src/templates/welcome_runner.html b/src/templates/welcome_runner.html new file mode 100644 index 0000000..c0acbdf --- /dev/null +++ b/src/templates/welcome_runner.html @@ -0,0 +1,397 @@ + + + + + {{__ "event_name-registration"}} + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ {{__ "event_name-registration"}} +
+ + + + +
+ + \ No newline at end of file diff --git a/src/templates/welcome_runner.txt b/src/templates/welcome_runner.txt new file mode 100644 index 0000000..2d78482 --- /dev/null +++ b/src/templates/welcome_runner.txt @@ -0,0 +1,18 @@ +{{event_name}} Registration + +Thanks for registering and welcome to the {{event_name}}! +We successfully processed your registration. + +The only thing you have to do now is to bring your registration code with you. +You can view your registration code, lap times and much more by visiting our selfservice. + +This is your private selfservice link: +{{selfservice_url}} + +If you ever loose the link you can request a new one by visiting our website: {{forgot_link}} + + +Copyright © {{copyright_owner}}. {{__ "all-rights-reserved"}}. +{{__ "imprint"}}: {{link_imprint}} | {{__ "privacy"}}: {{link_privacy}} +This mail was sent to you, because someone used your mail address to register themselfes for the {{event_name}}. +If you didn't register yourself you should contact us at {{contact_mail}} to get your data removed from our systems. \ No newline at end of file -- 2.47.2 From a62f9c683dd09303af47e2ed4e8df60bb2df3121 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 17:35:41 +0100 Subject: [PATCH 09/23] Added eventname to config ref #2 --- src/config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index 06d882d..e1eaca6 100644 --- a/src/config.ts +++ b/src/config.ts @@ -15,7 +15,8 @@ export const config = { mail_from: process.env.MAIL_FROM, privacy_url: process.env.PRIVACY_URL || "/privacy", imprint_url: process.env.IMPRINT_URL || "/imprint", - copyright_owner: process.env.COPYRIGHT_OWNER || "LfK!" + copyright_owner: process.env.COPYRIGHT_OWNER || "LfK!", + event_name: process.env.EVENT_NAME || "Testing 4 Kaya!" } let errors = 0 if (typeof config.internal_port !== "number") { -- 2.47.2 From 4994cb0489b168ecc9f18103fdea5e578bb9ef74 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 17:54:12 +0100 Subject: [PATCH 10/23] Added all missing config vars/interpolations ref #2 --- src/Mailer.ts | 59 +++++++++++++++++++++++++++---- src/config.ts | 3 +- src/templates/welcome_runner.html | 4 +-- src/templates/welcome_runner.txt | 2 +- 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/Mailer.ts b/src/Mailer.ts index 93597d6..d2752f8 100644 --- a/src/Mailer.ts +++ b/src/Mailer.ts @@ -16,7 +16,7 @@ import { MailServerConfigError } from './errors/MailErrors'; */ export class Mailer { private transport: Mail; - private static interpolations = { copyright_owner: config.copyright_owner } + private static interpolations = { copyright_owner: config.copyright_owner, event_name: config.event_name, contact_mail: config.contact_mail } /** * Main constructor. @@ -69,11 +69,18 @@ export class Mailer { public async sendResetMail(to_address: string, token: string, locale: string = "en") { await i18next.changeLanguage(locale); - const reset_link = `${config.app_url}/reset/${(Buffer.from(token)).toString("base64")}` + const replacements = { + recipient_mail: to_address, + copyright_owner: config.copyright_owner, + link_imprint: `${config.app_url}/imprint`, + link_privacy: `${config.app_url}/privacy`, + reset_link: `${config.app_url}/reset/${(Buffer.from(token)).toString("base64")}` + } + const template_html = Handlebars.compile(fs.readFileSync(__dirname + '/templates/pw-reset.html', { encoding: 'utf8' })); const template_txt = Handlebars.compile(fs.readFileSync(__dirname + '/templates/pw-reset.txt', { encoding: 'utf8' })); - const body_html = template_html({ recipient_mail: to_address, copyright_owner: config.copyright_owner, link_imprint: `${config.app_url}/imprint`, link_privacy: `${config.app_url}/privacy`, reset_link }); - const body_txt = template_txt({ recipient_mail: to_address, copyright_owner: config.copyright_owner, link_imprint: `${config.app_url}/imprint`, link_privacy: `${config.app_url}/privacy`, reset_link }); + const body_html = template_html(replacements); + const body_txt = template_txt(replacements); const mail: MailOptions = { to: to_address, @@ -91,13 +98,18 @@ export class Mailer { public async sendTestMail(locale: string = "en") { await i18next.changeLanguage(locale); const to_address: string = config.mail_from; + const replacements = { + recipient_mail: to_address, + copyright_owner: config.copyright_owner, + link_imprint: `${config.app_url}/imprint`, + link_privacy: `${config.app_url}/privacy` + } const template_html = Handlebars.compile(fs.readFileSync(__dirname + '/templates/test.html', { encoding: 'utf8' })); const template_txt = Handlebars.compile(fs.readFileSync(__dirname + '/templates/test.txt', { encoding: 'utf8' })); - const body_html = template_html({ recipient_mail: to_address, copyright_owner: config.copyright_owner, link_imprint: `${config.app_url}/imprint`, link_privacy: `${config.app_url}/privacy` }); - const body_txt = template_txt({ recipient_mail: to_address, copyright_owner: config.copyright_owner, link_imprint: `${config.app_url}/imprint`, link_privacy: `${config.app_url}/privacy` }); + const body_html = template_html(replacements); + const body_txt = template_txt(replacements); - fs.writeFileSync("./test.tmp", body_txt); const mail: MailOptions = { to: to_address, subject: i18next.t("test-mail", Mailer.interpolations).toString(), @@ -107,6 +119,39 @@ export class Mailer { await this.sendMail(mail); } + /** + * Function for sending a reset mail from the reset mail template. + * @param to_address The address the mail will be sent to. Should always get pulled from a user object. + * @param token The requested password reset token - will be combined with the app_url to generate a password reset link. + */ + public async sendWelcomeMail(to_address: string, token: string, locale: string = "en") { + await i18next.changeLanguage(locale); + + const replacements = { + recipient_mail: to_address, + copyright_owner: config.copyright_owner, + link_imprint: `${config.app_url}/imprint`, + link_privacy: `${config.app_url}/privacy`, + selfservice_link: `${config.app_url}/selfservice/profile/${token}`, + forgot_link: `${config.app_url}/selfservice`, + contact_mail: config.contact_mail, + event_name: config.event_name + } + + const template_html = Handlebars.compile(fs.readFileSync(__dirname + '/templates/welcome_runner.html', { encoding: 'utf8' })); + const template_txt = Handlebars.compile(fs.readFileSync(__dirname + '/templates/welcome_runner.txt', { encoding: 'utf8' })); + const body_html = template_html(replacements); + const body_txt = template_txt(replacements); + + const mail: MailOptions = { + to: to_address, + subject: i18next.t("event_name-registration", Mailer.interpolations).toString(), + text: body_txt, + html: body_html + }; + await this.sendMail(mail); + } + /** * Wrapper function for sending a mail via this object's transporter. * @param mail MailOptions object containing the diff --git a/src/config.ts b/src/config.ts index e1eaca6..2464181 100644 --- a/src/config.ts +++ b/src/config.ts @@ -16,7 +16,8 @@ export const config = { privacy_url: process.env.PRIVACY_URL || "/privacy", imprint_url: process.env.IMPRINT_URL || "/imprint", copyright_owner: process.env.COPYRIGHT_OWNER || "LfK!", - event_name: process.env.EVENT_NAME || "Testing 4 Kaya!" + event_name: process.env.EVENT_NAME || "Testing 4 Kaya!", + contact_mail: process.env.CONTACT_MAIL || process.env.MAIL_FROM, } let errors = 0 if (typeof config.internal_port !== "number") { diff --git a/src/templates/welcome_runner.html b/src/templates/welcome_runner.html index c0acbdf..cf35fa8 100644 --- a/src/templates/welcome_runner.html +++ b/src/templates/welcome_runner.html @@ -322,7 +322,7 @@
- {{__ "view-my-data"}} + {{__ "view-my-data"}}
@@ -331,7 +331,7 @@ -

Link: {{selfservice_url}}
+

Link: {{selfservice_link}}
{{__ "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website"}} {{forgot_link}}

diff --git a/src/templates/welcome_runner.txt b/src/templates/welcome_runner.txt index 2d78482..a77b00b 100644 --- a/src/templates/welcome_runner.txt +++ b/src/templates/welcome_runner.txt @@ -7,7 +7,7 @@ The only thing you have to do now is to bring your registration code with you. You can view your registration code, lap times and much more by visiting our selfservice. This is your private selfservice link: -{{selfservice_url}} +{{selfservice_link}} If you ever loose the link you can request a new one by visiting our website: {{forgot_link}} -- 2.47.2 From f11137e0c2140cd226d418c284387bc6a9532030 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 16:55:09 +0000 Subject: [PATCH 11/23] =?UTF-8?q?=F0=9F=93=96New=20license=20file=20versio?= =?UTF-8?q?n=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- licenses.md | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/licenses.md b/licenses.md index 0afda7a..30fc94b 100644 --- a/licenses.md +++ b/licenses.md @@ -428,6 +428,35 @@ OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE +# @types/jest +**Author**: undefined +**Repo**: https://github.com/DefinitelyTyped/DefinitelyTyped.git +**License**: MIT +**Description**: TypeScript definitions for Jest +## License Text + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + # @types/node **Author**: undefined **Repo**: https://github.com/DefinitelyTyped/DefinitelyTyped.git @@ -486,6 +515,33 @@ OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE +# axios +**Author**: Matt Zabriskie +**Repo**: https://github.com/axios/axios.git +**License**: MIT +**Description**: Promise based HTTP client for the browser and node.js +## License Text +Copyright (c) 2014-present Matt Zabriskie + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + # cp-cli **Author**: undefined **Repo**: git+https://github.com/screendriver/cp-cli.git @@ -515,6 +571,35 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# jest +**Author**: undefined +**Repo**: https://github.com/facebook/jest +**License**: MIT +**Description**: Delightful JavaScript Testing. +## License Text +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + # nodemon **Author**: [object Object] **Repo**: https://github.com/remy/nodemon.git @@ -604,6 +689,35 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ## License Text +# ts-jest +**Author**: Kulshekhar Kabra (https://github.com/kulshekhar) +**Repo**: git+https://github.com/kulshekhar/ts-jest.git +**License**: MIT +**Description**: A preprocessor with source maps support to help use TypeScript with Jest +## License Text +MIT License + +Copyright (c) 2016-2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + # ts-node **Author**: [object Object] **Repo**: git://github.com/TypeStrong/ts-node.git -- 2.47.2 From e2237d34d39ccaef5600a6eb5d4c555531cb5941 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 18:02:53 +0100 Subject: [PATCH 12/23] Added german translations ref #2 --- src/locales/de.json | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/locales/de.json b/src/locales/de.json index 5e980de..db2e60b 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1,16 +1,26 @@ { - "a-password-reset-for-your-account-got-requested": "Ein Passwort Reset wurde für dein Konto beantragt.", - "all-rights-reserved": "Alle Rechte vorbehalten", - "if-you-didnt-request-the-reset-please-ignore-this-mail": "Solltest du den Reset nicht beantragt haben kannst du diese Mail einfach ignorieren.", - "imprint": "Impressum", - "lfk-mail-test": "{{copyright_owner}} - Mail test", - "lfk-password-reset": "{{copyright_owner}} - Passwort zurücksetzen", - "password-reset": "Passwort zurücksetzen", - "privacy": "Datenschutz", - "reset-password": "Passwort zurücksetzen", - "test-mail": "Test mail", - "this-is-a-test-mail-triggered-by-an-admin-in-the-lfk-backend": "Das ist eine Testmail, die von einem Admin im LfK! backend erzeugt wurde.", - "this-mail-was-sent-to-recipient_mail-because-someone-request-a-mail-test-for-this-mail-address": "Du bekommst diese Mail, weil jemand eine Testmail für deine Mail-Adresse angefragt hat.", - "this-mail-was-sent-to-you-because-someone-request-a-password-reset-for-a-account-linked-to-the-mail-address": "Du bekommst diese E-Mail, weil jemand einen Passwort-Reset für deinen Account beantragt hat.", - "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Dein Passwort wird erst zurückgesetzt, wenn du den Reset-Link öffnest und ein neues Passwort setzt." -} \ No newline at end of file + "a-password-reset-for-your-account-got-requested": "Ein Passwort Reset wurde für dein Konto beantragt.", + "all-rights-reserved": "Alle Rechte vorbehalten", + "if-you-didnt-request-the-reset-please-ignore-this-mail": "Solltest du den Reset nicht beantragt haben kannst du diese Mail einfach ignorieren.", + "imprint": "Impressum", + "lfk-mail-test": "{{copyright_owner}} - Mail test", + "lfk-password-reset": "{{copyright_owner}} - Passwort zurücksetzen", + "password-reset": "Passwort zurücksetzen", + "privacy": "Datenschutz", + "reset-password": "Passwort zurücksetzen", + "test-mail": "Test mail", + "this-is-a-test-mail-triggered-by-an-admin-in-the-lfk-backend": "Das ist eine Testmail, die von einem Admin im LfK! backend erzeugt wurde.", + "this-mail-was-sent-to-recipient_mail-because-someone-request-a-mail-test-for-this-mail-address": "Du bekommst diese Mail, weil jemand eine Testmail für deine Mail-Adresse angefragt hat.", + "this-mail-was-sent-to-you-because-someone-request-a-password-reset-for-a-account-linked-to-the-mail-address": "Du bekommst diese E-Mail, weil jemand einen Passwort-Reset für deinen Account beantragt hat.", + "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Dein Passwort wird erst zurückgesetzt, wenn du den Reset-Link öffnest und ein neues Passwort setzt.", + "event_name-registration": "{{event_name}} Registrierung", + "if-you-didnt-register-yourself-you-should-contact-us-to-get-your-data-removed-from-our-systems": "Solltest du dich nicht selbst registriert haben schick uns bitte eine Mail und wir entfernen deine Daten aus unserem System: ", + "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website": "Solltest du den Link verlieren kannst du auf unserer Website einen neuen beantragen:", + "thanks-for-registering-and-welcome-to-the-event_name": "Vielen Dank für die Registrierung und willkommen beim {{event_name}}!", + "the-only-thing-you-have-to-do-now-is-to-bring-your-registration-code-with-you": "Du must nichts weiter machen, außer deinen Registrierungscode zum Lauf mitzubringen.", + "this-mail-was-sent-to-you-because-someone-used-your-mail-address-to-register-themselfes-for-the-event_name": "Du bekommst diese Mail, weil jemand deine E-Mail-Adresse verwendet hat, um sich beim {{event_name}} zu registrieren.", + "view-my-data": "Meine Daten", + "we-successfully-processed-your-registration": "Wir haben deine Registrierung erfolgreich verarbeitet.", + "welcome": "Willkommen", + "you-can-view-your-registration-code-lap-times-and-much-more-by-visiting-our-selfservice": "Du kannst deinen Registrierungscode, deine Rundenzeiten unv vieles mehr im Selfservice einsehen:" +} -- 2.47.2 From 056b74ce2268185d39554a7d7afeaaf75c4e17a2 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 18:10:08 +0100 Subject: [PATCH 13/23] Added request class ref #2 --- src/models/WelcomeMail.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/models/WelcomeMail.ts diff --git a/src/models/WelcomeMail.ts b/src/models/WelcomeMail.ts new file mode 100644 index 0000000..78cd928 --- /dev/null +++ b/src/models/WelcomeMail.ts @@ -0,0 +1,16 @@ +import { IsEmail, IsNotEmpty, IsString } from 'class-validator'; + +/** + * Simple welcome mail request class for validation and easier handling. + */ +export class WelcomeMail { + + @IsString() + @IsEmail() + @IsNotEmpty() + address: string; + + @IsString() + @IsNotEmpty() + selfserviceToken: string; +} \ No newline at end of file -- 2.47.2 From b3952c39e5f52412c955d6a9cb96f81396e06d82 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 18:10:41 +0100 Subject: [PATCH 14/23] Added registration mail endpoint ref #2 --- src/controllers/MailController.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/controllers/MailController.ts b/src/controllers/MailController.ts index 337318f..99be6c2 100644 --- a/src/controllers/MailController.ts +++ b/src/controllers/MailController.ts @@ -4,6 +4,7 @@ import { Mailer } from '../Mailer'; import { locales } from '../models/LocaleEnum'; import { ResetMail } from '../models/ResetMail'; import { SuccessResponse } from '../models/SuccessResponse'; +import { WelcomeMail } from '../models/WelcomeMail'; /** * The mail controller handels all endpoints concerning Mail sending. @@ -45,4 +46,20 @@ export class MailController { } return new SuccessResponse(locale); } + + @Post('/registration') + @OpenAPI({ description: "Sends registration welcome mails", parameters: [{ in: "query", name: "locale", schema: { type: "string", enum: ["de", "en"] } }] }) + async sendRegistrationWelcome(@Body({ validate: true }) mailOptions: WelcomeMail, @QueryParam("locale") locale: locales) { + if (!this.initialized) { + await this.mailer.init(); + this.initialized = true; + } + try { + this.mailer.sendWelcomeMail(mailOptions.address, mailOptions.selfserviceToken, locale?.toString()) + } catch (error) { + console.log(error) + throw error; + } + return new SuccessResponse(locale); + } } -- 2.47.2 From ce87e1fc03340922c412a431d9595c740a78f42b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 18:15:05 +0100 Subject: [PATCH 15/23] Added welcome mail tests ref #2 --- src/tests/selfservice_welcome_mail.spec.ts | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/tests/selfservice_welcome_mail.spec.ts diff --git a/src/tests/selfservice_welcome_mail.spec.ts b/src/tests/selfservice_welcome_mail.spec.ts new file mode 100644 index 0000000..709eec0 --- /dev/null +++ b/src/tests/selfservice_welcome_mail.spec.ts @@ -0,0 +1,72 @@ +import axios from 'axios'; +import { config } from '../config'; +const base = "http://localhost:" + config.internal_port + +const axios_config = { + validateStatus: undefined +}; + +describe('POST /registration without auth', () => { + it('Post without auth should return 401', async () => { + const res = await axios.post(base + '/registration', null, axios_config); + expect(res.status).toEqual(401); + }); +}); + +describe('POST /registration with auth but wrong body', () => { + it('Post with auth but no body should return 400', async () => { + const res = await axios.post(base + '/registration?key=' + config.api_key, null, axios_config); + expect(res.status).toEqual(400); + }); + it('Post with auth but no mail should return 400', async () => { + const res = await axios.post(base + '/registration?key=' + config.api_key, { selfserviceToken: "test" }, axios_config); + expect(res.status).toEqual(400); + }); + it('Post with auth but no reset key should return 400', async () => { + const res = await axios.post(base + '/registration?key=' + config.api_key, { address: "test@dev.lauf-fuer-kaya.de" }, axios_config); + expect(res.status).toEqual(400); + }); + it('Post with auth but invalid mail should return 400', async () => { + const res = await axios.post(base + '/registration?key=' + config.api_key, { selfserviceToken: "test", address: "testdev.l.de" }, axios_config); + expect(res.status).toEqual(400); + }); +}); + +describe('POST /reset with auth and vaild body', () => { + it('Post with auth, body and no locale should return 200', async () => { + const res = await axios.post(base + '/registration?key=' + config.api_key, { + selfserviceToken: "test", + address: "test@dev.lauf-fuer-kaya.de" + }, axios_config); + expect(res.status).toEqual(200); + expect(res.data).toEqual({ + success: true, + message: "Sent!", + locale: "en" + }) + }); + it('Post with auth, body and locale=en should return 200', async () => { + const res = await axios.post(base + '/registration?locale=en&key=' + config.api_key, { + selfserviceToken: "test", + address: "test@dev.lauf-fuer-kaya.de" + }, axios_config); + expect(res.status).toEqual(200); + expect(res.data).toEqual({ + success: true, + message: "Sent!", + locale: "en" + }) + }); + it('Post with auth, body and locale=de should return 200', async () => { + const res = await axios.post(base + '/registration?locale=de&key=' + config.api_key, { + selfserviceToken: "test", + address: "test@dev.lauf-fuer-kaya.de" + }, axios_config); + expect(res.status).toEqual(200); + expect(res.data).toEqual({ + success: true, + message: "Sent!", + locale: "de" + }) + }); +}); \ No newline at end of file -- 2.47.2 From 9cb100c7c43b082263f4f58c82554c85d7be8494 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 18:36:34 +0100 Subject: [PATCH 16/23] Added more info to the readme ref #3 --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e83512..18e72c1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,58 @@ # mailer -Handles mail generation and sending (pw reset, welcome mail, etc) \ No newline at end of file +Handles mail generation and sending (pw reset, welcome mail, etc) + +## Dev Setup 🛠 +> Local dev setup + +1. Rename the .env.example file to .env (you can adjust app port and other settings, if needed) or generate a example env with `yarn && yarn test:generate_env`. +2. Install Dependencies + ```bash + yarn + ``` +3. Start the server + ```bash + yarn dev + ``` + + +## Templates +> The mailer uses html and plaintext templates to generate various mails. +> The templates are stored in src/templates by default. + +We provide a set of default templates that we use for the ["Lauf für Kaya!" charity run](https://lauf-fuer-kaya.de). +We use handlebars for templateing utilizing i18next for translation - the i18n string format in the templates is : `{{__ "string"}}` +You can provide your own templates by replacing the ones we provided before compiling the project or by simply mounting your custom templates into the docker container. + +The server currently needs the following templates to work: +* pw-reset.html +* pw-reset.txt +* test.html +* test.txt +* welcome_runner.html +* welcome_runner.txt + + +## Recommended Editor + +[Visual Studio Code](https://code.visualstudio.com/) + +### Recommended Extensions + +* will be automatically recommended via ./vscode/extensions.json +* we also provide a config for i18n-ally in the .vscode folder + +## Staging +### Branches & Tags +* vX.Y.Z: Release tags created from the main branch + * The version numbers follow the semver standard + * A new release tag automaticly triggers the release ci pipeline +* main: Protected "release" branch + * The latest tag of the docker image get's build from this + * New releases get created as tags from this +* dev: Current dev branch for merging the different feature branches and bugfixes + * The dev tag of the docker image get's build from this + * Only push minor changes to this branch! + * To merge a feature branch into this please create a pull request +* feature/xyz: Feature branches - nameing scheme: `feature/issueid-title` +* bugfix/xyz: Branches for bugfixes - nameing scheme:`bugfix/issueid-title` \ No newline at end of file -- 2.47.2 From e48f830c08900a9c9e4451d16a25f3ef3d9485e4 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 18:37:50 +0100 Subject: [PATCH 17/23] Added ci status ref #3 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 18e72c1..a38a752 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # mailer +[![Build Status](https://ci.odit.services/api/badges/lfk/mailer/status.svg?ref=refs/heads/main)](https://ci.odit.services/lfk/mailer) Handles mail generation and sending (pw reset, welcome mail, etc) -- 2.47.2 From 5314100065f24cb0902c1ba207b880016abd300e Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 3 Mar 2021 18:45:06 +0100 Subject: [PATCH 18/23] Added env var docs to readme ref #3 --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a38a752..6c6ca2c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# mailer +# @lfk/mailer [![Build Status](https://ci.odit.services/api/badges/lfk/mailer/status.svg?ref=refs/heads/main)](https://ci.odit.services/lfk/mailer) Handles mail generation and sending (pw reset, welcome mail, etc) @@ -16,7 +16,6 @@ Handles mail generation and sending (pw reset, welcome mail, etc) yarn dev ``` - ## Templates > The mailer uses html and plaintext templates to generate various mails. > The templates are stored in src/templates by default. @@ -33,6 +32,22 @@ The server currently needs the following templates to work: * welcome_runner.html * welcome_runner.txt +| Name | Type | Default | Description +| - | - | - | - +| APP_PORT | Number | 4010 | The port the backend server listens on. Is optional. +| NODE_ENV | String | dev | The apps env - influences debug info. +| API_KEY | String(min length: 64) | Random generated string | The api key you want to use for auth (query-param `key`), has to be at least 64 chars long. +| API_URL | String(url) | "http://localhost:8080" | The URL ponting to the base (root) of the lfk runner system. +| MAIL_SERVER | String(FQDN) | None | The mailserver (smtp) used to send mails via nodemailer. +| MAIL_PORT | Number | 25 | The mailserver's port (smtp). +| MAIL_USER | String | None | The username used to authenticate against the mailserver. +| MAIL_PASSWORD | String | None | The password used to authenticate against the mailserver. +| MAIL_FROM | String | None | The mail address that mails get sent from. +| PRIVACY_URL | String | "/privacy" | The url path that get's attached to the app url to link to the privacy page. +| IMPRINT_URL | String | "/imprint" | The url path that get's attached to the app url to link to the imprint page. +| COPYRIGHT_OWNER | String | "LfK!" | Text that gets inserted as the "copyright by" owner in the mails. +| EVENT_NAME | String | "Testing 4 Kaya" | The event's name - used to generate the mail text. +| CONTACT_MAIL | String(email) | MAIL_FROM | Contact mail address listed at the bottom of some mail templates. ## Recommended Editor -- 2.47.2 From 4b5e24f3e30db94cf46d6d6362be519343c71a83 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 4 Mar 2021 16:43:59 +0100 Subject: [PATCH 19/23] Fixed typo ref #2 --- src/locales/de.json | 50 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/locales/de.json b/src/locales/de.json index db2e60b..36b7de5 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1,26 +1,26 @@ { - "a-password-reset-for-your-account-got-requested": "Ein Passwort Reset wurde für dein Konto beantragt.", - "all-rights-reserved": "Alle Rechte vorbehalten", - "if-you-didnt-request-the-reset-please-ignore-this-mail": "Solltest du den Reset nicht beantragt haben kannst du diese Mail einfach ignorieren.", - "imprint": "Impressum", - "lfk-mail-test": "{{copyright_owner}} - Mail test", - "lfk-password-reset": "{{copyright_owner}} - Passwort zurücksetzen", - "password-reset": "Passwort zurücksetzen", - "privacy": "Datenschutz", - "reset-password": "Passwort zurücksetzen", - "test-mail": "Test mail", - "this-is-a-test-mail-triggered-by-an-admin-in-the-lfk-backend": "Das ist eine Testmail, die von einem Admin im LfK! backend erzeugt wurde.", - "this-mail-was-sent-to-recipient_mail-because-someone-request-a-mail-test-for-this-mail-address": "Du bekommst diese Mail, weil jemand eine Testmail für deine Mail-Adresse angefragt hat.", - "this-mail-was-sent-to-you-because-someone-request-a-password-reset-for-a-account-linked-to-the-mail-address": "Du bekommst diese E-Mail, weil jemand einen Passwort-Reset für deinen Account beantragt hat.", - "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Dein Passwort wird erst zurückgesetzt, wenn du den Reset-Link öffnest und ein neues Passwort setzt.", - "event_name-registration": "{{event_name}} Registrierung", - "if-you-didnt-register-yourself-you-should-contact-us-to-get-your-data-removed-from-our-systems": "Solltest du dich nicht selbst registriert haben schick uns bitte eine Mail und wir entfernen deine Daten aus unserem System: ", - "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website": "Solltest du den Link verlieren kannst du auf unserer Website einen neuen beantragen:", - "thanks-for-registering-and-welcome-to-the-event_name": "Vielen Dank für die Registrierung und willkommen beim {{event_name}}!", - "the-only-thing-you-have-to-do-now-is-to-bring-your-registration-code-with-you": "Du must nichts weiter machen, außer deinen Registrierungscode zum Lauf mitzubringen.", - "this-mail-was-sent-to-you-because-someone-used-your-mail-address-to-register-themselfes-for-the-event_name": "Du bekommst diese Mail, weil jemand deine E-Mail-Adresse verwendet hat, um sich beim {{event_name}} zu registrieren.", - "view-my-data": "Meine Daten", - "we-successfully-processed-your-registration": "Wir haben deine Registrierung erfolgreich verarbeitet.", - "welcome": "Willkommen", - "you-can-view-your-registration-code-lap-times-and-much-more-by-visiting-our-selfservice": "Du kannst deinen Registrierungscode, deine Rundenzeiten unv vieles mehr im Selfservice einsehen:" -} + "a-password-reset-for-your-account-got-requested": "Ein Passwort Reset wurde für dein Konto beantragt.", + "all-rights-reserved": "Alle Rechte vorbehalten", + "if-you-didnt-request-the-reset-please-ignore-this-mail": "Solltest du den Reset nicht beantragt haben kannst du diese Mail einfach ignorieren.", + "imprint": "Impressum", + "lfk-mail-test": "{{copyright_owner}} - Mail test", + "lfk-password-reset": "{{copyright_owner}} - Passwort zurücksetzen", + "password-reset": "Passwort zurücksetzen", + "privacy": "Datenschutz", + "reset-password": "Passwort zurücksetzen", + "test-mail": "Test mail", + "this-is-a-test-mail-triggered-by-an-admin-in-the-lfk-backend": "Das ist eine Testmail, die von einem Admin im LfK! Backend erzeugt wurde.", + "this-mail-was-sent-to-recipient_mail-because-someone-request-a-mail-test-for-this-mail-address": "Du bekommst diese Mail, weil jemand eine Testmail für deine Mail-Adresse angefragt hat.", + "this-mail-was-sent-to-you-because-someone-request-a-password-reset-for-a-account-linked-to-the-mail-address": "Du bekommst diese E-Mail, weil jemand einen Passwort-Reset für deinen Account beantragt hat.", + "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Dein Passwort wird erst zurückgesetzt, wenn du den Reset-Link öffnest und ein neues Passwort setzt.", + "event_name-registration": "{{event_name}} Registrierung", + "if-you-didnt-register-yourself-you-should-contact-us-to-get-your-data-removed-from-our-systems": "Solltest du dich nicht selbst registriert haben schick uns bitte eine Mail und wir entfernen deine Daten aus unserem System: ", + "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website": "Solltest du den Link verlieren kannst du auf unserer Website einen neuen beantragen:", + "thanks-for-registering-and-welcome-to-the-event_name": "Vielen Dank für die Registrierung und willkommen beim {{event_name}}!", + "the-only-thing-you-have-to-do-now-is-to-bring-your-registration-code-with-you": "Du must nichts weiter machen, außer deinen Registrierungscode zum Lauf mitzubringen.", + "this-mail-was-sent-to-you-because-someone-used-your-mail-address-to-register-themselfes-for-the-event_name": "Du bekommst diese Mail, weil jemand deine E-Mail-Adresse verwendet hat, um sich beim {{event_name}} zu registrieren.", + "view-my-data": "Meine Daten", + "we-successfully-processed-your-registration": "Wir haben deine Registrierung erfolgreich verarbeitet.", + "welcome": "Willkommen", + "you-can-view-your-registration-code-lap-times-and-much-more-by-visiting-our-selfservice": "Du kannst deinen Registrierungscode, deine Rundenzeiten unv vieles mehr im Selfservice einsehen:" +} \ No newline at end of file -- 2.47.2 From 1ec95a1fda13bdfdc9c056a4f73578045c77d964 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 4 Mar 2021 16:46:34 +0100 Subject: [PATCH 20/23] Added missing translations ref #2 --- src/templates/welcome_runner.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/templates/welcome_runner.txt b/src/templates/welcome_runner.txt index a77b00b..7cc050f 100644 --- a/src/templates/welcome_runner.txt +++ b/src/templates/welcome_runner.txt @@ -1,18 +1,17 @@ -{{event_name}} Registration +{{__ "event_name-registration"}} -Thanks for registering and welcome to the {{event_name}}! -We successfully processed your registration. +{{__ "thanks-for-registering-and-welcome-to-the-event_name"}} +{{__ "we-successfully-processed-your-registration"}} -The only thing you have to do now is to bring your registration code with you. -You can view your registration code, lap times and much more by visiting our selfservice. +{{__ "the-only-thing-you-have-to-do-now-is-to-bring-your-registration-code-with-you"}} +{{__ "you-can-view-your-registration-code-lap-times-and-much-more-by-visiting-our-selfservice"}} -This is your private selfservice link: {{selfservice_link}} -If you ever loose the link you can request a new one by visiting our website: {{forgot_link}} +{{__ "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website"}} {{forgot_link}} Copyright © {{copyright_owner}}. {{__ "all-rights-reserved"}}. {{__ "imprint"}}: {{link_imprint}} | {{__ "privacy"}}: {{link_privacy}} -This mail was sent to you, because someone used your mail address to register themselfes for the {{event_name}}. -If you didn't register yourself you should contact us at {{contact_mail}} to get your data removed from our systems. \ No newline at end of file +{{__ "this-mail-was-sent-to-you-because-someone-used-your-mail-address-to-register-themselfes-for-the-event_name"}} +{{__ "if-you-didnt-register-yourself-you-should-contact-us-to-get-your-data-removed-from-our-systems"}} {{contact_mail}} \ No newline at end of file -- 2.47.2 From 18620133b92baa81272ee084385129b2fb60d234 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 4 Mar 2021 16:46:53 +0100 Subject: [PATCH 21/23] Sorted translations ref #2 --- src/locales/de.json | 14 ++++++------- src/locales/en.json | 50 ++++++++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/locales/de.json b/src/locales/de.json index 36b7de5..82de50b 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1,7 +1,10 @@ { "a-password-reset-for-your-account-got-requested": "Ein Passwort Reset wurde für dein Konto beantragt.", "all-rights-reserved": "Alle Rechte vorbehalten", + "event_name-registration": "{{event_name}} Registrierung", + "if-you-didnt-register-yourself-you-should-contact-us-to-get-your-data-removed-from-our-systems": "Solltest du dich nicht selbst registriert haben schick uns bitte eine Mail und wir entfernen deine Daten aus unserem System: ", "if-you-didnt-request-the-reset-please-ignore-this-mail": "Solltest du den Reset nicht beantragt haben kannst du diese Mail einfach ignorieren.", + "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website": "Solltest du den Link verlieren kannst du auf unserer Website einen neuen beantragen:", "imprint": "Impressum", "lfk-mail-test": "{{copyright_owner}} - Mail test", "lfk-password-reset": "{{copyright_owner}} - Passwort zurücksetzen", @@ -9,18 +12,15 @@ "privacy": "Datenschutz", "reset-password": "Passwort zurücksetzen", "test-mail": "Test mail", + "thanks-for-registering-and-welcome-to-the-event_name": "Vielen Dank für die Registrierung und willkommen beim {{event_name}}!", + "the-only-thing-you-have-to-do-now-is-to-bring-your-registration-code-with-you": "Du must nichts weiter machen, außer deinen Registrierungscode zum Lauf mitzubringen.", "this-is-a-test-mail-triggered-by-an-admin-in-the-lfk-backend": "Das ist eine Testmail, die von einem Admin im LfK! Backend erzeugt wurde.", "this-mail-was-sent-to-recipient_mail-because-someone-request-a-mail-test-for-this-mail-address": "Du bekommst diese Mail, weil jemand eine Testmail für deine Mail-Adresse angefragt hat.", "this-mail-was-sent-to-you-because-someone-request-a-password-reset-for-a-account-linked-to-the-mail-address": "Du bekommst diese E-Mail, weil jemand einen Passwort-Reset für deinen Account beantragt hat.", - "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Dein Passwort wird erst zurückgesetzt, wenn du den Reset-Link öffnest und ein neues Passwort setzt.", - "event_name-registration": "{{event_name}} Registrierung", - "if-you-didnt-register-yourself-you-should-contact-us-to-get-your-data-removed-from-our-systems": "Solltest du dich nicht selbst registriert haben schick uns bitte eine Mail und wir entfernen deine Daten aus unserem System: ", - "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website": "Solltest du den Link verlieren kannst du auf unserer Website einen neuen beantragen:", - "thanks-for-registering-and-welcome-to-the-event_name": "Vielen Dank für die Registrierung und willkommen beim {{event_name}}!", - "the-only-thing-you-have-to-do-now-is-to-bring-your-registration-code-with-you": "Du must nichts weiter machen, außer deinen Registrierungscode zum Lauf mitzubringen.", "this-mail-was-sent-to-you-because-someone-used-your-mail-address-to-register-themselfes-for-the-event_name": "Du bekommst diese Mail, weil jemand deine E-Mail-Adresse verwendet hat, um sich beim {{event_name}} zu registrieren.", "view-my-data": "Meine Daten", "we-successfully-processed-your-registration": "Wir haben deine Registrierung erfolgreich verarbeitet.", "welcome": "Willkommen", - "you-can-view-your-registration-code-lap-times-and-much-more-by-visiting-our-selfservice": "Du kannst deinen Registrierungscode, deine Rundenzeiten unv vieles mehr im Selfservice einsehen:" + "you-can-view-your-registration-code-lap-times-and-much-more-by-visiting-our-selfservice": "Du kannst deinen Registrierungscode, deine Rundenzeiten unv vieles mehr im Selfservice einsehen:", + "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Dein Passwort wird erst zurückgesetzt, wenn du den Reset-Link öffnest und ein neues Passwort setzt." } \ No newline at end of file diff --git a/src/locales/en.json b/src/locales/en.json index 4829060..627914c 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1,26 +1,26 @@ { - "a-password-reset-for-your-account-got-requested": "A password reset for your account got requested.", - "all-rights-reserved": "All rights reserved.", - "if-you-didnt-request-the-reset-please-ignore-this-mail": "If you didn't request the reset please ignore this mail.", - "imprint": "Imprint", - "lfk-mail-test": "{{copyright_owner}} - Mail test", - "lfk-password-reset": "{{copyright_owner}} - Password reset", - "password-reset": "Password reset", - "privacy": "Privacy", - "reset-password": "Reset password", - "test-mail": "Test mail", - "this-is-a-test-mail-triggered-by-an-admin-in-the-lfk-backend": "This is a test mail triggered by an admin in the LfK! backend.", - "this-mail-was-sent-to-recipient_mail-because-someone-request-a-mail-test-for-this-mail-address": "This mail was sent to you because someone request a mail test for this mail address.", - "this-mail-was-sent-to-you-because-someone-request-a-password-reset-for-a-account-linked-to-the-mail-address": "This mail was sent to you because someone request a password reset for a account linked to the mail address.", - "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Your password won't be changed until you click the reset link below and set a new one.", - "event_name-registration": "{{event_name}} Registration", - "welcome": "Welcome", - "thanks-for-registering-and-welcome-to-the-event_name": "Thanks for registering and welcome to the {{event_name}}!", - "we-successfully-processed-your-registration": "We successfully processed your registration.", - "the-only-thing-you-have-to-do-now-is-to-bring-your-registration-code-with-you": "The only thing you have to do now is to bring your registration code with you.", - "you-can-view-your-registration-code-lap-times-and-much-more-by-visiting-our-selfservice": "You can view your registration code, lap times and much more by visiting our selfservice:", - "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website": "If you ever loose the link you can request a new one by visiting our website:", - "view-my-data": "View my data", - "this-mail-was-sent-to-you-because-someone-used-your-mail-address-to-register-themselfes-for-the-event_name": "This mail was sent to you, because someone used your mail address to register themselfes for the {{event_name}}", - "if-you-didnt-register-yourself-you-should-contact-us-to-get-your-data-removed-from-our-systems": "If you didn't register yourself you should contact us to get your data removed from our systems:" -} + "a-password-reset-for-your-account-got-requested": "A password reset for your account got requested.", + "all-rights-reserved": "All rights reserved.", + "event_name-registration": "{{event_name}} Registration", + "if-you-didnt-register-yourself-you-should-contact-us-to-get-your-data-removed-from-our-systems": "If you didn't register yourself you should contact us to get your data removed from our systems:", + "if-you-didnt-request-the-reset-please-ignore-this-mail": "If you didn't request the reset please ignore this mail.", + "if-you-ever-loose-the-link-you-can-request-a-new-one-by-visiting-our-website": "If you ever loose the link you can request a new one by visiting our website:", + "imprint": "Imprint", + "lfk-mail-test": "{{copyright_owner}} - Mail test", + "lfk-password-reset": "{{copyright_owner}} - Password reset", + "password-reset": "Password reset", + "privacy": "Privacy", + "reset-password": "Reset password", + "test-mail": "Test mail", + "thanks-for-registering-and-welcome-to-the-event_name": "Thanks for registering and welcome to the {{event_name}}!", + "the-only-thing-you-have-to-do-now-is-to-bring-your-registration-code-with-you": "The only thing you have to do now is to bring your registration code with you.", + "this-is-a-test-mail-triggered-by-an-admin-in-the-lfk-backend": "This is a test mail triggered by an admin in the LfK! backend.", + "this-mail-was-sent-to-recipient_mail-because-someone-request-a-mail-test-for-this-mail-address": "This mail was sent to you because someone request a mail test for this mail address.", + "this-mail-was-sent-to-you-because-someone-request-a-password-reset-for-a-account-linked-to-the-mail-address": "This mail was sent to you because someone request a password reset for a account linked to the mail address.", + "this-mail-was-sent-to-you-because-someone-used-your-mail-address-to-register-themselfes-for-the-event_name": "This mail was sent to you, because someone used your mail address to register themselfes for the {{event_name}}", + "view-my-data": "View my data", + "we-successfully-processed-your-registration": "We successfully processed your registration.", + "welcome": "Welcome", + "you-can-view-your-registration-code-lap-times-and-much-more-by-visiting-our-selfservice": "You can view your registration code, lap times and much more by visiting our selfservice:", + "your-password-wont-be-changed-until-you-click-the-reset-link-below-and-set-a-new-one": "Your password won't be changed until you click the reset link below and set a new one." +} \ No newline at end of file -- 2.47.2 From 5e7cfff41eaf14bf17319319534c7713d9bbf3b9 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 4 Mar 2021 16:51:53 +0100 Subject: [PATCH 22/23] =?UTF-8?q?=F0=9F=9A=80Bumped=20version=20to=20v0.1.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 184 +++++++++++++++++++++++++-------------------------- 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/package.json b/package.json index 5c44558..fa6592e 100644 --- a/package.json +++ b/package.json @@ -1,92 +1,92 @@ -{ - "name": "@odit/lfk-mailer", - "version": "0.0.1", - "description": "The document mailer for the LfK! runner system. This generates and sends mails (password reset, welcome, ...)", - "main": "src/app.ts", - "scripts": { - "dev": "nodemon src/app.ts", - "build": "rimraf ./dist && tsc && cp-cli ./src/templates ./dist/templates && cp-cli ./src/locales ./dist/locales", - "licenses:export": "license-exporter --markdown", - "release": "release-it --only-version", - "translations:sort": "node ./scripts/sort_translations.js", - "test": "jest", - "test:watch": "jest --watchAll", - "test:generate_env": "ts-node ./scripts/create_testenv.ts", - "test:ci": "npm run test:generate_env && npm run test:ci:run", - "test:ci:run": "start-server-and-test dev http://localhost:4010/docs/openapi.json test" - }, - "repository": { - "type": "git", - "url": "git@git.odit.services:lfk/mailer.git" - }, - "keywords": [ - "odit", - "lfk", - "mail", - "node" - ], - "author": { - "name": "ODIT.Services", - "email": "info@odit.services", - "url": "https://odit.services" - }, - "contributors": [ - { - "name": "Philipp Dormann", - "email": "philipp@philippdormann.de", - "url": "https://philippdormann.de" - }, - { - "name": "Nicolai Ort", - "email": "info@nicolai-ort.com", - "url": "https://nicolai-ort.com" - } - ], - "license": "CC-BY-NC-SA-4.0", - "dependencies": { - "@odit/class-validator-jsonschema": "^2.1.1", - "class-transformer": "0.3.1", - "class-validator": "^0.13.1", - "consola": "^2.15.3", - "cors": "^2.8.5", - "dotenv": "^8.2.0", - "express": "^4.17.1", - "handlebars": "^4.7.6", - "i18next": "^19.8.7", - "i18next-fs-backend": "^1.0.8", - "nodemailer": "^6.5.0", - "reflect-metadata": "^0.1.13", - "routing-controllers": "0.9.0-alpha.6", - "routing-controllers-openapi": "2.2.0" - }, - "devDependencies": { - "@odit/license-exporter": "^0.0.10", - "@types/express": "^4.17.11", - "@types/jest": "^26.0.20", - "@types/node": "^14.14.22", - "@types/nodemailer": "^6.4.0", - "axios": "^0.21.1", - "cp-cli": "^2.0.0", - "jest": "^26.6.3", - "nodemon": "^2.0.7", - "release-it": "^14.2.2", - "rimraf": "^3.0.2", - "start-server-and-test": "^1.12.0", - "ts-jest": "^26.5.2", - "ts-node": "^9.1.1", - "typescript": "^4.1.3" - }, - "release-it": { - "git": { - "commit": true, - "requireCleanWorkingDir": false, - "commitMessage": "🚀Bumped version to v${version}", - "requireBranch": "dev", - "push": false, - "tag": false - }, - "npm": { - "publish": false - } - } -} \ No newline at end of file +{ + "name": "@odit/lfk-mailer", + "version": "0.1.0", + "description": "The document mailer for the LfK! runner system. This generates and sends mails (password reset, welcome, ...)", + "main": "src/app.ts", + "scripts": { + "dev": "nodemon src/app.ts", + "build": "rimraf ./dist && tsc && cp-cli ./src/templates ./dist/templates && cp-cli ./src/locales ./dist/locales", + "licenses:export": "license-exporter --markdown", + "release": "release-it --only-version", + "translations:sort": "node ./scripts/sort_translations.js", + "test": "jest", + "test:watch": "jest --watchAll", + "test:generate_env": "ts-node ./scripts/create_testenv.ts", + "test:ci": "npm run test:generate_env && npm run test:ci:run", + "test:ci:run": "start-server-and-test dev http://localhost:4010/docs/openapi.json test" + }, + "repository": { + "type": "git", + "url": "git@git.odit.services:lfk/mailer.git" + }, + "keywords": [ + "odit", + "lfk", + "mail", + "node" + ], + "author": { + "name": "ODIT.Services", + "email": "info@odit.services", + "url": "https://odit.services" + }, + "contributors": [ + { + "name": "Philipp Dormann", + "email": "philipp@philippdormann.de", + "url": "https://philippdormann.de" + }, + { + "name": "Nicolai Ort", + "email": "info@nicolai-ort.com", + "url": "https://nicolai-ort.com" + } + ], + "license": "CC-BY-NC-SA-4.0", + "dependencies": { + "@odit/class-validator-jsonschema": "^2.1.1", + "class-transformer": "0.3.1", + "class-validator": "^0.13.1", + "consola": "^2.15.3", + "cors": "^2.8.5", + "dotenv": "^8.2.0", + "express": "^4.17.1", + "handlebars": "^4.7.6", + "i18next": "^19.8.7", + "i18next-fs-backend": "^1.0.8", + "nodemailer": "^6.5.0", + "reflect-metadata": "^0.1.13", + "routing-controllers": "0.9.0-alpha.6", + "routing-controllers-openapi": "2.2.0" + }, + "devDependencies": { + "@odit/license-exporter": "^0.0.10", + "@types/express": "^4.17.11", + "@types/jest": "^26.0.20", + "@types/node": "^14.14.22", + "@types/nodemailer": "^6.4.0", + "axios": "^0.21.1", + "cp-cli": "^2.0.0", + "jest": "^26.6.3", + "nodemon": "^2.0.7", + "release-it": "^14.2.2", + "rimraf": "^3.0.2", + "start-server-and-test": "^1.12.0", + "ts-jest": "^26.5.2", + "ts-node": "^9.1.1", + "typescript": "^4.1.3" + }, + "release-it": { + "git": { + "commit": true, + "requireCleanWorkingDir": false, + "commitMessage": "🚀Bumped version to v${version}", + "requireBranch": "dev", + "push": false, + "tag": false + }, + "npm": { + "publish": false + } + } +} -- 2.47.2 From 4cde30ef98370069dfad748e12bd720c1b84ad3e Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 4 Mar 2021 15:59:33 +0000 Subject: [PATCH 23/23] =?UTF-8?q?=F0=9F=93=96New=20license=20file=20versio?= =?UTF-8?q?n=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad93058..431570f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,4 @@ All notable changes to this project will be documented in this file. Dates are displayed in UTC. -#### 0.0.1 +#### 0.1.0 -- 2.47.2