- Register internalRoutes at /api/auth/internal (used by management) - Add registerRoutes for staff self-registration flow - Add workforce sync job (runs on schedule, fails gracefully if unconfigured) - Add email.js for registration/invite emails Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
61 lines
2.4 KiB
JavaScript
61 lines
2.4 KiB
JavaScript
import nodemailer from 'nodemailer'
|
|
|
|
const SETTINGS_URL = process.env.SETTINGS_URL || 'http://10.10.10.106:3080'
|
|
const SETTINGS_SECRET = process.env.SETTINGS_SECRET || ''
|
|
|
|
let _smtpCache = null // { config, expires_at }
|
|
let _transporter = null
|
|
|
|
async function getSmtpConfig() {
|
|
if (_smtpCache && Date.now() < _smtpCache.expires_at) return _smtpCache.config
|
|
const res = await fetch(`${SETTINGS_URL}/settings/api/internal/integration/smtp`, {
|
|
headers: { Authorization: `Bearer ${SETTINGS_SECRET}` },
|
|
signal: AbortSignal.timeout(5000),
|
|
})
|
|
if (!res.ok) throw new Error(`Failed to fetch SMTP config from settings: ${res.status}`)
|
|
const config = await res.json()
|
|
if (!config.host) throw new Error('SMTP not configured in settings')
|
|
_smtpCache = { config, expires_at: Date.now() + 5 * 60_000 }
|
|
_transporter = null // force transporter rebuild on next send
|
|
return config
|
|
}
|
|
|
|
async function getTransporter() {
|
|
if (_transporter) return _transporter
|
|
const config = await getSmtpConfig()
|
|
const port = parseInt(config.port || '587')
|
|
_transporter = nodemailer.createTransport({
|
|
host: config.host,
|
|
port,
|
|
secure: port === 465,
|
|
auth: config.user ? { user: config.user, pass: config.pass } : undefined,
|
|
})
|
|
return _transporter
|
|
}
|
|
|
|
export async function sendPinEmail(to, name, pin) {
|
|
const config = await getSmtpConfig()
|
|
const transport = await getTransporter()
|
|
const from = config.from || '"Hotel Number Four" <noreply@hotelnumberfour.com>'
|
|
|
|
await transport.sendMail({
|
|
from,
|
|
to,
|
|
subject: 'Your Hotel Number Four verification code',
|
|
text: `Hi ${name},\n\nYour staff portal verification code is: ${pin}\n\nThis code expires in 15 minutes.\n\nIf you did not request this, please ignore this email.`,
|
|
html: `
|
|
<div style="font-family:sans-serif;max-width:480px;margin:0 auto;padding:2rem">
|
|
<h2 style="color:#1e3a5f;margin:0 0 1rem">Hotel Number Four</h2>
|
|
<p>Hi ${name},</p>
|
|
<p>Your staff portal verification code is:</p>
|
|
<div style="font-size:2.5rem;font-weight:700;letter-spacing:0.3em;color:#1e3a5f;
|
|
background:#f3f4f6;padding:1rem 2rem;border-radius:8px;
|
|
text-align:center;margin:1.5rem 0">${pin}</div>
|
|
<p style="color:#6b7280;font-size:0.875rem">
|
|
This code expires in 15 minutes.<br>
|
|
If you did not request access to the staff portal, please ignore this email.
|
|
</p>
|
|
</div>
|
|
`,
|
|
})
|
|
}
|