Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions src/services/authService.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ const { tokenTypes } = require("../config/tokens");
const { sendEmail } = require("../Email/sendEmail");


// Les emails envoyés une fois l'opération enregistrée en base ne sont que des
// notifications : une panne SMTP ne doit pas faire répondre en erreur alors
// que le changement, lui, est acquis. Les emails porteurs d'un code, eux,
// restent bloquants.
const sendNotificationEmail = async (options) => {
try {
await sendEmail(options);
} catch (e) {
logger.error(e);
}
};


const createUser = async (userBody) => {
try {
let message = 'Successfully Registered the account! Please Verify your email.';
Expand Down Expand Up @@ -312,7 +325,7 @@ const confirmEmailService = async (data, user) => {
subject: "Merci - Email confirmer",
message: "Votre email a été confirmer ",
}
await sendEmail(options);
await sendNotificationEmail(options);

return success(
httpStatus.OK,
Expand Down Expand Up @@ -368,7 +381,7 @@ const confirmTelService = async (data, user) => {
subject: "Merci - Numéro de téléphone confirmer",
message: "Votre numéro de téléphone a été confirmer ",
}
await sendEmail(options);
await sendNotificationEmail(options);

return success(
httpStatus.OK,
Expand Down Expand Up @@ -516,7 +529,7 @@ const confirmPasswordCodeService = async (data) => {
message: "Your password has been successfully reset. If you are not at the origin of this action write to us at the email address at the bottom of the page",
// email_verification_code: userBody.email_verification_code
}
await sendEmail(options);
await sendNotificationEmail(options);

return success(
httpStatus.OK,
Expand Down Expand Up @@ -562,8 +575,18 @@ const updateUserService = async (userBody, user) => {
};

const getOnlyUserData = (user) => {
const { nom, prenoms, address, email, tel, uuid,} = user;
return {uuid, nom, prenoms, email, tel, address,};
// Le client affiche le rôle et les badges de vérification à partir de ces
// champs : les omettre ici revenait à les effacer côté client après une
// inscription ou une mise à jour de profil.
const { nom, prenoms, address, email, tel, uuid, role, status, email_verified_at, tel_verified_at } = user;
return {
uuid, nom, prenoms, email, tel, address, role, status,
// Sur une instance fraîchement créée ces dates valent undefined et
// disparaissent de la réponse JSON : on les force à null pour que le
// client reçoive toujours la même forme.
email_verified_at: email_verified_at ?? null,
tel_verified_at: tel_verified_at ?? null,
};
}

module.exports = {
Expand Down
75 changes: 75 additions & 0 deletions tests/profile-payload.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
jest.mock('../src/Email/sendEmail', () => ({ sendEmail: jest.fn().mockResolvedValue(true) }));

const { sendEmail } = require('../src/Email/sendEmail');
const {
resetDatabase, closeDatabase, createLoggedInUser, authed, register, minutesFromNow,
} = require('./helpers');

let accessToken;
let user;

beforeEach(async () => {
sendEmail.mockReset();
sendEmail.mockResolvedValue(true);
await resetDatabase();
({ accessToken, user } = await createLoggedInUser());
});

afterAll(closeDatabase);

// Le client construit son affichage (badges de vérification, rôle) à partir de
// ces champs : s'ils manquent de la réponse, il les efface de son état.
describe('payload de profil', () => {
it("expose le rôle, le statut et les dates de vérification à l'inscription", async () => {
const res = await register({ email: 'second.user@example.com', tel: '+22509080706' });

expect(res.status).toBe(201);
expect(res.body.data.role).toBe('user');
expect(res.body.data).toHaveProperty('status');
expect(res.body.data).toHaveProperty('email_verified_at');
expect(res.body.data).toHaveProperty('tel_verified_at');
});

it('expose les mêmes champs après une mise à jour de profil', async () => {
const res = await authed('put', '/update-profile', accessToken)
.send({ nom: 'Nouveau', prenoms: 'Nom', address: 'Abidjan' });

expect(res.status).toBe(200);
expect(res.body.response.data.role).toBe('user');
expect(res.body.response.data).toHaveProperty('email_verified_at');
expect(res.body.response.data).toHaveProperty('tel_verified_at');
});
});

// Ces emails partent une fois le changement écrit en base : les faire échouer
// ferait répondre en erreur alors que l'opération a bien eu lieu.
describe('notifications non bloquantes', () => {
const armCode = () => user.update({
verification_code: '1234567',
verification_code_expires_at: minutesFromNow(5),
});

it("confirme l'email même si l'envoi de la notification échoue", async () => {
await armCode();
sendEmail.mockRejectedValue(new Error('SMTP indisponible'));

const res = await authed('post', '/confirm-email', accessToken)
.send({ verification_email_code: 1234567 });

expect(res.status).toBe(200);
await user.reload();
expect(user.email_verified_at).not.toBeNull();
});

it('confirme le téléphone même si l\'envoi de la notification échoue', async () => {
await armCode();
sendEmail.mockRejectedValue(new Error('SMTP indisponible'));

const res = await authed('post', '/confirm-tel', accessToken)
.send({ verification_tel_code: 1234567 });

expect(res.status).toBe(200);
await user.reload();
expect(user.tel_verified_at).not.toBeNull();
});
});
Loading