Some checks failed
CI / skip-ci-check (pull_request) Successful in 1m19s
CI / lint-and-type-check (pull_request) Failing after 1m37s
CI / test (pull_request) Successful in 2m16s
CI / build (pull_request) Failing after 1m46s
CI / secret-scanning (pull_request) Successful in 1m20s
CI / dependency-scan (pull_request) Successful in 1m27s
CI / sast-scan (pull_request) Successful in 2m29s
CI / workflow-summary (pull_request) Successful in 1m18s
- Add duplicate photo detection (file hash and URL checking) - Add max attempts per photo with UI counter - Simplify penalty system (auto-enable when points > 0) - Prevent scores from going below 0 - Add admin photo deletion functionality - Improve navigation with always-visible logout - Prevent users from guessing their own photos
114 lines
3.5 KiB
TypeScript
114 lines
3.5 KiB
TypeScript
import nodemailer from "nodemailer"
|
|
|
|
let transporter: nodemailer.Transporter | null = null
|
|
|
|
async function getTransporter() {
|
|
if (transporter) return transporter
|
|
|
|
// In development, use Ethereal or console transport
|
|
if (process.env.NODE_ENV === "development") {
|
|
// Try to use Ethereal for testing
|
|
try {
|
|
const testAccount = await nodemailer.createTestAccount()
|
|
transporter = nodemailer.createTransport({
|
|
host: "smtp.ethereal.email",
|
|
port: 587,
|
|
secure: false,
|
|
auth: {
|
|
user: testAccount.user,
|
|
pass: testAccount.pass,
|
|
},
|
|
})
|
|
return transporter
|
|
} catch {
|
|
// Fallback to console transport
|
|
transporter = nodemailer.createTransport({
|
|
streamTransport: true,
|
|
newline: "unix",
|
|
buffer: true,
|
|
})
|
|
return transporter
|
|
}
|
|
}
|
|
|
|
// Production: use SMTP
|
|
transporter = nodemailer.createTransport({
|
|
host: process.env.SMTP_HOST,
|
|
port: parseInt(process.env.SMTP_PORT || "587"),
|
|
secure: process.env.SMTP_PORT === "465",
|
|
auth: {
|
|
user: process.env.SMTP_USER,
|
|
pass: process.env.SMTP_PASSWORD,
|
|
},
|
|
})
|
|
|
|
return transporter
|
|
}
|
|
|
|
export async function sendNewPhotoEmail(
|
|
recipientEmail: string,
|
|
recipientName: string,
|
|
photoId: string,
|
|
uploaderName: string
|
|
) {
|
|
const emailTransporter = await getTransporter()
|
|
const baseUrl = process.env.NEXTAUTH_URL || "http://localhost:3000"
|
|
const photoUrl = `${baseUrl}/photos/${photoId}`
|
|
|
|
const mailOptions = {
|
|
from: process.env.SMTP_FROM || "MirrorMatch <noreply@mirrormatch.com>",
|
|
to: recipientEmail,
|
|
subject: "New Photo Ready to Guess!",
|
|
html: `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
</head>
|
|
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 30px; text-align: center; border-radius: 10px 10px 0 0;">
|
|
<h1 style="color: white; margin: 0;">MirrorMatch</h1>
|
|
</div>
|
|
<div style="background: #f9f9f9; padding: 30px; border-radius: 0 0 10px 10px;">
|
|
<h2 style="color: #667eea; margin-top: 0;">New Photo Uploaded!</h2>
|
|
<p>Hi ${recipientName},</p>
|
|
<p><strong>${uploaderName}</strong> has uploaded a new photo for you to guess!</p>
|
|
<p style="margin: 30px 0;">
|
|
<a href="${photoUrl}" style="background: #667eea; color: white; padding: 12px 30px; text-decoration: none; border-radius: 5px; display: inline-block;">View Photo & Guess</a>
|
|
</p>
|
|
<p style="color: #666; font-size: 14px; margin-top: 30px;">
|
|
Good luck! 🎯
|
|
</p>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
`,
|
|
text: `
|
|
Hi ${recipientName},
|
|
|
|
${uploaderName} has uploaded a new photo for you to guess!
|
|
|
|
View the photo and submit your guess here: ${photoUrl}
|
|
|
|
Good luck!
|
|
`.trim(),
|
|
}
|
|
|
|
try {
|
|
const info = await emailTransporter.sendMail(mailOptions)
|
|
|
|
if (process.env.NODE_ENV === "development") {
|
|
console.log("Email sent (dev mode):")
|
|
console.log("Preview URL:", nodemailer.getTestMessageUrl(info) || "Check console")
|
|
console.log("To:", recipientEmail)
|
|
console.log("Subject:", mailOptions.subject)
|
|
}
|
|
|
|
return info
|
|
} catch (error) {
|
|
console.error("Error sending email:", error)
|
|
throw error
|
|
}
|
|
}
|