104 lines
3.5 KiB
TypeScript
104 lines
3.5 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import nodemailer from 'nodemailer'
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const body = await request.json()
|
|
const { name, email, reason } = body
|
|
|
|
// Validate required fields
|
|
if (!name || !email) {
|
|
return NextResponse.json(
|
|
{ error: 'Name and email are required' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Email validation
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
if (!emailRegex.test(email)) {
|
|
return NextResponse.json(
|
|
{ error: 'Invalid email format' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
const smtpHost = process.env.SMTP_HOST
|
|
const smtpUser = process.env.SMTP_USER
|
|
const smtpPass = process.env.SMTP_PASS
|
|
if (!smtpHost || !smtpUser || !smtpPass) {
|
|
console.error('SMTP credentials not configured')
|
|
return NextResponse.json(
|
|
{ error: 'Email service not configured' },
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
|
|
const adminEmail = process.env.ADMIN_EMAIL || 'jeff@jeffemmett.com'
|
|
|
|
const transporter = nodemailer.createTransport({
|
|
host: smtpHost,
|
|
port: Number(process.env.SMTP_PORT) || 587,
|
|
secure: false,
|
|
auth: { user: smtpUser, pass: smtpPass },
|
|
tls: { rejectUnauthorized: false },
|
|
})
|
|
|
|
await transporter.sendMail({
|
|
from: `Jefflix <${smtpUser}>`,
|
|
to: adminEmail,
|
|
subject: `[Jefflix] New Access Request from ${name}`,
|
|
html: `
|
|
<h2>New Jefflix Access Request</h2>
|
|
<p>Someone has requested access to Jefflix:</p>
|
|
<table style="border-collapse: collapse; margin: 20px 0;">
|
|
<tr>
|
|
<td style="padding: 8px; font-weight: bold; border: 1px solid #ddd;">Name:</td>
|
|
<td style="padding: 8px; border: 1px solid #ddd;">${escapeHtml(name)}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 8px; font-weight: bold; border: 1px solid #ddd;">Email:</td>
|
|
<td style="padding: 8px; border: 1px solid #ddd;"><a href="mailto:${escapeHtml(email)}">${escapeHtml(email)}</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 8px; font-weight: bold; border: 1px solid #ddd;">Reason:</td>
|
|
<td style="padding: 8px; border: 1px solid #ddd;">${escapeHtml(reason || 'Not provided')}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 8px; font-weight: bold; border: 1px solid #ddd;">Requested:</td>
|
|
<td style="padding: 8px; border: 1px solid #ddd;">${new Date().toLocaleString()}</td>
|
|
</tr>
|
|
</table>
|
|
<p>To approve this request:</p>
|
|
<ol>
|
|
<li>Go to <a href="https://movies.jefflix.lol">Jellyfin Dashboard</a></li>
|
|
<li>Navigate to Dashboard → Users → Add User</li>
|
|
<li>Create an account for ${escapeHtml(name)} (${escapeHtml(email)})</li>
|
|
<li>Reply to this email to let them know their account is ready</li>
|
|
</ol>
|
|
<hr style="margin: 20px 0; border: none; border-top: 1px solid #ddd;" />
|
|
<p style="color: #666; font-size: 12px;">This is an automated message from Jefflix.</p>
|
|
`,
|
|
})
|
|
|
|
return NextResponse.json({ success: true })
|
|
} catch (error) {
|
|
console.error('Request access error:', error)
|
|
return NextResponse.json(
|
|
{ error: 'Internal server error' },
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|
|
|
|
function escapeHtml(text: string): string {
|
|
const map: Record<string, string> = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": ''',
|
|
}
|
|
return text.replace(/[&<>"']/g, (char) => map[char])
|
|
}
|