From 12406777856b290158a460828eace9fba2bd92fa Mon Sep 17 00:00:00 2001 From: Janderson Souza Matias Date: Mon, 15 Jan 2024 12:20:28 -0300 Subject: [PATCH] admin login with otp --- .../migrations/1705331535248-migrations.ts | 23 ++++++ src/modules/auth/controller/index.ts | 81 ++++++++++++------- src/modules/auth/entity/otp.entity.ts | 7 +- src/modules/auth/routes.ts | 6 +- src/modules/auth/service/index.ts | 10 +-- 5 files changed, 89 insertions(+), 38 deletions(-) create mode 100644 src/database/migrations/1705331535248-migrations.ts diff --git a/src/database/migrations/1705331535248-migrations.ts b/src/database/migrations/1705331535248-migrations.ts new file mode 100644 index 0000000..61a71fa --- /dev/null +++ b/src/database/migrations/1705331535248-migrations.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Migrations1705331535248 implements MigrationInterface { + name = "Migrations1705331535248"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "otp" DROP CONSTRAINT "FK_2b232c6eac98f99d29a0ec6950e"` + ); + await queryRunner.query(`ALTER TABLE "otp" DROP COLUMN "coach_id"`); + await queryRunner.query( + `ALTER TABLE "otp" ADD "email" character varying NOT NULL` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "otp" DROP COLUMN "email"`); + await queryRunner.query(`ALTER TABLE "otp" ADD "coach_id" uuid`); + await queryRunner.query( + `ALTER TABLE "otp" ADD CONSTRAINT "FK_2b232c6eac98f99d29a0ec6950e" FOREIGN KEY ("coach_id") REFERENCES "coach"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + } +} diff --git a/src/modules/auth/controller/index.ts b/src/modules/auth/controller/index.ts index 6770589..0ce1acd 100644 --- a/src/modules/auth/controller/index.ts +++ b/src/modules/auth/controller/index.ts @@ -7,32 +7,9 @@ import config from "../../../config"; import { LogsService } from "../../logs/service"; import { RegionService } from "../../region/service"; import { CoachService } from "../../coach/service"; +import { UserService } from "../../user/service"; export default class AuthenticationController { - public static login = async (req: Request, res: Response): Promise => { - try { - const user = await Authentication.authenticateUser(req); - if (user.region_id) await RegionService.getParents(user.region_id); - await LogsService.create(user, "login"); - res.locals.authUser = user; - Authentication.signUser(user, res); - - const { id, name, email, role, region } = user; - - const result = { - id, - name, - email, - role, - region, - }; - - return res.status(HTTP_STATUS_OK).send(result); - } catch (error) { - Authentication.unauthorize(res, error); - } - }; - public static supertsetLogin = async ( _req: Request, res: Response @@ -76,17 +53,65 @@ export default class AuthenticationController { } }; + public static otpAdmin = async (req: Request, res: Response) => { + const { email } = req.body; + + if (email) { + const user = await UserService.findUserByEmail(email); + + if (!user?.email) { + return res.status(404).send({ user }); + } + + await Authentication.sendEmailOTP(user.email); + + return res.status(200).send(email); + } + + return res.status(404).send({ email }); + }; + + public static verifyOtpAdmin = async (req: Request, res: Response) => { + const { email, code } = req.body; + + if (email && code) { + const user = await UserService.findUserByEmail(email); + + if (!user?.email) { + return res.status(404).send({ user }); + } + + const otp = await Authentication.verifyOTP(user.email, code); + + const { id, name, role, region } = user; + + if (otp) { + return res.status(200).send({ + id, + name, + role, + email, + region, + }); + } + + return res.status(404).send({ otp }); + } + + return res.status(404).send({ email, code }); + }; + public static otp = async (req: Request, res: Response) => { const { email } = req.body; if (email) { const coach = await CoachService.findByEmail(email); - if (!coach) { + if (!coach?.email) { return res.status(404).send({ coach }); } - await Authentication.sendEmailOTP(coach); + await Authentication.sendEmailOTP(coach.email); return res.status(200).send(email); } @@ -100,11 +125,11 @@ export default class AuthenticationController { if (email && code) { const coach = await CoachService.findByEmail(email); - if (!coach) { + if (!coach?.email) { return res.status(404).send({ coach }); } - const otp = await Authentication.verifyOTP(coach, code); + const otp = await Authentication.verifyOTP(coach.email, code); if (otp) { return res.status(200).send({ coach }); diff --git a/src/modules/auth/entity/otp.entity.ts b/src/modules/auth/entity/otp.entity.ts index 5e6ef55..eba7706 100644 --- a/src/modules/auth/entity/otp.entity.ts +++ b/src/modules/auth/entity/otp.entity.ts @@ -19,10 +19,9 @@ export class Otp { @Column() code?: string; + @Column() + email?: string; + @Column({ type: "bigint" }) created_at?: number; - - @ManyToOne(() => Coach, (coach) => coach.id) - @JoinColumn({ name: "coach_id" }) - coach?: Coach; } diff --git a/src/modules/auth/routes.ts b/src/modules/auth/routes.ts index 1908031..144bc46 100644 --- a/src/modules/auth/routes.ts +++ b/src/modules/auth/routes.ts @@ -4,7 +4,11 @@ import AuthenticationController from "./controller"; import config from "../../config"; const AuthRouter = (app: Application): void => { - app.post(`/${config.country}/api/auth`, AuthenticationController.login); + app.post(`/${config.country}/api/auth`, AuthenticationController.otpAdmin); + app.post( + `/${config.country}/api/auth/verify`, + AuthenticationController.verifyOtpAdmin + ); app.get( `/${config.country}/api/auth`, Authentication.authenticate, diff --git a/src/modules/auth/service/index.ts b/src/modules/auth/service/index.ts index 8bfa136..edbdd18 100644 --- a/src/modules/auth/service/index.ts +++ b/src/modules/auth/service/index.ts @@ -131,12 +131,12 @@ export default class Authentication { } }; - public static sendEmailOTP = async (coach: Coach) => { + public static sendEmailOTP = async (email: string) => { sgMail.setApiKey(process.env.SENDGRID_API_KEY || ""); const code = Math.floor(1000 + Math.random() * 9000).toString(); const msg = { - to: coach.email, + to: email, from: "noreply@quanti.ca", subject: "Coach Digital - OTP", html: OTP_EMAIL.replace("#{code}", code), @@ -147,18 +147,18 @@ export default class Authentication { await sgMail.send(msg); return await otpRepository.save({ - coach, + email, code, created_at: new Date().getTime(), }); }; - public static verifyOTP = async (coach: Coach, code: string) => { + public static verifyOTP = async (email: string, code: string) => { const otpRepository = await dataSource.getRepository(Otp); const tenMinutesAgo = new Date().getTime() - 10 * 60 * 1000; return await otpRepository.findOneBy({ - coach, + email, code, created_at: MoreThan(tenMinutesAgo), });