Skip to content

Commit bdda1d8

Browse files
Implement mailersend
1 parent ee03f16 commit bdda1d8

9 files changed

+287
-53
lines changed

.env.example

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
API_URI=http://localhost:4000
2+
APP_URI=http://localhost:4200
3+
APP_VERSION=
4+
5+
AWS_ACCESS_KEY_ID=
6+
AWS_BUCKET=
7+
AWS_ENDPOINT=
8+
AWS_REGION=
9+
AWS_SECRET_ACCESS_KEY=
10+
11+
DATABASE_MASTER_HOST=
12+
DATABASE_SLAVE_HOST=
13+
DATABASE_PORT=
14+
DATABASE_TYPE=
15+
DATABASE_NAME=
16+
DATABASE_USER=
17+
DATABASE_PASSWORD=
18+
19+
DEBUG=false
20+
21+
ENCRYPT_KEY=
22+
JWT_SECRET=
23+
JWT_TTL=
24+
25+
MODE=production
26+
ORIGIN=http://localhost:4200,https://ordero.vercel.app
27+
PORT=4000
28+
29+
REDIS_DATABASE=0
30+
REDIS_ENABLED=false
31+
REDIS_HOST=
32+
REDIS_PASSWORD=
33+
REDIS_PORT=
34+
REDIS_QUEUE=0
35+
36+
MAIL_FROM='Ordero <[email protected]>'
37+
MAIL_PASSWORD=
38+
MAIL_USERNAME=
39+
SMTP_HOST=
40+
SMTP_PORT=
41+
42+
MAILERSEND_API_KEY=
43+
MAILERSEND_DOMAIN=
44+
45+
SENTRY_DSN=
46+
SOCKET_TYPE=socketio
47+
48+
TWILLIO_SERVICE=
49+
TWILLIO_SID=
50+
TWILLIO_TOKEN=
51+
52+
TZ=UTC

docker-compose.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ services:
9595
TWILLIO_SID: '${TWILLIO_SID}'
9696
TWILLIO_TOKEN: '${TWILLIO_TOKEN}'
9797
TWILLIO_SERVICE: '${TWILLIO_SERVICE}'
98+
MAILERSEND_API_KEY: '${MAILERSEND_API_KEY}'
99+
MAILERSEND_DOMAIN: '${MAILERSEND_DOMAIN}'
98100
volumes:
99101
- 'ordero:/api'
100102
ports:

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"json2csv": "^6.0.0-alpha.2",
6666
"libphonenumber-js": "^1.10.12",
6767
"lodash": "^4.17.21",
68+
"mailersend": "^2.3.0",
6869
"mysql-import": "^5.0.21",
6970
"mysql2": "^3.10.2",
7071
"nest-router": "^1.0.9",

src/app/owner/auth/auth.controller.ts

+25-23
Original file line numberDiff line numberDiff line change
@@ -156,23 +156,25 @@ export class AuthController {
156156
}
157157

158158
const owner: Owner = await Owner.findOne({ where: { email } });
159-
if (owner && owner.id) {
160-
owner.reset_token = uuid();
161-
await owner.save();
162-
163-
this.mail
164-
.sendMail({
165-
to: owner.email,
166-
subject: 'Set up a new password',
167-
template: 'change-password',
168-
context: {
169-
name: owner.name,
170-
link: `${config.get('APP_URI')}/restaurant/auth/reset-password/${owner.reset_token}`,
171-
},
172-
})
173-
.then(() => null)
174-
.catch((error) => Logger.getInstance().notify(error));
175-
}
159+
await this.service.forgotPassword(owner);
160+
161+
// if (owner && owner.id) {
162+
// owner.reset_token = uuid();
163+
// await owner.save();
164+
165+
// this.mail
166+
// .sendMail({
167+
// to: owner.email,
168+
// subject: 'Set up a new password',
169+
// template: 'change-password',
170+
// context: {
171+
// name: owner.name,
172+
// link: `${config.get('APP_URI')}/restaurant/auth/reset-password/${owner.reset_token}`,
173+
// },
174+
// })
175+
// .then(() => null)
176+
// .catch((error) => Logger.getInstance().notify(error));
177+
// }
176178

177179
return response.noContent();
178180
}
@@ -188,19 +190,19 @@ export class AuthController {
188190
throw new ValidationException(validation);
189191
}
190192

191-
const staff: Owner = await Owner.findOrFail({ where: { reset_token: body.token } });
193+
const owner: Owner = await Owner.findOrFail({ where: { reset_token: body.token } });
192194

193-
staff.password = await hash(body.password);
194-
staff.reset_token = null;
195-
await staff.save();
195+
owner.password = await hash(body.password);
196+
owner.reset_token = null;
197+
await owner.save();
196198

197199
await this.mail
198200
.sendMail({
199-
to: staff.email,
201+
to: owner.email,
200202
subject: 'Changed password',
201203
template: 'changed-password',
202204
context: {
203-
name: staff.name,
205+
name: owner.name,
204206
},
205207
})
206208
.then(() => null)

src/app/owner/restaurant/staff/staff.controller.ts

+24-15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Loc } from '@core/decorators/location.decorator';
22
import { Rest } from '@core/decorators/restaurant.decorator';
33
import { OwnerAuthGuard } from '@core/guards/auth.guard';
44
import { OwnerGuard } from '@core/guards/owner.guard';
5+
import { MailService } from '@core/services/mail.service';
56
import { PermAct, PermOwner } from '@core/services/role.service';
67
import { Location } from '@db/entities/owner/location.entity';
78
import { StaffRole } from '@db/entities/staff/role.entity';
@@ -11,16 +12,14 @@ import { ValidationException } from '@lib/exceptions/validation.exception';
1112
import { hash } from '@lib/helpers/encrypt.helper';
1213
import { randomChar } from '@lib/helpers/utils.helper';
1314
import { Validator } from '@lib/helpers/validator.helper';
14-
import Logger from '@lib/logger/logger.library';
1515
import { Permissions } from '@lib/rbac';
1616
import AppDataSource from '@lib/typeorm/datasource.typeorm';
17-
import { MailerService } from '@nestjs-modules/mailer';
1817
import { BadRequestException, Body, Controller, Get, Param, Post, Put, Res, UseGuards } from '@nestjs/common';
1918

2019
@Controller()
2120
@UseGuards(OwnerAuthGuard())
2221
export class StaffController {
23-
constructor(private mail: MailerService) {}
22+
constructor(private mail: MailService) {}
2423

2524
@Get()
2625
@UseGuards(OwnerGuard)
@@ -94,18 +93,28 @@ export class StaffController {
9493
staff.restaurant_id = rest.id;
9594
await staff.save();
9695

97-
this.mail
98-
.sendMail({
99-
to: staff.email,
100-
subject: 'Your staff account!',
101-
template: 'staff-register',
102-
context: {
103-
name: staff.name,
104-
password: plainPass,
105-
},
106-
})
107-
.then(() => null)
108-
.catch((error) => Logger.getInstance().notify(error));
96+
await this.mail.sendStaffRegister({
97+
receipient: staff.email,
98+
subject: 'Your staff account!',
99+
data: {
100+
team_name: 'Ordero',
101+
name: staff.name,
102+
password: plainPass,
103+
},
104+
});
105+
106+
// this.mail
107+
// .sendMail({
108+
// to: staff.email,
109+
// subject: 'Your staff account!',
110+
// template: 'staff-register',
111+
// context: {
112+
// name: staff.name,
113+
// password: plainPass,
114+
// },
115+
// })
116+
// .then(() => null)
117+
// .catch((error) => Logger.getInstance().notify(error));
109118

110119
await response.item(staff, StaffTransformer);
111120
}

src/core/core.module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { DataSource } from 'typeorm';
1010
import { AuthService } from './services/auth.service';
1111
import { AwsService } from './services/aws.service';
1212
import { CustomerService } from './services/customer.service';
13+
import { MailService } from './services/mail.service';
1314
import { PdfService } from './services/pdf.service';
1415
import { ProductService } from './services/product.service';
1516
import { RoleService } from './services/role.service';
@@ -26,6 +27,7 @@ const services = [
2627
ProductService,
2728
PdfService,
2829
UtilService,
30+
MailService,
2931
];
3032

3133
@Global()

src/core/services/auth.service.ts

+35-15
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import { jwt } from '@config/jwt.config';
22
import { Role } from '@db/entities/core/role.entity';
33
import { Owner, OwnerStatus } from '@db/entities/owner/owner.entity';
44
import { Restaurant, RestaurantStatus } from '@db/entities/owner/restaurant.entity';
5+
import { config } from '@lib/helpers/config.helper';
56
import { hash, hashAreEqual } from '@lib/helpers/encrypt.helper';
6-
import Logger from '@lib/logger/logger.library';
77
import AppDataSource from '@lib/typeorm/datasource.typeorm';
88
import { uuid } from '@lib/uid/uuid.library';
9-
import { MailerService } from '@nestjs-modules/mailer';
109
import { Injectable, NotFoundException } from '@nestjs/common';
1110
import * as JWT from 'jsonwebtoken';
11+
import { MailService } from './mail.service';
1212

1313
@Injectable()
1414
export class AuthService {
15-
constructor(private mail: MailerService) {}
15+
constructor(private readonly mailer: MailService) {}
1616

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

7575
// eslint-disable-next-line @typescript-eslint/no-unused-vars
7676
async sendVerificationEmail(user: Owner, changeEmail = false): Promise<void> {
77-
this.mail
78-
.sendMail({
79-
to: user.email,
80-
subject: 'Verify Your Account',
81-
template: 'register',
82-
context: {
83-
name: user.name,
84-
code: user.verification_code,
85-
},
86-
})
87-
.then(() => null)
88-
.catch((error) => Logger.getInstance().notify(error));
77+
this.mailer.sendVerificationCode({
78+
receipient: user.email,
79+
subject: 'Verify Your Account',
80+
data: {
81+
verification_code: user.verification_code,
82+
team_name: 'Ordero',
83+
name: user.name,
84+
},
85+
});
86+
87+
// this.mail
88+
// .sendMail({
89+
// to: user.email,
90+
// subject: 'Verify Your Account',
91+
// template: 'register',
92+
// context: {
93+
// name: user.name,
94+
// code: user.verification_code,
95+
// },
96+
// })
97+
// .then(() => null)
98+
// .catch((error) => Logger.getInstance().notify(error));
8999
}
90100

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

106+
this.mailer.sendResetPassword({
107+
receipient: user.email,
108+
subject: 'Reset Password',
109+
data: {
110+
team_name: 'Ordero',
111+
name: user.name,
112+
reset_link: `${config.get('APP_URI')}/reset-password/${user.reset_token}`,
113+
},
114+
});
115+
96116
// this.mail
97117
// .sendMail({
98118
// to: user.email,

src/core/services/mail.service.ts

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { config } from '@lib/helpers/config.helper';
2+
import { Injectable } from '@nestjs/common';
3+
import { EmailParams, MailerSend, Recipient, Sender } from 'mailersend';
4+
5+
interface MailersendPayload {
6+
receipient: string;
7+
subject: string;
8+
data: {
9+
name: string;
10+
team_name: string;
11+
verification_code?: string;
12+
reset_link?: string;
13+
password?: string;
14+
};
15+
template_id?: string;
16+
}
17+
18+
@Injectable()
19+
export class MailService {
20+
protected mailerSend: MailerSend;
21+
protected sentFrom: Sender;
22+
protected mailDomain: string;
23+
24+
constructor() {
25+
this.mailerSend = new MailerSend({
26+
apiKey: config.get('MAILERSEND_API_KEY'),
27+
});
28+
this.sentFrom = new Sender('[email protected]', 'Order Team');
29+
}
30+
31+
async sendVerificationCode(payload: MailersendPayload) {
32+
const recipients = [new Recipient(payload.receipient, payload.data.name)];
33+
const personalization = [
34+
{
35+
email: payload.receipient,
36+
data: payload.data,
37+
},
38+
];
39+
40+
const emailParams = new EmailParams()
41+
.setFrom(this.sentFrom)
42+
.setTo(recipients)
43+
.setSubject(payload.subject)
44+
.setPersonalization(personalization)
45+
.setTemplateId('z3m5jgrkqkdldpyo');
46+
47+
await this.mailerSend.email.send(emailParams);
48+
}
49+
50+
async sendResetPassword(payload: MailersendPayload) {
51+
const recipients = [new Recipient(payload.receipient, payload.data.name)];
52+
const personalization = [
53+
{
54+
email: payload.receipient,
55+
data: {
56+
name: payload.data.name,
57+
reset_link: payload.data.reset_link,
58+
team_name: payload.data.team_name,
59+
},
60+
},
61+
];
62+
63+
const emailParams = new EmailParams()
64+
.setFrom(this.sentFrom)
65+
.setTo(recipients)
66+
.setSubject(payload.subject)
67+
.setPersonalization(personalization)
68+
.setTemplateId('pq3enl67y78g2vwr');
69+
70+
await this.mailerSend.email.send(emailParams);
71+
}
72+
73+
async sendStaffRegister(payload: MailersendPayload) {
74+
const recipients = [new Recipient(payload.receipient, payload.data.name)];
75+
const personalization = [
76+
{
77+
email: payload.receipient,
78+
data: {
79+
name: payload.data.name,
80+
team_name: payload.data.team_name,
81+
password: payload.data.password,
82+
},
83+
},
84+
];
85+
86+
const emailParams = new EmailParams()
87+
.setFrom(this.sentFrom)
88+
.setTo(recipients)
89+
.setSubject(payload.subject)
90+
.setPersonalization(personalization)
91+
.setTemplateId('351ndgw6q6n4zqx8');
92+
93+
await this.mailerSend.email.send(emailParams);
94+
}
95+
}

0 commit comments

Comments
 (0)