Skip to content

Commit a051221

Browse files
committed
Resend OTP API & test cases
1 parent dfe2264 commit a051221

File tree

6 files changed

+209
-68
lines changed

6 files changed

+209
-68
lines changed

packages/backend/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"scripts": {
2424
"docker:up": "docker-compose up -d",
2525
"start": "node ./dist/index.js",
26-
"test": "jest --coverage --runInBand --transformIgnorePatterns 'node_modules/(?!(dm3-lib-\\w*)/)'",
26+
"test": "npm run docker:up && jest --coverage --runInBand --transformIgnorePatterns 'node_modules/(?!(dm3-lib-\\w*)/)'",
2727
"build": "yarn tsc && cp ./config.yml ./dist/config.yml | true",
2828
"createDeliveryServiceProfile": "node --no-warnings ./cli.js"
2929
},

packages/backend/src/notifications.test.ts

+20-19
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ describe('Notifications', () => {
566566
it('Returns 400 on resend email verification OTP as globalNotifications is turned off', async () => {
567567
const app = express();
568568
app.use(bodyParser.json());
569-
app.use(notifications());
569+
app.use(notifications(deliveryServiceProperties));
570570

571571
const token = await createAuthToken();
572572
const resendOtpMock = jest.fn();
@@ -607,7 +607,7 @@ describe('Notifications', () => {
607607
it('Returns 400 on resend email verification OTP as notificationChannelType is invalid', async () => {
608608
const app = express();
609609
app.use(bodyParser.json());
610-
app.use(notifications());
610+
app.use(notifications(deliveryServiceProperties));
611611

612612
const token = await createAuthToken();
613613
const resendOtpMock = jest.fn();
@@ -644,9 +644,26 @@ describe('Notifications', () => {
644644
});
645645

646646
it('Resend email verification OTP', async () => {
647+
const deliveryServiceProperties: DeliveryServiceProperties = {
648+
messageTTL: 12345,
649+
sizeLimit: 456,
650+
notificationChannel: [
651+
{
652+
type: NotificationChannelType.EMAIL,
653+
config: {
654+
smtpHost: 'smtp.gmail.com',
655+
smtpPort: 587,
656+
smtpEmail: '[email protected]',
657+
smtpUsername: '[email protected]',
658+
smtpPassword: 'abcd1234',
659+
},
660+
},
661+
],
662+
};
663+
647664
const app = express();
648665
app.use(bodyParser.json());
649-
app.use(notifications());
666+
app.use(notifications(deliveryServiceProperties));
650667

651668
const token = await createAuthToken();
652669

@@ -679,22 +696,6 @@ describe('Notifications', () => {
679696
},
680697
},
681698
]),
682-
getDeliveryServiceProperties: () => {
683-
return {
684-
notificationChannel: [
685-
{
686-
type: NotificationChannelType.EMAIL,
687-
config: {
688-
smtpHost: 'smtp.gmail.com',
689-
smtpPort: 587,
690-
smtpEmail: '[email protected]',
691-
smtpUsername: '[email protected]',
692-
smtpPassword: 'abcd1234',
693-
},
694-
},
695-
],
696-
};
697-
},
698699
resendOtp: resendOtpMock,
699700
addUsersNotificationChannel: addUsersNotificationChannelMock,
700701
setOtp: setOtpMock,

packages/backend/src/notifications.ts

+4-7
Original file line numberDiff line numberDiff line change
@@ -103,20 +103,17 @@ export default (deliveryServiceProperties: DeliveryServiceProperties) => {
103103
await resendOtp(
104104
account,
105105
notificationChannelType,
106-
getDeliveryServiceProperties().notificationChannel,
106+
deliveryServiceProperties.notificationChannel,
107107
req.app.locals.db as IDatabase,
108108
);
109109
// Sending a success response
110110
res.sendStatus(200);
111111
}
112112
} catch (e: any) {
113-
if (
114-
e instanceof ChannelNotSupportedError ||
115-
e.message === 'Invalid config.yml'
116-
) {
113+
if (e instanceof ChannelNotSupportedError) {
117114
// return the error for not supported channels
118-
res.sendStatus(400).json({
119-
error: `Notification channel ${notificationChannelType} is currently not supported yet by the DS`,
115+
res.status(400).json({
116+
error: `Notification channel ${notificationChannelType} is currently not supported by the DS`,
120117
});
121118
} else {
122119
// Passing the error to the next middleware

packages/lib/delivery/src/Notification.test.ts

+176-37
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
import { NotificationChannel, NotificationChannelType } from './notifications';
2-
import { addNewNotificationChannel, resendOtp } from './Notification';
3-
import { ChannelNotSupportedError } from './errors/ChannelNotSupportedError';
4-
const nodemailer = require('nodemailer');
2+
import {
3+
RESEND_VERIFICATION_OTP_TIME_PERIOD,
4+
addNewNotificationChannel,
5+
resendOtp,
6+
} from './Notification';
57

68
jest.mock('nodemailer');
79

8-
const sendMailMock = jest.fn();
9-
nodemailer.createTransport.mockReturnValue({
10-
sendMail: sendMailMock,
11-
close: () => {},
12-
});
13-
1410
describe('Notification', () => {
1511
describe('AddEmailNotificationChannel', () => {
1612
it('adds email notification channel', async () => {
@@ -41,6 +37,13 @@ describe('Notification', () => {
4137
},
4238
];
4339

40+
const nodemailer = require('nodemailer');
41+
const sendMailMock = jest.fn();
42+
nodemailer.createTransport.mockReturnValue({
43+
sendMail: sendMailMock,
44+
close: () => {},
45+
});
46+
4447
const db = {
4548
getUsersNotificationChannels,
4649
addUsersNotificationChannel,
@@ -62,6 +65,22 @@ describe('Notification', () => {
6265
});
6366

6467
describe('Resend Email verification OTP', () => {
68+
const notificationChannels: NotificationChannel[] = [
69+
{
70+
type: NotificationChannelType.EMAIL,
71+
config: {
72+
smtpHost: 'smtp.gmail.com',
73+
smtpPort: 587,
74+
smtpEmail: '[email protected]',
75+
smtpUsername: '[email protected]',
76+
smtpPassword: 'abcd1234',
77+
},
78+
},
79+
];
80+
81+
const getOtp = jest.fn();
82+
const setOtp = jest.fn();
83+
6584
it('Should throw error as notification channel is not supported', async () => {
6685
const getUsersNotificationChannels = () =>
6786
Promise.resolve([
@@ -74,21 +93,6 @@ describe('Notification', () => {
7493
},
7594
},
7695
]);
77-
const getOtp = jest.fn();
78-
const setOtp = jest.fn();
79-
80-
const notificationChannels: NotificationChannel[] = [
81-
{
82-
type: NotificationChannelType.EMAIL,
83-
config: {
84-
smtpHost: 'smtp.gmail.com',
85-
smtpPort: 587,
86-
smtpEmail: '[email protected]',
87-
smtpUsername: '[email protected]',
88-
smtpPassword: 'abcd1234',
89-
},
90-
},
91-
];
9296

9397
const db = {
9498
getUsersNotificationChannels,
@@ -122,21 +126,116 @@ describe('Notification', () => {
122126
},
123127
},
124128
]);
125-
const getOtp = jest.fn();
126-
const setOtp = jest.fn();
127129

128-
const notificationChannels: NotificationChannel[] = [
129-
{
130+
const db = {
131+
getUsersNotificationChannels,
132+
getOtp,
133+
setOtp,
134+
};
135+
136+
try {
137+
await resendOtp(
138+
'0x71cb05ee1b1f506ff321da3dac38f25c0c9ce6e1',
139+
NotificationChannelType.EMAIL,
140+
notificationChannels,
141+
db,
142+
);
143+
} catch (error: any) {
144+
expect(error.message).toBe(
145+
'EMAIL notification channel not configured',
146+
);
147+
}
148+
});
149+
150+
it('Should throw error as notification channel is not enabled', async () => {
151+
const getUsersNotificationChannels = () =>
152+
Promise.resolve([
153+
{
154+
type: NotificationChannelType.EMAIL,
155+
config: {
156+
recipientValue: '[email protected]',
157+
isVerified: false,
158+
isEnabled: false,
159+
},
160+
},
161+
]);
162+
163+
const db = {
164+
getUsersNotificationChannels,
165+
getOtp,
166+
setOtp,
167+
};
168+
169+
try {
170+
await resendOtp(
171+
'0x71cb05ee1b1f506ff321da3dac38f25c0c9ce6e1',
172+
NotificationChannelType.EMAIL,
173+
notificationChannels,
174+
db,
175+
);
176+
} catch (error: any) {
177+
expect(error.message).toBe(
178+
'EMAIL notification channel is not enabled',
179+
);
180+
}
181+
});
182+
183+
it('Should throw error as notification channel is already verified', async () => {
184+
const getUsersNotificationChannels = () =>
185+
Promise.resolve([
186+
{
187+
type: NotificationChannelType.EMAIL,
188+
config: {
189+
recipientValue: '[email protected]',
190+
isVerified: true,
191+
isEnabled: true,
192+
},
193+
},
194+
]);
195+
196+
const db = {
197+
getUsersNotificationChannels,
198+
getOtp,
199+
setOtp,
200+
};
201+
202+
try {
203+
await resendOtp(
204+
'0x71cb05ee1b1f506ff321da3dac38f25c0c9ce6e1',
205+
NotificationChannelType.EMAIL,
206+
notificationChannels,
207+
db,
208+
);
209+
} catch (error: any) {
210+
expect(error.message).toBe(
211+
'EMAIL notification channel is already verified',
212+
);
213+
}
214+
});
215+
216+
it('Should throw error as new OTP can not be sent before RESEND_VERIFICATION_OTP_TIME_PERIOD', async () => {
217+
const getOtp = async (
218+
ensName: string,
219+
channelType: NotificationChannelType,
220+
) => {
221+
return Promise.resolve({
222+
otp: '19283',
130223
type: NotificationChannelType.EMAIL,
131-
config: {
132-
smtpHost: 'smtp.gmail.com',
133-
smtpPort: 587,
134-
smtpEmail: '[email protected]',
135-
smtpUsername: '[email protected]',
136-
smtpPassword: 'abcd1234',
224+
generatedAt: new Date(),
225+
});
226+
};
227+
228+
const getUsersNotificationChannels = () =>
229+
Promise.resolve([
230+
{
231+
type: NotificationChannelType.EMAIL,
232+
config: {
233+
recipientValue: '[email protected]',
234+
isVerified: false,
235+
isEnabled: true,
236+
},
137237
},
138-
},
139-
];
238+
]);
140239

141240
const db = {
142241
getUsersNotificationChannels,
@@ -153,9 +252,49 @@ describe('Notification', () => {
153252
);
154253
} catch (error: any) {
155254
expect(error.message).toBe(
156-
'EMAIL notification channel not configured',
255+
'New OTP can be generated after 1 minutes of last OTP generated',
157256
);
158257
}
159258
});
259+
260+
it('Should resend new OTP email error for notification channel', async () => {
261+
const nodemailer = require('nodemailer');
262+
const sendMailMock = jest.fn();
263+
nodemailer.createTransport.mockReturnValue({
264+
sendMail: sendMailMock,
265+
close: () => {},
266+
});
267+
268+
const getUsersNotificationChannels = () =>
269+
Promise.resolve([
270+
{
271+
type: NotificationChannelType.EMAIL,
272+
config: {
273+
recipientValue: '[email protected]',
274+
isVerified: false,
275+
isEnabled: true,
276+
},
277+
},
278+
]);
279+
280+
const db = {
281+
getUsersNotificationChannels,
282+
getOtp,
283+
setOtp,
284+
};
285+
286+
await resendOtp(
287+
'0x71cb05ee1b1f506ff321da3dac38f25c0c9ce6e1',
288+
NotificationChannelType.EMAIL,
289+
notificationChannels,
290+
db,
291+
);
292+
293+
expect(sendMailMock).toHaveBeenCalled();
294+
});
295+
296+
it('Resend OTP time period should be 60 seconds', async () => {
297+
expect(RESEND_VERIFICATION_OTP_TIME_PERIOD).toBe(60);
298+
});
160299
});
161300
});

packages/lib/delivery/src/Notification.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { generateOtp } from './notifications/generateOtp';
1111
const OTP_LENGTH = 5;
1212

1313
// resend OTP time period in seconds
14-
export const RESEND_VERIFICATION_OTP_TIME_PERIOD = 0; // 0 minute
14+
export const RESEND_VERIFICATION_OTP_TIME_PERIOD: number = 60; // 1 minute
1515

1616
// method to save OTP in Redis
1717
export const saveOtp = async (
@@ -139,8 +139,8 @@ export const resendOtp = async (
139139
if (existingOtp && !isAllowedtoSendNewOtp(existingOtp.generatedAt)) {
140140
throw Error(
141141
`New OTP can be generated after ${
142-
RESEND_VERIFICATION_OTP_TIME_PERIOD / 10
143-
} minutes of last OTP genarted`,
142+
RESEND_VERIFICATION_OTP_TIME_PERIOD / 60
143+
} minutes of last OTP generated`,
144144
);
145145
}
146146

packages/lib/delivery/src/index.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,9 @@ export type { DeliveryServiceProperties } from './Delivery';
1717

1818
export * from './notifications';
1919
export { NotificationChannelType } from './notifications';
20-
export { addNewNotificationChannel, resendOtp } from './Notification';
20+
export {
21+
addNewNotificationChannel,
22+
resendOtp,
23+
RESEND_VERIFICATION_OTP_TIME_PERIOD, // it may be needed to show in UI
24+
} from './Notification';
2125
export { ChannelNotSupportedError } from './errors/ChannelNotSupportedError';

0 commit comments

Comments
 (0)