From 2a2b3deafe37fb5f10ae9be00a81e406365b8218 Mon Sep 17 00:00:00 2001 From: Joywin Bennis <107112207+joywin2003@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:54:07 +0530 Subject: [PATCH 1/3] Refactor: grouped send and verify mail route into verification --- prisma/schema.prisma | 1 + src/app/api/{ => (verification)}/send-mail/route.ts | 0 src/app/api/{ => (verification)}/verify-mail/route.ts | 9 +++++++++ 3 files changed, 10 insertions(+) rename src/app/api/{ => (verification)}/send-mail/route.ts (100%) rename src/app/api/{ => (verification)}/verify-mail/route.ts (83%) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index de8607b..7e6171a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -81,6 +81,7 @@ model Form { name String usn String email String + emailVerified Boolean @default(false) @map("email_verified") contact String? designation String? photo String @map("photo_url") // URL of the photo uploaded by the participan diff --git a/src/app/api/send-mail/route.ts b/src/app/api/(verification)/send-mail/route.ts similarity index 100% rename from src/app/api/send-mail/route.ts rename to src/app/api/(verification)/send-mail/route.ts diff --git a/src/app/api/verify-mail/route.ts b/src/app/api/(verification)/verify-mail/route.ts similarity index 83% rename from src/app/api/verify-mail/route.ts rename to src/app/api/(verification)/verify-mail/route.ts index 2c869fc..d14484f 100644 --- a/src/app/api/verify-mail/route.ts +++ b/src/app/api/(verification)/verify-mail/route.ts @@ -27,6 +27,15 @@ export async function POST(req: NextRequest) { ); } + await prisma.form.updateMany({ + where: { + email: identifier, // Assuming identifier is the email + }, + data: { + emailVerified: true, // Mark email as verified + }, + }); + await prisma.verificationRequest.deleteMany({ where: { identifier, From 5167c4a6b764df676c4f12c41224d496b7b152de Mon Sep 17 00:00:00 2001 From: Joywin Bennis <107112207+joywin2003@users.noreply.github.com> Date: Fri, 13 Sep 2024 14:13:18 +0530 Subject: [PATCH 2/3] Fix: added prisma to ensure atomicity in verify email --- prisma/dev.db | Bin 102400 -> 102400 bytes prisma/dev.db-journal | Bin 25136 -> 25136 bytes .../20240913083428_verify/migration.sql | 25 ++++++ .../api/(verification)/verify-mail/route.ts | 80 ++++++++++-------- 4 files changed, 68 insertions(+), 37 deletions(-) create mode 100644 prisma/migrations/20240913083428_verify/migration.sql diff --git a/prisma/dev.db b/prisma/dev.db index d4a05b3574799bfede85e7191e8c44770211209a..4e681afc46700dbe1ed7a82686be20b5b73e3ad8 100644 GIT binary patch delta 491 zcmZozz}B#UZGyDmOa=x9Ngx&nVrC!~nW$sTICEpd5`HdbK0gNjLcRxlewzga9Qf)R z`I)&w8+lpH85meOEetJEf!IVhB`rBc*Tgv4RM*ldEk)PTB+Wc2$<)}u$jrVUdHtCI?1=?TiYHEDF-BxeWa0x#hX?INx!0 za`^FV=3!vX<-X2+ocs881qVh)R+ZK)3HH`B33hQ=S;p2lAT27&*ezd@n3R+1mS2<$ z!u->%eHnXsQgahCb0AL6oP3*2Yx_xGMmDDHejbb(%xpZr7!o6mr};8UOrPS-Xe^{J z$tLbB%gB(Kmy%jhT$rOSIe9&=3^&NQcta2=HqD3e7YhRe)78lvd8POf61+gMHJbyO YS1@fq@6Tu>zzP&#;Mp#a!1zHQ06y@AG5`Po delta 327 zcmZozz}B#UZGyDmR0akHNgx&nVrC!~oTy{WICW#f5`GRQz6T8ag?tY-3o2aU+x$RI zg^`1ae?0^Ldj1=m1q~MSZ(gq-xM7il00eDvU=-NSsKCggAkE>&z<-`sndcX`JXap) zJI+oHKc3Az4D3(XpKMofV02{NtRP^+DAeR4$}Vng&DbJel9-f}nwMHW{elmp2s4Z! zB;g$7>KNjx5aQ_Mv?6k k-SUfa;|)P1?`B`-HB8&j`!m`Iu!;e-@oyJMVEmvD0Fb^}2LJ#7 diff --git a/prisma/dev.db-journal b/prisma/dev.db-journal index 39b40c946dbc9d4cb430d44724941a4ca12369e7..13e174efc6a7f68a03b2e3e553e276df3b44311f 100644 GIT binary patch literal 25136 zcmeI4&2Qtz6~M*yT3$Q;*lyqoZLt8$Lw5y42|p#W1&S&%9T>G`N0!=bfqXJ^Ns1?_9+={9=TE&n(w_>PXt=rWUQLa{HVpK(2aXnJ2 zbq%HKX_~4zBC&O+TJx&9ZAiK?HMR#RG?#fbCltoz;4M`DoMU{2y z5eaOhRCHOBE1IpVt|ZI0r>TalRJ(4~ zQAEdNF7ilXbbNMwb`GLeX+O0r#39YYi)Rpp-i`tlVT!S_cEhPYdP8-`!X#DGGP~t;p{7$dBl|;5&BY4+kysa7@A|r)o19tX+S7 z-{gfH34y=6#=|A}uE4j=x7vL35K3o%pFe8t9n@R*_#c}0USTq15W%pZS5`J@kA@G( zAis&cH}V4#3j7WjqrG=vrsE{fIsvgG;#zi;Bg5~QyYB5u$j58cWwgVKYH4{883H_5n>@1o3(fwgGw8p{Qu6jLk zLg*Xi*g@hTNte_UqElN_T_ z=^Rm?W;GK$mz0>Ik*mT~`-}pugd@1rtP;m&@~U3aVy%2Ypn>=%=Sg%}jX6E%}J5;Jh$|hHbv~|XzfE=vfS8}G;){3RZ z?Rn0W>LancmmV7{u~VI!u~UU43}K@R+2@U{Q?cqRIaTtIwP4c$0>Rux=CgLBX~Q!G zt)$0!yyMZH&D?9{*KRC=ovI?SyVdizmt)w!*@$7Y*oJ);v#?q9m0&L<8J&*iyxwWB zlp8Lv*6HvmS1=$R#18kTO`W{jFd1;IoQA}@aX0~6f%%5nN*;;*#k$ZrsSceXn?+Is zyWW&)nbwpZqB`3UyH4aF%( zWACWmY~M+Gc&5E%v6W%ZzP@PBro1eP{#^d$Pq>wmByqpCV!&{U@x#7t_5G6|4)W;n zXr|^`7XD>{j49}mVCISs2UBN)bkAjE?i1%hIEK(Sb7jsHiKyof{P2Df>|aRF7%QDk z5@aTVc^&qKCvdd5bWKITVCNnT*tMMp@tTmx&I}1}b-)fGQ@t^%bjqoVIO8CINZ5+} zKAgbp{wSHDJsS0V7%z;-D74}uE7dPqiQq7L4AG~#bGbutt=za)Ed5xTx7l7coF!eZ zqvv_JUS9qC&(8h>H;eKBA3!_H1JE=7Ehtyb1AKsa0Gf+PRzMnaU>+cMEB~yhD?N*S z1=}d*0Wc3h_W+uB$c^CH<~})ZK3g0=*$Ad%w)o5qp)AXat8m+B)MFT>hE8wzwS<}uYyt8_dAZ9NI63?n_|Nky^ZeqL=gQ-J$Jxo@$FrIJ z2?TCdWU6KpZgLT27q_-%Y>_WXOv*{kOD&I|tf(T)0%HhEI0v~phPWz(I6C>bDkwq4 z6PWW$3MLCkn@v6-W;c1at{exKrmq;Ac%t=W1yu>SZnk(sm_cfiKo>~^oyO2;Cc-Wr zYs}b~nc3t3vAxLxNE;h7wun!@FRaZdF_~K=58Z}(F3n^ic5!`K#zywcyp+_6pwzU~ zqN2o{_~iVQ)cEYwN|=BM)XAZKo`IpR3Z8y0t`Q1KFj=^AB?W&!gs_r^6384S%{oDL zaYvvf+F(nHQ;Ul;^Ye=1i!&gs_>%nW)I5-NFexFd*1=@sp$vpRh`lg*puH$6lr%S= z72;rIVPIgioh+y73}HM}{>0=eHd#j1g;8=cuZHI4MAbD+lcTf@Ifa^z$N&RXjBB%Q S5VHU)kjW2WZq^9m5C8y>2CTaP diff --git a/prisma/migrations/20240913083428_verify/migration.sql b/prisma/migrations/20240913083428_verify/migration.sql new file mode 100644 index 0000000..fc3e1f0 --- /dev/null +++ b/prisma/migrations/20240913083428_verify/migration.sql @@ -0,0 +1,25 @@ +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Form" ( + "id" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL, + "usn" TEXT NOT NULL, + "email" TEXT NOT NULL, + "email_verified" BOOLEAN NOT NULL DEFAULT false, + "contact" TEXT, + "designation" TEXT, + "photo_url" TEXT NOT NULL, + "college_id_card" TEXT, + "entity_name" TEXT NOT NULL, + "referral_id" TEXT, + "created_by_id" TEXT NOT NULL, + "created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "Form_created_by_id_fkey" FOREIGN KEY ("created_by_id") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "Form_referral_id_fkey" FOREIGN KEY ("referral_id") REFERENCES "Referral" ("id") ON DELETE SET NULL ON UPDATE CASCADE +); +INSERT INTO "new_Form" ("college_id_card", "contact", "created_at", "created_by_id", "designation", "email", "entity_name", "id", "name", "photo_url", "referral_id", "usn") SELECT "college_id_card", "contact", "created_at", "created_by_id", "designation", "email", "entity_name", "id", "name", "photo_url", "referral_id", "usn" FROM "Form"; +DROP TABLE "Form"; +ALTER TABLE "new_Form" RENAME TO "Form"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/src/app/api/(verification)/verify-mail/route.ts b/src/app/api/(verification)/verify-mail/route.ts index d14484f..7b3e7d9 100644 --- a/src/app/api/(verification)/verify-mail/route.ts +++ b/src/app/api/(verification)/verify-mail/route.ts @@ -6,49 +6,55 @@ export async function POST(req: NextRequest) { const body = await req.json(); console.log(body); const { identifier, otp } = body; + try { + await prisma.$transaction(async (tx) => { + const request = await tx.verificationRequest.findFirst({ + where: { + identifier, + otp, + expires: { + gte: new Date(), + }, + }, + orderBy: { + created_at: "desc", + + }, + }); - const request = await prisma.verificationRequest.findFirst({ - where: { - identifier, - otp, - expires: { - gte: new Date(), - }, - }, - orderBy: { - created_at: "desc", - }, - }); + if (!request) { + throw new Error("Invalid or expired OTP"); + } + + await tx.form.updateMany({ + where: { + email: identifier, + }, + data: { + emailVerified: true, + }, + }); - if (!request) { + await tx.verificationRequest.deleteMany({ + where: { + identifier, + }, + }); + }); + return NextResponse.json( - { message: "Invalid or expired OTP", status: 400 }, + { + message: "OTP verified successfully back!", + status: 200, + }, + { status: 200 } + ); + } catch (error: any) { + return NextResponse.json( + { message: error.message, status: 400 }, { status: 200 } ); } - - await prisma.form.updateMany({ - where: { - email: identifier, // Assuming identifier is the email - }, - data: { - emailVerified: true, // Mark email as verified - }, - }); - - await prisma.verificationRequest.deleteMany({ - where: { - identifier, - }, - }); - - return NextResponse.json( - { - message: "OTP verified successfully back!", - status: 200, - }, - { status: 200 } - ); } export async function GET() { From d4f9d821372265d0cece21966762335c1dc68d3e Mon Sep 17 00:00:00 2001 From: Joywin Bennis <107112207+joywin2003@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:29:56 +0530 Subject: [PATCH 3/3] added middleware for admin page --- src/app/admin/page.tsx | 7 +++++++ src/middleware.ts | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/app/admin/page.tsx create mode 100644 src/middleware.ts diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx new file mode 100644 index 0000000..2297983 --- /dev/null +++ b/src/app/admin/page.tsx @@ -0,0 +1,7 @@ +import React from 'react' + +export default function page() { + return ( +
Admin Page
+ ) +} diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..3ad4bba --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,21 @@ +import { NextResponse } from "next/server"; +import type { NextRequest } from "next/server"; +export { default } from "next-auth/middleware"; +import { getToken } from "next-auth/jwt"; + +// This function can be marked `async` if using `await` inside +export async function middleware(request: NextRequest) { + const token = await getToken({ req: request }); + const url = request.nextUrl; + + if (url.pathname === "/admin") { + if (token?.role!=="ADMIN") { + return NextResponse.redirect(new URL("/", request.url)); + } + } +} + +// See "Matching Paths" below to learn more +export const config = { + matcher: ["/:path*", "/"], +}; \ No newline at end of file