diff --git a/src/app.module.ts b/src/app.module.ts index 5e7865bac281ebc0539b8f24c728ef52d540c7f9..317caaab60e78a921488aa404f57fde2e6da13c5 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -4,6 +4,7 @@ import { AppController } from './app.controller'; import { StructuresModule } from './structures/structures.module'; import { ConfigurationModule } from './configuration/configuration.module'; import { CategoriesModule } from './categories/categories.module'; +import { MailerModule } from './mailer/mailer.module'; @Module({ imports: [ ConfigurationModule, @@ -12,6 +13,7 @@ import { CategoriesModule } from './categories/categories.module'; ), StructuresModule, CategoriesModule, + MailerModule, ], controllers: [AppController], }) diff --git a/src/configuration/config.ts b/src/configuration/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee0b9db0dbad8115e0bafe32c87cead508ac0490 --- /dev/null +++ b/src/configuration/config.ts @@ -0,0 +1,21 @@ +export const config = { + url: process.env.MAIL_URL, + token: process.env.MAIL_TOKEN, + host: 'ram.grandlyon.com', + protocol: 'https', + port: '443', + from: 'inclusionnumerique@grandlyon.com', + from_name: 'Réseau des acteurs de la médiation numérique', + replyTo: 'inclusionnumerique@grandlyon.com', + templates: { + directory: './src/mailer/mail-templates', + verify: { + ejs: 'verify.ejs', + json: 'verify.json', + }, + changeEmail: { + ejs: 'changeEmail.ejs', + json: 'changeEmail.json', + }, + }, +}; diff --git a/src/configuration/configuration.service.ts b/src/configuration/configuration.service.ts index ecb1919a1519df3436d2be9d8753972e08e1ef2d..09d6666ca4b1ea1f417218e794f25db463b21789 100644 --- a/src/configuration/configuration.service.ts +++ b/src/configuration/configuration.service.ts @@ -1,8 +1,14 @@ import * as dotenv from 'dotenv'; - +import { config } from './config'; export class ConfigurationService { + private _config = config; + constructor() { // Initializing conf with values from var env dotenv.config(); } + + get config() { + return this._config; + } } diff --git a/src/mailer/mail-templates/changeEmail.ejs b/src/mailer/mail-templates/changeEmail.ejs new file mode 100644 index 0000000000000000000000000000000000000000..636faf2345061368d97af669dbdd882758b9800f --- /dev/null +++ b/src/mailer/mail-templates/changeEmail.ejs @@ -0,0 +1,8 @@ +Bonjour,<br /> +<br /> +Votre adresse email a été modifiée, si vous en avez bien fait la demande, +<a href="<%= config.protocol %>://<%= config.host %><%= config.port ? ':' + config.port : '' %>/change-email/<%= token %>" + >cliquez ici pour valider le changement.</a +> +<br /> +Ce mail est un mail automatique. Merci de ne pas y répondre. diff --git a/src/mailer/mail-templates/changeEmail.json b/src/mailer/mail-templates/changeEmail.json new file mode 100644 index 0000000000000000000000000000000000000000..99c1dddc92c5a36cbb56f51d5f799d872dbc7ef8 --- /dev/null +++ b/src/mailer/mail-templates/changeEmail.json @@ -0,0 +1,3 @@ +{ + "subject": "Changement d'adresse email" +} diff --git a/src/mailer/mail-templates/verify.ejs b/src/mailer/mail-templates/verify.ejs new file mode 100644 index 0000000000000000000000000000000000000000..e384dae43ff76ded6f735fe586b80598c6f8fb14 --- /dev/null +++ b/src/mailer/mail-templates/verify.ejs @@ -0,0 +1,10 @@ +Bonjour<br /> +<br /> +Afin de pouvoir vous connecter sur la plateforme, merci de cliquer sur +<a + href="<%= config.protocol %>://<%= config.host %><%= config.port ? ':' + config.port : '' %>/users/verify/<%= token %>" + >ce lien</a +> +afin de valider votre inscription<br /> +<br /> +Ce mail est un mail automatique. Merci de ne pas y répondre. diff --git a/src/mailer/mail-templates/verify.json b/src/mailer/mail-templates/verify.json new file mode 100644 index 0000000000000000000000000000000000000000..4e9f7278c5459890d1a8a9e4c479873cf6362a25 --- /dev/null +++ b/src/mailer/mail-templates/verify.json @@ -0,0 +1,3 @@ +{ + "subject": "Bienvenue sur le Réseau des Acteurs de la Médiation Numérique de la Métropole de Lyon" +} diff --git a/src/mailer/mailer.module.ts b/src/mailer/mailer.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..e7b3a0e6a361722b7b16ae713fca532a546f02e2 --- /dev/null +++ b/src/mailer/mailer.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { HttpModule } from '@nestjs/common/http/http.module'; +import { MailerService } from './mailer.service'; + +@Module({ + imports: [HttpModule], + providers: [MailerService], + exports: [MailerService], +}) +export class MailerModule {} diff --git a/src/mailer/mailer.service.spec.ts b/src/mailer/mailer.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ab5e828cc63cdd85859586764c0ca2a9d4dc882 --- /dev/null +++ b/src/mailer/mailer.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { MailerService } from './mailer.service'; + +describe('MailerService', () => { + let service: MailerService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [MailerService], + }).compile(); + + service = module.get<MailerService>(MailerService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/mailer/mailer.service.ts b/src/mailer/mailer.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..fdebbee315d40fb73dcb0afcc5ae233f8715c932 --- /dev/null +++ b/src/mailer/mailer.service.ts @@ -0,0 +1,77 @@ +import { HttpService, Injectable, Logger } from '@nestjs/common'; +import { ConfigurationService } from '../configuration/configuration.service'; +import * as fs from 'fs'; +import * as path from 'path'; +@Injectable() +export class MailerService { + public config = null; + constructor(private readonly httpService: HttpService, private configurationService: ConfigurationService) { + this.config = this.configurationService.config; + } + + /** + * Send an email + * + * @param {string} from + * @param {string} to + * @param {string} replyTo + * @param {string} subject + * @param {string} html + * @param {string} text + */ + public send(to: string, subject: string, html: string): Promise<any> { + const data = JSON.stringify({ + from: this.config.from, + // eslint-disable-next-line camelcase + from_name: this.config.from_name, + to: to, + subject: subject, + content: html, + }); + Logger.log(`[Mailer] Send mail : ${subject}`); + return new Promise((resolve, reject) => { + this.httpService + .post(process.env.MAIL_URL, data, { + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + process.env.MAIL_TOKEN, + }, + }) + .subscribe( + (body) => { + Logger.log(`[Mailer] Send mail : ${subject} success`); + return resolve(body); + }, + (err) => { + Logger.error(err); + return reject(err); + } + ); + }); + } + + /** + * Get email template location from config directory and given filename. Also, check if file exists. + * + * @param {string} filename + */ + public getTemplateLocation(filename) { + const ejsPath = path.join(this.config.templates.directory, filename); + if (!fs.existsSync(ejsPath)) { + throw new Error(`Email template '${filename}' cannot be found in ${this.config.templates.directory}`); + } + return ejsPath; + } + /** + * Load email json config file from config directory and given filename. Also, check if file exists + * + * @param {filename} filename + */ + public loadJsonConfig(filename) { + const jsonPath = path.join(this.config.templates.directory, filename); + if (!fs.existsSync(jsonPath)) { + throw new Error(`Email json definition file '${filename}' cannot be found in ${this.config.templates.directory}`); + } + return JSON.parse(fs.readFileSync(jsonPath).toString()); + } +} diff --git a/src/structures/structures.module.ts b/src/structures/structures.module.ts index f6843d41be67818a99918eae46421f7948632340..6a82aae92ddcec6e352b3ede79367694322e150f 100644 --- a/src/structures/structures.module.ts +++ b/src/structures/structures.module.ts @@ -1,11 +1,12 @@ import { HttpModule, Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; +import { MailerModule } from '../mailer/mailer.module'; import { Structure, StructureSchema } from './schemas/structure.schema'; import { StructuresController } from './structures.controller'; import { StructuresService } from './structures.service'; @Module({ - imports: [MongooseModule.forFeature([{ name: Structure.name, schema: StructureSchema }]), HttpModule], + imports: [MongooseModule.forFeature([{ name: Structure.name, schema: StructureSchema }]), HttpModule, MailerModule], controllers: [StructuresController], providers: [StructuresService], }) diff --git a/template.env b/template.env index 92d0f28c21f7d10bf355d6b3108a61482e9c4ef0..bd0a81b58efd1d682e148deff4171376ae8dc3a6 100644 --- a/template.env +++ b/template.env @@ -9,3 +9,5 @@ MONGO_DB_HOST_AND_PORT=<host:port used by the api to connect to mongo db> ME_CONFIG_BASICAUTH_USERNAME=<mongo express username> ME_CONFIG_BASICAUTH_PASSWORD=<mongo express password> ME_PORT=<mongo express port> +MAIL_URL=<API url> +MAIL_TOKEN=<API token> \ No newline at end of file