Skip to content

Commit

Permalink
Implement mailersend
Browse files Browse the repository at this point in the history
  • Loading branch information
akbarsaputrait committed Nov 9, 2024
1 parent ee03f16 commit bdda1d8
Show file tree
Hide file tree
Showing 9 changed files with 287 additions and 53 deletions.
52 changes: 52 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
API_URI=http://localhost:4000
APP_URI=http://localhost:4200
APP_VERSION=

AWS_ACCESS_KEY_ID=
AWS_BUCKET=
AWS_ENDPOINT=
AWS_REGION=
AWS_SECRET_ACCESS_KEY=

DATABASE_MASTER_HOST=
DATABASE_SLAVE_HOST=
DATABASE_PORT=
DATABASE_TYPE=
DATABASE_NAME=
DATABASE_USER=
DATABASE_PASSWORD=

DEBUG=false

ENCRYPT_KEY=
JWT_SECRET=
JWT_TTL=

MODE=production
ORIGIN=http://localhost:4200,https://ordero.vercel.app
PORT=4000

REDIS_DATABASE=0
REDIS_ENABLED=false
REDIS_HOST=
REDIS_PASSWORD=
REDIS_PORT=
REDIS_QUEUE=0

MAIL_FROM='Ordero <[email protected]>'
MAIL_PASSWORD=
MAIL_USERNAME=
SMTP_HOST=
SMTP_PORT=

MAILERSEND_API_KEY=
MAILERSEND_DOMAIN=

SENTRY_DSN=
SOCKET_TYPE=socketio

TWILLIO_SERVICE=
TWILLIO_SID=
TWILLIO_TOKEN=

TZ=UTC
2 changes: 2 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ services:
TWILLIO_SID: '${TWILLIO_SID}'
TWILLIO_TOKEN: '${TWILLIO_TOKEN}'
TWILLIO_SERVICE: '${TWILLIO_SERVICE}'
MAILERSEND_API_KEY: '${MAILERSEND_API_KEY}'
MAILERSEND_DOMAIN: '${MAILERSEND_DOMAIN}'
volumes:
- 'ordero:/api'
ports:
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"json2csv": "^6.0.0-alpha.2",
"libphonenumber-js": "^1.10.12",
"lodash": "^4.17.21",
"mailersend": "^2.3.0",
"mysql-import": "^5.0.21",
"mysql2": "^3.10.2",
"nest-router": "^1.0.9",
Expand Down
48 changes: 25 additions & 23 deletions src/app/owner/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,23 +156,25 @@ export class AuthController {
}

const owner: Owner = await Owner.findOne({ where: { email } });
if (owner && owner.id) {
owner.reset_token = uuid();
await owner.save();

this.mail
.sendMail({
to: owner.email,
subject: 'Set up a new password',
template: 'change-password',
context: {
name: owner.name,
link: `${config.get('APP_URI')}/restaurant/auth/reset-password/${owner.reset_token}`,
},
})
.then(() => null)
.catch((error) => Logger.getInstance().notify(error));
}
await this.service.forgotPassword(owner);

// if (owner && owner.id) {
// owner.reset_token = uuid();
// await owner.save();

// this.mail
// .sendMail({
// to: owner.email,
// subject: 'Set up a new password',
// template: 'change-password',
// context: {
// name: owner.name,
// link: `${config.get('APP_URI')}/restaurant/auth/reset-password/${owner.reset_token}`,
// },
// })
// .then(() => null)
// .catch((error) => Logger.getInstance().notify(error));
// }

return response.noContent();
}
Expand All @@ -188,19 +190,19 @@ export class AuthController {
throw new ValidationException(validation);
}

const staff: Owner = await Owner.findOrFail({ where: { reset_token: body.token } });
const owner: Owner = await Owner.findOrFail({ where: { reset_token: body.token } });

staff.password = await hash(body.password);
staff.reset_token = null;
await staff.save();
owner.password = await hash(body.password);
owner.reset_token = null;
await owner.save();

await this.mail
.sendMail({
to: staff.email,
to: owner.email,
subject: 'Changed password',
template: 'changed-password',
context: {
name: staff.name,
name: owner.name,
},
})
.then(() => null)
Expand Down
39 changes: 24 additions & 15 deletions src/app/owner/restaurant/staff/staff.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Loc } from '@core/decorators/location.decorator';
import { Rest } from '@core/decorators/restaurant.decorator';
import { OwnerAuthGuard } from '@core/guards/auth.guard';
import { OwnerGuard } from '@core/guards/owner.guard';
import { MailService } from '@core/services/mail.service';
import { PermAct, PermOwner } from '@core/services/role.service';
import { Location } from '@db/entities/owner/location.entity';
import { StaffRole } from '@db/entities/staff/role.entity';
Expand All @@ -11,16 +12,14 @@ import { ValidationException } from '@lib/exceptions/validation.exception';
import { hash } from '@lib/helpers/encrypt.helper';
import { randomChar } from '@lib/helpers/utils.helper';
import { Validator } from '@lib/helpers/validator.helper';
import Logger from '@lib/logger/logger.library';
import { Permissions } from '@lib/rbac';
import AppDataSource from '@lib/typeorm/datasource.typeorm';
import { MailerService } from '@nestjs-modules/mailer';
import { BadRequestException, Body, Controller, Get, Param, Post, Put, Res, UseGuards } from '@nestjs/common';

@Controller()
@UseGuards(OwnerAuthGuard())
export class StaffController {
constructor(private mail: MailerService) {}
constructor(private mail: MailService) {}

@Get()
@UseGuards(OwnerGuard)
Expand Down Expand Up @@ -94,18 +93,28 @@ export class StaffController {
staff.restaurant_id = rest.id;
await staff.save();

this.mail
.sendMail({
to: staff.email,
subject: 'Your staff account!',
template: 'staff-register',
context: {
name: staff.name,
password: plainPass,
},
})
.then(() => null)
.catch((error) => Logger.getInstance().notify(error));
await this.mail.sendStaffRegister({
receipient: staff.email,
subject: 'Your staff account!',
data: {
team_name: 'Ordero',
name: staff.name,
password: plainPass,
},
});

// this.mail
// .sendMail({
// to: staff.email,
// subject: 'Your staff account!',
// template: 'staff-register',
// context: {
// name: staff.name,
// password: plainPass,
// },
// })
// .then(() => null)
// .catch((error) => Logger.getInstance().notify(error));

await response.item(staff, StaffTransformer);
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DataSource } from 'typeorm';
import { AuthService } from './services/auth.service';
import { AwsService } from './services/aws.service';
import { CustomerService } from './services/customer.service';
import { MailService } from './services/mail.service';
import { PdfService } from './services/pdf.service';
import { ProductService } from './services/product.service';
import { RoleService } from './services/role.service';
Expand All @@ -26,6 +27,7 @@ const services = [
ProductService,
PdfService,
UtilService,
MailService,
];

@Global()
Expand Down
50 changes: 35 additions & 15 deletions src/core/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { jwt } from '@config/jwt.config';
import { Role } from '@db/entities/core/role.entity';
import { Owner, OwnerStatus } from '@db/entities/owner/owner.entity';
import { Restaurant, RestaurantStatus } from '@db/entities/owner/restaurant.entity';
import { config } from '@lib/helpers/config.helper';
import { hash, hashAreEqual } from '@lib/helpers/encrypt.helper';
import Logger from '@lib/logger/logger.library';
import AppDataSource from '@lib/typeorm/datasource.typeorm';
import { uuid } from '@lib/uid/uuid.library';
import { MailerService } from '@nestjs-modules/mailer';
import { Injectable, NotFoundException } from '@nestjs/common';
import * as JWT from 'jsonwebtoken';
import { MailService } from './mail.service';

@Injectable()
export class AuthService {
constructor(private mail: MailerService) {}
constructor(private readonly mailer: MailService) {}

async attempt(username: string, pass: string): Promise<Owner | null> {
const user = await Owner.findOne({ where: [{ email: username }, { phone: username }] });
Expand Down Expand Up @@ -74,25 +74,45 @@ export class AuthService {

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async sendVerificationEmail(user: Owner, changeEmail = false): Promise<void> {
this.mail
.sendMail({
to: user.email,
subject: 'Verify Your Account',
template: 'register',
context: {
name: user.name,
code: user.verification_code,
},
})
.then(() => null)
.catch((error) => Logger.getInstance().notify(error));
this.mailer.sendVerificationCode({
receipient: user.email,
subject: 'Verify Your Account',
data: {
verification_code: user.verification_code,
team_name: 'Ordero',
name: user.name,
},
});

// this.mail
// .sendMail({
// to: user.email,
// subject: 'Verify Your Account',
// template: 'register',
// context: {
// name: user.name,
// code: user.verification_code,
// },
// })
// .then(() => null)
// .catch((error) => Logger.getInstance().notify(error));
}

async forgotPassword(user: Owner): Promise<void> {
user.reset_token = uuid();
// user.reset_token_expires = time().add(24, 'hour').toDate();
await user.save();

this.mailer.sendResetPassword({
receipient: user.email,
subject: 'Reset Password',
data: {
team_name: 'Ordero',
name: user.name,
reset_link: `${config.get('APP_URI')}/reset-password/${user.reset_token}`,
},
});

// this.mail
// .sendMail({
// to: user.email,
Expand Down
95 changes: 95 additions & 0 deletions src/core/services/mail.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { config } from '@lib/helpers/config.helper';
import { Injectable } from '@nestjs/common';
import { EmailParams, MailerSend, Recipient, Sender } from 'mailersend';

interface MailersendPayload {
receipient: string;
subject: string;
data: {
name: string;
team_name: string;
verification_code?: string;
reset_link?: string;
password?: string;
};
template_id?: string;
}

@Injectable()
export class MailService {
protected mailerSend: MailerSend;
protected sentFrom: Sender;
protected mailDomain: string;

constructor() {
this.mailerSend = new MailerSend({
apiKey: config.get('MAILERSEND_API_KEY'),
});
this.sentFrom = new Sender('[email protected]', 'Order Team');
}

async sendVerificationCode(payload: MailersendPayload) {
const recipients = [new Recipient(payload.receipient, payload.data.name)];
const personalization = [
{
email: payload.receipient,
data: payload.data,
},
];

const emailParams = new EmailParams()
.setFrom(this.sentFrom)
.setTo(recipients)
.setSubject(payload.subject)
.setPersonalization(personalization)
.setTemplateId('z3m5jgrkqkdldpyo');

await this.mailerSend.email.send(emailParams);
}

async sendResetPassword(payload: MailersendPayload) {
const recipients = [new Recipient(payload.receipient, payload.data.name)];
const personalization = [
{
email: payload.receipient,
data: {
name: payload.data.name,
reset_link: payload.data.reset_link,
team_name: payload.data.team_name,
},
},
];

const emailParams = new EmailParams()
.setFrom(this.sentFrom)
.setTo(recipients)
.setSubject(payload.subject)
.setPersonalization(personalization)
.setTemplateId('pq3enl67y78g2vwr');

await this.mailerSend.email.send(emailParams);
}

async sendStaffRegister(payload: MailersendPayload) {
const recipients = [new Recipient(payload.receipient, payload.data.name)];
const personalization = [
{
email: payload.receipient,
data: {
name: payload.data.name,
team_name: payload.data.team_name,
password: payload.data.password,
},
},
];

const emailParams = new EmailParams()
.setFrom(this.sentFrom)
.setTo(recipients)
.setSubject(payload.subject)
.setPersonalization(personalization)
.setTemplateId('351ndgw6q6n4zqx8');

await this.mailerSend.email.send(emailParams);
}
}
Loading

0 comments on commit bdda1d8

Please sign in to comment.