feature: nodemailer set

This commit is contained in:
Anushlinux
2025-09-03 18:54:55 +05:30
parent 972ed81192
commit 425475c027
9 changed files with 1235 additions and 21 deletions

View File

@@ -1,6 +1,8 @@
import { db, applications } from '@workspace/db';
import { db, applications, students } from '@workspace/db';
import { eq } from '@workspace/db/drizzle';
import { NextRequest, NextResponse } from 'next/server';
import { sendEmail } from '@/lib/mailer';
import { statusUpdateHtml, statusUpdateSubject, statusUpdateText } from '@/lib/mail-templates';
export async function PATCH(req: NextRequest, { params }: { params: Promise<{ applicationId: string }> }) {
const { applicationId: applicationIdParam } = await params;
@@ -9,18 +11,63 @@ export async function PATCH(req: NextRequest, { params }: { params: Promise<{ ap
return NextResponse.json({ error: 'Invalid applicationId' }, { status: 400 });
}
const { status } = await req.json();
const { status, studentId, notify } = await req.json();
if (!status) {
return NextResponse.json({ error: 'Missing status' }, { status: 400 });
}
const result = await db.update(applications)
.set({ status })
.where(eq(applications.id, applicationId));
let result;
try {
result = await db
.update(applications)
.set({ status })
.where(eq(applications.id, applicationId));
} catch (e) {
const message = e instanceof Error ? e.message : 'Unknown database error';
return NextResponse.json({ error: 'Database update failed', detail: message }, { status: 500 });
}
if (result.rowCount === 0) {
if (!result || result.rowCount === 0) {
return NextResponse.json({ error: 'Application not found' }, { status: 404 });
}
return NextResponse.json({ success: true });
const shouldNotify = notify === undefined ? true : Boolean(notify);
let emailError: string | undefined;
let notified = false;
try {
if (shouldNotify) {
// studentId is provided by client components; if missing, try to infer
let effectiveStudentId: number | null = Number.isFinite(Number(studentId)) && Number(studentId) > 0 ? Number(studentId) : null;
if (!effectiveStudentId) {
const app = await db.query.applications.findFirst({
where: eq(applications.id, applicationId),
columns: { studentId: true },
});
effectiveStudentId = app?.studentId ?? null;
}
if (effectiveStudentId) {
const student = await db.query.students.findFirst({
where: eq(students.id, effectiveStudentId),
columns: { email: true, firstName: true, lastName: true },
});
if (student?.email) {
const name = `${student.firstName ?? ''} ${student.lastName ?? ''}`.trim() || 'Student';
await sendEmail({
to: student.email,
subject: statusUpdateSubject(status),
text: statusUpdateText(name, status),
html: statusUpdateHtml(name, status),
});
notified = true;
}
}
}
} catch (err) {
emailError = err instanceof Error ? err.message : 'Unknown email error';
console.error('Failed to send status update email', { applicationId, status, error: emailError });
}
return NextResponse.json({ success: true, emailError: emailError ?? null, notified });
}

View File

@@ -1,15 +1,43 @@
import { NextResponse } from 'next/server'
import { getMailer } from '@/lib/mailer'
import { db } from '@workspace/db'
import { sql } from '@workspace/db/drizzle'
export async function GET() {
try {
// You can add additional health checks here
// For example, database connectivity, external service checks, etc.
const envSeen = {
SMTP_URL: Boolean(process.env.SMTP_URL || process.env.MAIL_URL),
SMTP_HOST: Boolean(process.env.SMTP_HOST || process.env.MAIL_HOST),
SMTP_PORT: Boolean(process.env.SMTP_PORT || process.env.MAIL_PORT),
SMTP_USER: Boolean(process.env.SMTP_USER || process.env.SMTP_USERNAME || process.env.MAIL_USER || process.env.MAIL_USERNAME),
SMTP_PASS: Boolean(process.env.SMTP_PASS || process.env.SMTP_PASSWORD || process.env.MAIL_PASS || process.env.MAIL_PASSWORD),
SMTP_FROM: Boolean(process.env.SMTP_FROM),
}
let smtp: { ok: boolean; message?: string } = { ok: false }
try {
await getMailer().verify()
smtp = { ok: true }
} catch (e) {
smtp = { ok: false, message: e instanceof Error ? e.message : 'unknown error' }
}
let database: { ok: boolean; message?: string } = { ok: false }
try {
await db.execute(sql`select 1`)
database = { ok: true }
} catch (e) {
database = { ok: false, message: e instanceof Error ? e.message : 'unknown error' }
}
return NextResponse.json(
{
status: 'ok',
timestamp: new Date().toISOString(),
service: 'admin-app'
service: 'admin-app',
smtp,
database,
envSeen
},
{ status: 200 }
)