import fs from 'fs/promises'
import path from 'path'
import { getUserFromToken, hasAnyRole } from '../../../utils/auth.js'
import { getRecipientsByGroup, getNewsletterSubscribers, generateUnsubscribeToken } from '../../../utils/newsletter.js'
import nodemailer from 'nodemailer'
const getDataPath = (filename) => {
const cwd = process.cwd()
if (cwd.endsWith('.output')) {
return path.join(cwd, '../server/data', filename)
}
return path.join(cwd, 'server/data', filename)
}
const NEWSLETTERS_FILE = getDataPath('newsletters.json')
async function readNewsletters() {
try {
const data = await fs.readFile(NEWSLETTERS_FILE, 'utf-8')
return JSON.parse(data)
} catch (error) {
if (error.code === 'ENOENT') {
return []
}
throw error
}
}
async function writeNewsletters(newsletters) {
await fs.writeFile(NEWSLETTERS_FILE, JSON.stringify(newsletters, null, 2), 'utf-8')
}
// Lädt Config für Logo und Clubname
async function loadConfig() {
try {
const configPath = getDataPath('config.json')
const data = await fs.readFile(configPath, 'utf-8')
return JSON.parse(data)
} catch {
return {
verein: { name: 'Harheimer Tischtennis-Club 1954 e.V.' }
}
}
}
// Erstellt Newsletter-HTML mit Header und Footer
async function createNewsletterHTML(newsletter, unsubscribeToken = null) {
const config = await loadConfig()
const clubName = config.verein?.name || 'Harheimer Tischtennis-Club 1954 e.V.'
const baseUrl = process.env.NUXT_PUBLIC_BASE_URL || 'http://localhost:3100'
let unsubscribeLink = ''
if (unsubscribeToken) {
const unsubscribeUrl = `${baseUrl}/newsletter/unsubscribe?token=${unsubscribeToken}`
unsubscribeLink = `
Sie erhalten diese E-Mail, weil Sie sich für unseren Newsletter angemeldet haben.
Newsletter abmelden
`
}
return `
${clubName}
|
${newsletter.title}
${newsletter.content}
${unsubscribeLink}
|
|
${clubName}
${baseUrl}
|
|
`
}
export default defineEventHandler(async (event) => {
try {
// Authentifizierung prüfen
const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace('Bearer ', '')
if (!token) {
throw createError({
statusCode: 401,
statusMessage: 'Nicht authentifiziert'
})
}
const user = await getUserFromToken(token)
if (!user || !hasAnyRole(user, 'admin', 'vorstand', 'newsletter')) {
throw createError({
statusCode: 403,
statusMessage: 'Keine Berechtigung'
})
}
const newsletterId = getRouterParam(event, 'id')
const newsletters = await readNewsletters()
const newsletterIndex = newsletters.findIndex(n => n.id === newsletterId)
if (newsletterIndex === -1) {
throw createError({
statusCode: 404,
statusMessage: 'Newsletter nicht gefunden'
})
}
const newsletter = newsletters[newsletterIndex]
if (newsletter.status === 'sent') {
throw createError({
statusCode: 400,
statusMessage: 'Newsletter wurde bereits versendet'
})
}
// Prüfe ob Newsletter Inhalt hat
if (!newsletter.content || newsletter.content.trim() === '' || newsletter.content === '
') {
throw createError({
statusCode: 400,
statusMessage: 'Newsletter hat keinen Inhalt. Bitte fügen Sie Inhalte hinzu, bevor Sie den Newsletter versenden.'
})
}
// SMTP-Credentials prüfen
const smtpUser = process.env.SMTP_USER
const smtpPass = process.env.SMTP_PASS
if (!smtpUser || !smtpPass) {
throw createError({
statusCode: 500,
statusMessage: 'SMTP-Credentials fehlen! Bitte setzen Sie SMTP_USER und SMTP_PASS in der .env Datei.'
})
}
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST || 'smtp.gmail.com',
port: process.env.SMTP_PORT || 587,
secure: false,
auth: {
user: smtpUser,
pass: smtpPass
}
})
// Empfänger bestimmen
let recipients = []
if (newsletter.type === 'subscription') {
// Abonnenten-Newsletter
recipients = await getNewsletterSubscribers(!newsletter.sendToExternal)
} else if (newsletter.type === 'group') {
// Gruppen-Newsletter
recipients = await getRecipientsByGroup(newsletter.targetGroup)
}
if (recipients.length === 0) {
throw createError({
statusCode: 400,
statusMessage: 'Keine Empfänger gefunden'
})
}
// Newsletter versenden
let sentCount = 0
let failedCount = 0
const failedEmails = []
for (const recipient of recipients) {
try {
// Abmelde-Token generieren (nur für Abonnenten-Newsletter)
let unsubscribeToken = null
if (newsletter.type === 'subscription') {
unsubscribeToken = await generateUnsubscribeToken(recipient.email)
}
const htmlContent = await createNewsletterHTML(newsletter, unsubscribeToken)
await transporter.sendMail({
from: process.env.SMTP_FROM || 'noreply@harheimertc.de',
to: recipient.email,
subject: newsletter.title,
html: htmlContent
})
sentCount++
} catch (error) {
console.error(`Fehler beim Senden an ${recipient.email}:`, error)
failedCount++
failedEmails.push(recipient.email)
}
}
// Newsletter als versendet markieren
newsletters[newsletterIndex].status = 'sent'
newsletters[newsletterIndex].sentAt = new Date().toISOString()
newsletters[newsletterIndex].sentTo = {
total: recipients.length,
sent: sentCount,
failed: failedCount,
failedEmails: failedEmails.length > 0 ? failedEmails : undefined
}
await writeNewsletters(newsletters)
return {
success: true,
message: `Newsletter erfolgreich versendet`,
stats: {
total: recipients.length,
sent: sentCount,
failed: failedCount,
failedEmails: failedEmails.length > 0 ? failedEmails : undefined
}
}
} catch (error) {
console.error('Fehler beim Versenden des Newsletters:', error)
if (error.statusCode) {
throw error
}
throw createError({
statusCode: 500,
statusMessage: error.message || 'Fehler beim Versenden des Newsletters'
})
}
})