Initial commit: Lageplan v1.0 - Next.js 15.5, React 19

This commit is contained in:
Pepe Ziberi
2026-02-21 11:57:44 +01:00
commit adf3dc8c1d
167 changed files with 34265 additions and 0 deletions

111
src/lib/email.ts Normal file
View File

@@ -0,0 +1,111 @@
import nodemailer from 'nodemailer'
import { prisma } from './db'
export interface SmtpConfig {
host: string
port: number
secure: boolean
user: string
pass: string
fromName: string
fromEmail: string
}
// Get SMTP settings from DB (SystemSetting table)
export async function getSmtpConfig(): Promise<SmtpConfig | null> {
try {
const settings = await (prisma as any).systemSetting.findMany({
where: { category: 'smtp' },
})
if (!settings || settings.length === 0) return null
const map: Record<string, string> = {}
for (const s of settings) {
map[s.key] = s.value
}
if (!map['smtp_host'] || !map['smtp_user']) return null
return {
host: map['smtp_host'],
port: parseInt(map['smtp_port'] || '587'),
secure: map['smtp_secure'] === 'true',
user: map['smtp_user'],
pass: map['smtp_pass'] || '',
fromName: map['smtp_from_name'] || 'Lageplan',
fromEmail: map['smtp_from_email'] || map['smtp_user'],
}
} catch {
return null
}
}
// Save SMTP settings to DB
export async function saveSmtpConfig(config: Partial<SmtpConfig>): Promise<void> {
const entries: { key: string; value: string; isSecret: boolean }[] = []
if (config.host !== undefined) entries.push({ key: 'smtp_host', value: config.host, isSecret: false })
if (config.port !== undefined) entries.push({ key: 'smtp_port', value: String(config.port), isSecret: false })
if (config.secure !== undefined) entries.push({ key: 'smtp_secure', value: String(config.secure), isSecret: false })
if (config.user !== undefined) entries.push({ key: 'smtp_user', value: config.user, isSecret: false })
if (config.pass !== undefined) entries.push({ key: 'smtp_pass', value: config.pass, isSecret: true })
if (config.fromName !== undefined) entries.push({ key: 'smtp_from_name', value: config.fromName, isSecret: false })
if (config.fromEmail !== undefined) entries.push({ key: 'smtp_from_email', value: config.fromEmail, isSecret: false })
for (const entry of entries) {
await (prisma as any).systemSetting.upsert({
where: { key: entry.key },
update: { value: entry.value, isSecret: entry.isSecret },
create: { key: entry.key, value: entry.value, isSecret: entry.isSecret, category: 'smtp' },
})
}
}
// Create nodemailer transport from DB settings
async function createTransport() {
const config = await getSmtpConfig()
if (!config) throw new Error('SMTP nicht konfiguriert')
return nodemailer.createTransport({
host: config.host,
port: config.port,
secure: config.secure,
auth: {
user: config.user,
pass: config.pass,
},
tls: {
rejectUnauthorized: false,
},
})
}
// Send email
export async function sendEmail(to: string, subject: string, html: string): Promise<boolean> {
try {
const config = await getSmtpConfig()
if (!config) throw new Error('SMTP nicht konfiguriert')
const transport = await createTransport()
await transport.sendMail({
from: `"${config.fromName}" <${config.fromEmail}>`,
to,
subject,
html,
})
return true
} catch (error) {
console.error('Email send error:', error)
throw error
}
}
// Test SMTP connection
export async function testSmtpConnection(): Promise<{ success: boolean; error?: string }> {
try {
const transport = await createTransport()
await transport.verify()
return { success: true }
} catch (error) {
return { success: false, error: error instanceof Error ? error.message : 'Verbindung fehlgeschlagen' }
}
}