Skip to content

Commit

Permalink
Merge pull request #13 from TEDx-SJEC/email
Browse files Browse the repository at this point in the history
Added emailing feature with code and bug imporvements
  • Loading branch information
joywin2003 authored Sep 18, 2024
2 parents 1712dca + 45e4284 commit b7e0af3
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 74 deletions.
6 changes: 0 additions & 6 deletions jest.config.js

This file was deleted.

98 changes: 57 additions & 41 deletions src/app/api/(verification)/send-mail/route.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,69 @@
import { MailUsingResend } from "@/lib/resend-mailer";
import prisma from "@/server/db";
import getErrorMessage from "@/utils/getErrorMessage";
import { emailSchema } from "@/utils/zod-schemas";
import { NextRequest, NextResponse } from "next/server";
import sendEmail from "@/lib/sendMail";
import otpGenerator from "otp-generator";
import prisma from "@/server/db";
import { addToQueue } from "@/jobs";
import { MailUsingResend } from "@/lib/resend-mailer";
import { z } from "zod";

export async function POST(req: NextRequest) {
const body = await req.json();
const otp = otpGenerator.generate(6, {
upperCaseAlphabets: false,
lowerCaseAlphabets: false,
specialChars: false,
});

const expiresIn = 10; // 10 minutes
const expiresAt = new Date(Date.now() + expiresIn * 60 * 1000);

await prisma.verificationRequest.create({
data: {
identifier: body.email,
otp,
expires: expiresAt,
},
});
if (!body.email) {
try {
const body = await req.json();
const parsedBody = emailSchema.parse(body);

const otp = otpGenerator.generate(6, {
upperCaseAlphabets: false,
lowerCaseAlphabets: false,
specialChars: false,
});

const expiresIn = 10; // OTP valid for 10 minutes
const expiresAt = new Date(Date.now() + expiresIn * 60 * 1000);

await prisma.verificationRequest.create({
data: {
identifier: parsedBody.email,
otp,
expires: expiresAt,
},
});

const mailResponse = await MailUsingResend({
email: parsedBody.email,
name: parsedBody.name,
OTP: otp,
});

// const mailResponse1 = await addToQueue({
// email: parsedBody.email,
// name: parsedBody.name,
// OTP: otp,
// })

return NextResponse.json({
message: "Email sent successfully!",
mailResponse,
});

} catch (error:unknown) {
const errorMessage = getErrorMessage(error);

if (error instanceof z.ZodError) {
return NextResponse.json(
{ message: "Validation error", errors: errorMessage },
{ status: 400 }
);
}

// Handle general server errors
return NextResponse.json(
{ message: "No recipients defined", status: 400 },
{ status: 400 }
{ message: "Internal Server Error", errorMessage },
{ status: 500 }
);
}
console.log(body);
// const mailResponse1 = await addToQueue({
// email: body.email,
// name: body.name,
// OTP: otp,
// });
const mailResponse2 = await MailUsingResend({
email: body.email,
name: body.name,
OTP: otp,
});

return NextResponse.json({
message: "Email sent successfully!",
// mailResponse1,
mailResponse2,
});
}

// Test endpoint
export async function GET() {
return NextResponse.json({ message: "Hello from the Send mail!" });
}
26 changes: 17 additions & 9 deletions src/app/api/(verification)/verify-mail/route.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { NextRequest, NextResponse } from "next/server";
import prisma from "@/server/db";
import getErrorMessage from "@/utils/getErrorMessage";
import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
const body = await req.json();
console.log(body);
const { identifier, otp } = body;
if (!identifier || !otp) {
return NextResponse.json(
{ message: "Identifier and OTP are required", status: 400 },
{ status: 400 }
);
}
try {
await prisma.$transaction(async (tx) => {
const request = await tx.verificationRequest.findFirst({
Expand All @@ -17,20 +24,19 @@ export async function POST(req: NextRequest) {
},
orderBy: {
created_at: "desc",

},
});

if (!request) {
throw new Error("Invalid or expired OTP");
throw new Error("Verification failed: Invalid or expired OTP");
}

await tx.form.updateMany({
where: {
email: identifier,
email: identifier,
},
data: {
emailVerified: true,
emailVerified: true,
},
});

Expand All @@ -40,18 +46,20 @@ export async function POST(req: NextRequest) {
},
});
});

return NextResponse.json(
{
message: "OTP verified successfully back!",
status: 200,
},
{ status: 200 }
);
} catch (error: any) {
} catch (error: unknown) {
const errorMessage = getErrorMessage(error);
console.error("OTP verification failed:", errorMessage);
return NextResponse.json(
{ message: error.message, status: 400 },
{ status: 200 }
{ message: errorMessage, status: 400 },
{ status: 400 }
);
}
}
Expand Down
57 changes: 42 additions & 15 deletions src/app/api/users/route.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,47 @@
import prisma from "@/server/db";

import { NextResponse } from "next/server";

export async function GET(req: Request) {
const { searchParams } = new URL(req.url);
const page = parseInt(searchParams.get("page") || "1");
const search = searchParams.get("search") || "";
const limit = 10;
try {
const { searchParams } = new URL(req.url);

const page = Math.max(1, parseInt(searchParams.get("page") || "1", 10));
const search = searchParams.get("search") || "";
const limit = 10;

const [users, totalCount] = await Promise.all([
prisma.user.findMany({
skip: (page - 1) * limit,
take: limit,
where: {
name: {
contains: search,
},
},
}),
prisma.user.count({ // Get the total number of users for pagination
where: {
name: {
contains: search,
},
},
})
]);

const totalPages = Math.ceil(totalCount / limit);

return NextResponse.json({
users,
pagination: {
currentPage: page,
totalPages,
totalCount,
limit
}
});

const users = await prisma.user.findMany({
skip: (page - 1) * limit,
take: limit,
where: {
name: {
contains: search,
},
},
});
return NextResponse.json({ users });
} catch (error) {
console.error("Failed to fetch users:", error);
return NextResponse.json({ message: "Failed to fetch users", status: 500 }, { status: 500 });
}
}
2 changes: 1 addition & 1 deletion src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export async function middleware(request: NextRequest) {
const token = await getToken({ req: request });
const url = request.nextUrl;

if (url.pathname === "/admin") {
if (url.pathname.startsWith("/admin")) {
if (token?.role!=="ADMIN") {
return NextResponse.redirect(new URL("/", request.url));
}
Expand Down
9 changes: 7 additions & 2 deletions src/utils/getErrorMessage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { z } from "zod";

const getErrorMessage = (error: unknown): string => {
let message: string;

if (error instanceof Error) {
if (error instanceof z.ZodError) {
message = error.errors
.map((err) => `${err.path.join(".")} - ${err.message}`)
.join(", ");
} else if (error instanceof Error) {
message = error.message;
} else if (error && typeof error === "object" && "message" in error) {
message = String(error.message);
Expand Down
6 changes: 6 additions & 0 deletions src/utils/zod-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ export const RegistrationFormSchema = z.object({
});

export type TRegistrationForm = z.infer<typeof RegistrationFormSchema>;


export const emailSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
});

0 comments on commit b7e0af3

Please sign in to comment.