eletrotupi / tcc/ commit / f217e8c

api: dispatch a reset password email

Pedro Lucas Porcellis porcellis@eletrotupi.com · 5 months ago f217e8c7216589be03ffe264c1931b4c2369d5b1 Browse files
Parents c387557
Changed files
6
Additions
+52
Deletions
-7
api/src/controllers/auth.ts
1 1
import { Request, Response, NextFunction } from 'express';
2 2
import {
3 3
  authenticateUser,
4 4
  generateToken,
5 5
  initiatePasswordReset,
6 6
  resetPassword,
7 7
  findUserByEmail
8 8
} from '@app/models/user';
9 +

9 10
import {
10 11
  validateRequiredFields
11 12
} from '@app/utils/validators';
13 +

12 14
import { verifyToken } from '@app/lib/jwt';
15 +
import { getQueue, MailJobName } from '@app/lib/queue';
13 16

14 17
export const AuthController = {
15 18
  login: async (req: Request, res: Response, next: NextFunction) => {
16 19
    try {
17 20
      const { email, password } = req.body;
59 62
          missing: requiredValidation.missing
60 63
        });
61 64
      }
62 65

63 66
      const result = await initiatePasswordReset(email);
67 +
      const mailQueue = getQueue('mail');
68 +
      const job = await mailQueue.add(MailJobName.PasswordReset, {
69 +
        userId: result.id,
70 +
        token: result.token
71 +
      });
64 72

65 73
      // In production, don't send token in response
66 74
      // Instead, send email with reset link
67 75
      res.json({
68 76
        message: 'Password reset instructions sent to your email',
128 136
      }
129 137
      next(err);
130 138
    }
131 139
  }
132 140
};
api/src/lib/queue/processors/mail.ts
1 1
import { Job } from 'bullmq';
2 2
import {
3 3
  MailJobName, MailJobData,
4 4
  WelcomeEmailPayload,
5 5
  PasswordResetPayload,
6 6
} from '@app/lib/queue/types';
7 7

8 8
import {
9 -
  sendWelcomeEmail
9 +
  sendWelcomeEmail,
10 +
  sendResetPasswordEmail
10 11
} from '@app/services/mail'
11 12

12 13
export async function mailProcessor(job: Job<MailJobData['data']>): Promise<void> {
13 14
  // job.name is the discriminant
14 15
  switch (job.name as MailJobName) {
15 16
    case MailJobName.WelcomeEmail: {
16 17
      const data = job.data as WelcomeEmailPayload;
17 -
      // await sendWelcomeEmail(data.userId);
18 -

19 18
      console.log("Dispatching an welcome email", data);
20 19

21 20
      sendWelcomeEmail(Number(data.userId));
22 21

23 22
      break;
24 23
    }
25 24

26 25
    case MailJobName.PasswordReset: {
27 26
      const data = job.data as PasswordResetPayload;
28 -
      // await sendPasswordResetEmail(data.userId, data.token);
27 +
      console.log("Dispatching an welcome email", data);
28 +

29 +
      await sendResetPasswordEmail(data.userId, data.token);
30 +

29 31
      break;
30 32
    }
31 33

32 34
    default:
33 35
      throw new Error(`Unknown mail job: ${job.name}`);
34 36
  }
35 37
}
api/src/lib/queue/types.ts
1 1
// Mail queue
2 2
export enum MailJobName {
3 3
  WelcomeEmail    = 'mail:welcome',
4 4
  PasswordReset   = 'mail:password-reset',
5 5
}
6 6

7 -
export type WelcomeEmailPayload    = { userId: string };
8 -
export type PasswordResetPayload   = { userId: string; token: string };
7 +
export type WelcomeEmailPayload    = { userId: number };
8 +
export type PasswordResetPayload   = { userId: number; token: string };
9 9

10 10
export type MailJobData =
11 11
  | { name: MailJobName.WelcomeEmail;  data: WelcomeEmailPayload }
12 12
  | { name: MailJobName.PasswordReset; data: PasswordResetPayload };
api/src/models/user.ts
1 1
import bcrypt from "bcryptjs";
2 2
import { prisma } from '../lib/prisma'
3 3
import {
4 4
  generateToken as createJWT,
5 5
  generatePasswordResetToken,
107 107
  // In production, send email with reset link
108 108
  // For now, return token for testing
109 109
  return {
110 110
    success: true,
111 111
    token: resetToken,
112 -
    email: user.email
112 +
    email: user.email,
113 +
    id: user.id
113 114
  };
114 115
};
115 116

116 117
const resetPassword = async (token: string, newPassword: string) => {
117 118
  const user = await prisma.user.findFirst({
171 172
  authenticateUser,
172 173
  initiatePasswordReset,
173 174
  resetPassword,
174 175
  updateUser
175 176
}
api/src/services/mail/index.ts
1 1
export { sendWelcomeEmail } from '@app/services/mail/welcome';
2 +
export { sendResetPasswordEmail } from '@app/services/mail/sendPasswordReset'
/dev/null → api/src/services/mail/sendPasswordReset.ts
1 +
import { findUserById } from '@app/models/user';
2 +
import { sendEmail }  from '@app/lib/mail';
3 +

4 +
const email = (firstName: string, token: string) => {
5 +
  return (`
6 +
Oi, ${firstName}.
7 +

8 +
Ouvimos por aí que você precisa trocar a senha?
9 +

10 +
Segue o código para você digitar no app: ${token}
11 +

12 +
Qualquer coisa prende o grito!
13 +
`)
14 +
}
15 +

16 +
export async function sendResetPasswordEmail(userId: number, token: string): Promise<void> {
17 +
  const user = await findUserById(userId)!;
18 +

19 +
  console.log("Email/passwdReset: ", user);
20 +

21 +
  const { data, error } = await sendEmail({
22 +
    to: user!.email,
23 +
    subject: "Esqueceu a senha do orbit?",
24 +
    text: email(user!.firstName, token)
25 +
  });
26 +

27 +
  if (error) {
28 +
    console.error("Error sending email: ", error);
29 +
  }
30 +

31 +
  console.log("Email sent successfully!");
32 +
  console.log("Email ID:", data?.id);
33 +
}