diff --git a/.gitignore b/.gitignore index a63a3ca18744344c22da1189818e3c0a80004bce..00b568be8a906e8e56e434da09316e3c6ced2f46 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ npm-debug.log *.env !template.env + +swagger-spec.json diff --git a/src/email/email.controller.ts b/src/email/email.controller.ts index 6e081c623b00c5042057793ad63fcc80a06bc742..121fe309fc1ab0a393a841816aa74db80c003f37 100644 --- a/src/email/email.controller.ts +++ b/src/email/email.controller.ts @@ -1,7 +1,7 @@ -import { Controller, Post, Body, Res } from '@nestjs/common'; +import { Controller, Post, Body, Res, HttpException, InternalServerErrorException, Logger, HttpCode } from '@nestjs/common'; import { ContactForm } from './email'; import { EmailService } from './email.service'; -import { ApiBadRequestResponse, ApiOkResponse, ApiUseTags, ApiOperation } from '@nestjs/swagger'; +import { ApiBadRequestResponse, ApiOkResponse, ApiUseTags, ApiOperation, ApiInternalServerErrorResponse } from '@nestjs/swagger'; @ApiUseTags('email') @Controller('email') @@ -13,16 +13,16 @@ export class EmailController { @Post('contact') @ApiOperation({ title: 'Send email to admin (emails defined as var env of the project, see docker-compose.yml file).' }) - @ApiOkResponse({ description: 'OK'}) - @ApiBadRequestResponse({ description: 'Missing fields'}) - create(@Body() contactForm: ContactForm, @Res() res) { - this.emailService.send(contactForm, (err, result) => { - if (err !== null || result !== true) { - res.status(err.status).send({error: err.message}); - } else { - res.status(200).send(); - } - }); + @ApiOkResponse({ description: 'OK' }) + @ApiBadRequestResponse({ description: 'Missing fields' }) + @ApiInternalServerErrorResponse({ description: 'Internal error, this is probably a rabbitMQ related error (unreachable service...)'}) + @HttpCode(200) + async create(@Body() contactForm: ContactForm) { + try { + return await this.emailService.send(contactForm); + } catch (error) { + Logger.log(error); + throw new InternalServerErrorException(); + } } - } diff --git a/src/email/email.service.ts b/src/email/email.service.ts index 4170359b52a96787a28ebc3cf079ba86eac26be4..377a62d6241996632311054156969c166c162696 100644 --- a/src/email/email.service.ts +++ b/src/email/email.service.ts @@ -1,18 +1,25 @@ -import { Injectable, Logger } from '@nestjs/common'; -import * as amqp from 'amqplib/callback_api'; +import { Injectable, Logger, InternalServerErrorException, BadRequestException } from '@nestjs/common'; +import * as amqp from 'amqplib'; import { ContactForm, Email } from './email'; -import { config } from 'configuration/config'; +import { ConfigService } from 'configuration/config.service'; @Injectable() export class EmailService { + config: any = {}; - send(contactForm: ContactForm, done) { - const rabbitmqUrl = `amqp://${config.rabbitMQ.user}:${config.rabbitMQ.password}@${config.rabbitMQ.host}:${config.rabbitMQ.port}`; - const mailerQueue = config.mailerQueue; + constructor(private configService: ConfigService) { + this.config = this.configService.config; + } + + async send(contactForm: ContactForm) { + let conn, ch; + // tslint:disable-next-line:max-line-length + const rabbitmqUrl = `amqp://${this.config.rabbitMQ.user}:${this.config.rabbitMQ.password}@${this.config.rabbitMQ.host}:${this.config.rabbitMQ.port}`; + const mailerQueue = this.config.mailerQueue; const email = new Email(); email.from = `${contactForm.firstname} ${contactForm.lastname} ${contactForm.from}`; - email.to = config.adminEmails; + email.to = this.config.adminEmails; email.subject = contactForm.subject; email.text = contactForm.text; @@ -20,34 +27,43 @@ export class EmailService { Logger.log(email); // Connect to rabbitmq - amqp.connect(rabbitmqUrl, (err, conn) => { - if (err != null) { - Logger.error(' [x] Error connecting to RabbitMQ: ', err); - done({ message: 'Could not connect to rabbitMQ.', status: 500}); - } else { - // Create a communication channel - conn.createChannel((error, ch) => { - - if (error != null) { - Logger.error(' [x] Error creating channel: ', error); - done({ message: 'Could not create channel.', status: 500}); - } else { - // Stringify and bufferise message - const buffer = Buffer.from(JSON.stringify(email)); - - ch.assertQueue(mailerQueue, { durable: true }); - - ch.sendToQueue(mailerQueue, buffer, { persistent: true }); - - Logger.log(`Sent to queue ${mailerQueue}: ${JSON.stringify(email)}`); - - done(null, true); - - setTimeout(() => { conn.close(); }, 500); - } - }); - } - }); + try { + conn = await amqp.connect(rabbitmqUrl); + } catch (error) { + Logger.error(' [x] Error connecting to RabbitMQ: ', JSON.stringify(error)); + throw new InternalServerErrorException('Could not connect to rabbitMQ.'); + } + + try { + // Create a communication channel + ch = await conn.createChannel(); + } catch (error) { + Logger.error(' [x] Error creating channel: ', JSON.stringify(error)); + throw new InternalServerErrorException('Could not create channel.'); + } + + // Stringify and bufferise message + const buffer = Buffer.from(JSON.stringify(email)); + + try { + await ch.assertQueue(mailerQueue, { durable: true }); + } catch (error) { + Logger.error(' [x] Error creating channel: ', JSON.stringify(error)); + throw new InternalServerErrorException('Could not assert channel.'); + } + + try { + await ch.sendToQueue(mailerQueue, buffer, { persistent: true }); + } catch (error) { + Logger.error(' [x] Error sending to queue: ', JSON.stringify(error)); + throw new InternalServerErrorException('Could not send to queue.'); + } + + Logger.log(`Sent to queue ${mailerQueue}: ${JSON.stringify(email)}`); + + setTimeout(() => { conn.close(); }, 500); + + return; } } diff --git a/src/main.ts b/src/main.ts index a9e48ce55732ca7ecfdc3c3229f9dacc62e5062c..57e26cd9cf92fdb7f94e7c28ba02341343dcd4bb 100644 --- a/src/main.ts +++ b/src/main.ts @@ -17,7 +17,7 @@ async function bootstrap() { const document = SwaggerModule.createDocument(app, options); fs.writeFileSync('./swagger-spec.json', JSON.stringify(document)); - SwaggerModule.setup('api', app, document); + SwaggerModule.setup('api-doc', app, document); app.useGlobalPipes(new ValidationPipe()); await app.listen(3000); diff --git a/swagger-spec.json b/swagger-spec.json index a84f48ccf9b851975ffb60623a1d25e6f470bc49..86ef94311ea98275f19b6a1af4cba0e14899c562 100644 --- a/swagger-spec.json +++ b/swagger-spec.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"description":"APIs description for the Email API","version":"0.1","title":"Portail Data Email MicroService API"},"basePath":"/","tags":[],"schemes":["http"],"paths":{"/email/contact":{"post":{"parameters":[{"name":"ContactForm","required":true,"in":"body","schema":{"$ref":"#/definitions/ContactForm"}}],"responses":{"200":{"description":"OK"},"400":{"description":"Missing fields"}},"produces":["application/json"],"consumes":["application/json"]}}},"definitions":{"ContactForm":{"type":"object","properties":{"from":{"type":"string"},"subject":{"type":"string"},"firstname":{"type":"string"},"lastname":{"type":"string"},"text":{"type":"string"}},"required":["from","subject","firstname","lastname","text"]}}} \ No newline at end of file +{"swagger":"2.0","info":{"description":"Service providing the method to send emails.","version":"0.1","title":"Email service API"},"basePath":"/","tags":[{"name":"email","description":""}],"schemes":["http"],"paths":{"/email/contact":{"post":{"summary":"Send email to admin (emails defined as var env of the project, see docker-compose.yml file).","parameters":[{"name":"ContactForm","required":true,"in":"body","schema":{"$ref":"#/definitions/ContactForm"}}],"responses":{"200":{"description":"OK"},"400":{"description":"Missing fields"},"500":{"description":"Internal error, this is probably a rabbitMQ related error (unreachable service...)"}},"tags":["email"],"produces":["application/json"],"consumes":["application/json"]}}},"definitions":{"ContactForm":{"type":"object","properties":{"from":{"type":"string"},"subject":{"type":"string"},"firstname":{"type":"string"},"lastname":{"type":"string"},"text":{"type":"string"}},"required":["from","subject","firstname","lastname","text"]}}} \ No newline at end of file