Skip to content

Commit 8aca66a

Browse files
committed
feat: verify flow
1 parent 491b8e6 commit 8aca66a

File tree

4 files changed

+99
-27
lines changed

4 files changed

+99
-27
lines changed

lib/db.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,34 @@ export async function createCode(userId: string) {
111111
userId,
112112
},
113113
});
114-
return prisma.codes.create({
114+
await prisma.codes.create({
115115
data: {
116116
userId,
117117
code,
118118
},
119119
});
120+
return code;
121+
}
122+
123+
export async function setVerifyed(id: string) {
124+
return prisma.user.update({
125+
where: {
126+
id,
127+
},
128+
data: {
129+
verifyed: true,
130+
},
131+
});
132+
}
133+
134+
export async function changePassword(id: string, newPassword: string) {
135+
const password = bcrypt.hashSync(newPassword, 12);
136+
return prisma.user.update({
137+
where: {
138+
id,
139+
},
140+
data: {
141+
password,
142+
},
143+
});
120144
}

lib/email.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,47 @@
1+
import type { User } from "@prisma/client";
12
import { Resend } from "resend";
23

3-
const resend = new Resend(process.env.RESEND_API_KEY || "");
4+
const RESEND_API_KEY = process.env.RESEND_API_KEY || "";
5+
console.log("RESEND_API_KEY", RESEND_API_KEY);
6+
const resend = new Resend(RESEND_API_KEY);
47
const SENDER_EMAIL = process.env.SENDER_EMAIL || "";
5-
const HOST = process.env.HOST || "/";
8+
const HOST = process.env.HOST_URL || "/";
9+
const APP_URL = process.env.APP_URL || "/";
610
const COPY = "Dataviz";
711

812
async function sendMail(addresses: string[], html: string) {
9-
await resend.emails.send({
13+
const obj = {
1014
from: SENDER_EMAIL,
1115
to: addresses.join(";"),
1216
subject: "Activate Account",
17+
};
18+
const result = await resend.emails.send({
19+
...obj,
1320
html,
1421
});
22+
console.log("RESULT", result);
23+
return result;
1524
}
1625

1726
function compileTemplate(template: string, data: any) {
1827
return template.replace(/\${(.*?)}/g, (_, key) => data[key]);
1928
}
2029

21-
export async function sendActivationEmail(recipeint: string, pin: string[]) {
22-
const html = activationTemplate(HOST, pin);
23-
await sendMail([recipeint], html);
30+
export function sendActivationEmail(user: User, pin: string) {
31+
const html = activationTemplate(user.id, pin);
32+
console.log("html", html);
33+
return sendMail([user.email], html);
2434
}
2535

26-
export async function sendResetPasswordEmail(recipeint: string, pin: string[]) {
27-
const html = resetTemplate(HOST, pin);
28-
await sendMail([recipeint], html);
36+
export async function sendResetPasswordEmail(user: User, pin: string) {
37+
const html = resetTemplate(user.id, pin);
38+
return sendMail([user.email], html);
2939
}
3040

31-
function resetTemplate(baseUrl: string, pin: string[]) {
32-
const url = `${baseUrl}/auth/reset?pin=${pin.join("")}`;
41+
function resetTemplate(uid: string, pin: string) {
42+
const url = `${APP_URL}/verify/${uid}?action=reset`;
3343
const code = pin
44+
.split("")
3445
.map((item: string) => {
3546
return `<span><code style="display:inline;padding:16px 4.5%;width:auto;margin:0 4px;background-color:#f4f4f4;border-radius:5px;border:1px solid #eee;color:#333">${item}</code></span>`;
3647
})
@@ -40,9 +51,10 @@ function resetTemplate(baseUrl: string, pin: string[]) {
4051
`;
4152
}
4253

43-
function activationTemplate(baseUrl: string, pin: string[]) {
44-
const url = `${baseUrl}/auth/activate?pin=${pin.join("")}`;
54+
function activationTemplate(uid: string, pin: string) {
55+
const url = `${APP_URL}/verify/${uid}?action=init`;
4556
const code = pin
57+
.split("")
4658
.map((item: string) => {
4759
return `<span><code style="display:inline;padding:16px 4.5%;width:auto;margin:0 4px;background-color:#f4f4f4;border-radius:5px;border:1px solid #eee;color:#333">${item}</code></span>`;
4860
})

prisma/schema.prisma

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ datasource db {
1414
}
1515

1616
model User {
17-
id String @id @default(cuid())
18-
email String @unique
19-
password String
20-
createdAt DateTime @default(now())
21-
updatedAt DateTime @updatedAt
17+
id String @id @default(cuid())
18+
email String @unique
19+
password String
20+
verifyed Boolean @default(false)
21+
22+
createdAt DateTime @default(now())
23+
updatedAt DateTime @updatedAt
24+
2225
Chart Chart[]
2326
Dashboard Dashboard[]
2427
}

routes/auth.ts

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import * as db from "../lib/db";
44
import { generateTokens, sendAccessToken } from "../lib/jwt";
55
import { validateRequest } from "../lib/middlewares";
66
import * as z from "zod";
7-
import generatePin from "../lib/pin";
87
import { sendActivationEmail } from "../lib/email";
98

109
const registerSchema = z.object({
@@ -47,20 +46,19 @@ router.post(
4746
}
4847
const existingUser = await db.findUserByEmail(email);
4948
if (existingUser) {
50-
res.status(400);
51-
throw new Error("Email already in use.");
49+
res.status(409);
50+
return res.json({ error: { message: "Email already in use." } });
5251
}
5352
const user = await db.createUserByEmailAndPassword({ email, password });
54-
5553
//@TODO SEND EMAIL TO ACTIVATE USER
56-
const pin = generatePin();
57-
58-
sendActivationEmail(email, pin);
54+
const pin = await db.createCode(user.id);
55+
console.log("pin", pin);
56+
await sendActivationEmail(user, pin);
5957

6058
// const { accessToken } = generateTokens(user);
6159
// sendAccessToken(res, accessToken);
6260

63-
res.json({ auth: true });
61+
return res.json({ auth: true });
6462
} catch (err) {
6563
next(err);
6664
}
@@ -113,4 +111,39 @@ router.get("/logout", (req: any, res) => {
113111
return res.status(204);
114112
});
115113

114+
router.post("/verify", (req: any, res) => {
115+
const { uid, code } = req.body;
116+
console.log("uid", uid);
117+
console.log("code", code);
118+
return res.json({ uid, code });
119+
});
120+
121+
// router.get("/mail/:uid", async (req, res) => {
122+
// const uid = req.params.uid;
123+
// const pin = await db.createCode(uid);
124+
// const email = "[email protected]";
125+
// console.log("pin", pin);
126+
// console.log("email", email);
127+
// await sendActivationEmail(email, pin);
128+
// return res.status(204);
129+
// });
130+
131+
router.get("/init", (req: any, res) => {
132+
const user = req.user;
133+
if (!user) {
134+
return res.status(400).json({ error: "User and password are required." });
135+
}
136+
return res.status(204);
137+
});
138+
139+
router.put("/pwd", async (req: any, res) => {
140+
const user = req.user;
141+
const { password } = req.body;
142+
if (!user || !password) {
143+
return res.status(400).json({ error: "User and password are required." });
144+
}
145+
await db.changePassword(user.id, password);
146+
return res.status(204);
147+
});
148+
116149
export default router;

0 commit comments

Comments
 (0)