diff --git a/backend/migrations/020_ensure_default_email_templates.js b/backend/migrations/020_ensure_default_email_templates.js index 3e0892e..e11a0a6 100644 --- a/backend/migrations/020_ensure_default_email_templates.js +++ b/backend/migrations/020_ensure_default_email_templates.js @@ -3,11 +3,20 @@ exports.up = async function(knex) { const templates = await knex('email_templates').select('template_key'); const existingKeys = templates.map(t => t.template_key); + // Check which columns exist in the table + const hasSubjectEn = await knex.schema.hasColumn('email_templates', 'subject_en'); + const hasSubject = await knex.schema.hasColumn('email_templates', 'subject'); + + // Determine which columns to use based on schema + const subjectCol = hasSubjectEn ? 'subject_en' : 'subject'; + const bodyHtmlCol = hasSubjectEn ? 'body_html_en' : 'body_html'; + const bodyTextCol = hasSubjectEn ? 'body_text_en' : 'body_text'; + const defaultTemplates = [ { template_key: 'gallery_created', - subject: 'Your Photo Gallery is Ready!', - body_html: `
Dear {{host_name}},
Your photo gallery "{{event_name}}" has been created successfully!
Gallery Details:
@@ -18,39 +27,39 @@ exports.up = async function(knex) {Share this link and password with your guests to allow them to view and download photos.
`, - body_text: 'Gallery Created Successfully\n\nDear {{host_name}},\n\nYour photo gallery "{{event_name}}" has been created successfully!', + [bodyTextCol]: 'Gallery Created Successfully\n\nDear {{host_name}},\n\nYour photo gallery "{{event_name}}" has been created successfully!', variables: JSON.stringify(['host_name', 'event_name', 'event_date', 'gallery_link', 'gallery_password', 'expiry_date']) }, { template_key: 'expiration_warning', - subject: 'Your Photo Gallery Expires Soon', - body_html: `Dear {{host_name}},
Your photo gallery "{{event_name}}" will expire in {{days_remaining}} days.
After expiration, the gallery will be archived and no longer accessible to guests.
`, - body_text: 'Gallery Expiring Soon\n\nDear {{host_name}},\n\nYour photo gallery "{{event_name}}" will expire in {{days_remaining}} days.', + [bodyTextCol]: 'Gallery Expiring Soon\n\nDear {{host_name}},\n\nYour photo gallery "{{event_name}}" will expire in {{days_remaining}} days.', variables: JSON.stringify(['host_name', 'event_name', 'days_remaining', 'gallery_link']) }, { template_key: 'gallery_expired', - subject: 'Your Photo Gallery Has Expired', - body_html: `Dear {{host_name}},
Your photo gallery "{{event_name}}" has expired and been archived.
The photos are safely stored in our archive system. If you need access to the archived photos, please contact support.
`, - body_text: 'Gallery Expired\n\nDear {{host_name}},\n\nYour photo gallery "{{event_name}}" has expired and been archived.', + [bodyTextCol]: 'Gallery Expired\n\nDear {{host_name}},\n\nYour photo gallery "{{event_name}}" has expired and been archived.', variables: JSON.stringify(['host_name', 'event_name']) }, { template_key: 'archive_complete', - subject: 'Gallery Archive Complete', - body_html: `Dear {{host_name}},
Your photo gallery "{{event_name}}" has been successfully archived.
Archive size: {{archive_size}}
The archive is stored securely and can be retrieved if needed.
`, - body_text: 'Archive Complete\n\nDear {{host_name}},\n\nYour photo gallery "{{event_name}}" has been successfully archived.', + [bodyTextCol]: 'Archive Complete\n\nDear {{host_name}},\n\nYour photo gallery "{{event_name}}" has been successfully archived.', variables: JSON.stringify(['host_name', 'event_name', 'archive_size']) } ]; @@ -58,6 +67,20 @@ exports.up = async function(knex) { // Insert missing templates for (const template of defaultTemplates) { if (!existingKeys.includes(template.template_key)) { + // If we have language columns, also set German versions with same content + if (hasSubjectEn) { + template.subject_de = template[subjectCol]; + template.body_html_de = template[bodyHtmlCol]; + template.body_text_de = template[bodyTextCol]; + + // Also ensure we have the basic columns if they exist + if (hasSubject) { + template.subject = template[subjectCol]; + template.body_html = template[bodyHtmlCol]; + template.body_text = template[bodyTextCol]; + } + } + await knex('email_templates').insert(template); } } diff --git a/backend/src/routes/adminEmail.js b/backend/src/routes/adminEmail.js index a8fe5f5..cc25e52 100644 --- a/backend/src/routes/adminEmail.js +++ b/backend/src/routes/adminEmail.js @@ -193,20 +193,34 @@ router.get('/templates/:key', adminAuth, async (req, res) => { return res.status(404).json({ error: 'Template not found' }); } - res.json({ + // Handle both old and new schema formats + const response = { id: template.id, template_key: template.template_key, - // English versions - subject_en: template.subject_en || template.subject, - body_html_en: template.body_html_en || template.body_html, - body_text_en: template.body_text_en || template.body_text, - // German versions - subject_de: template.subject_de || template.subject_en || template.subject, - body_html_de: template.body_html_de || template.body_html_en || template.body_html, - body_text_de: template.body_text_de || template.body_text_en || template.body_text, variables: template.variables ? JSON.parse(template.variables) : [], updated_at: template.updated_at - }); + }; + + // Check which columns exist and use them appropriately + if (template.subject_en !== undefined) { + // New schema with language columns + response.subject_en = template.subject_en; + response.body_html_en = template.body_html_en; + response.body_text_en = template.body_text_en; + response.subject_de = template.subject_de; + response.body_html_de = template.body_html_de; + response.body_text_de = template.body_text_de; + } else { + // Old schema - use basic columns for both languages + response.subject_en = template.subject; + response.body_html_en = template.body_html; + response.body_text_en = template.body_text; + response.subject_de = template.subject; + response.body_html_de = template.body_html; + response.body_text_de = template.body_text; + } + + res.json(response); } catch (error) { console.error('Email template fetch error:', error); res.status(500).json({ error: 'Failed to fetch email template' }); @@ -237,13 +251,39 @@ router.put('/templates/:key', [ updated_at: new Date() }; - // Only update provided fields - if (subject_en !== undefined) updateData.subject_en = subject_en; - if (subject_de !== undefined) updateData.subject_de = subject_de; - if (body_html_en !== undefined) updateData.body_html_en = body_html_en; - if (body_html_de !== undefined) updateData.body_html_de = body_html_de; - if (body_text_en !== undefined) updateData.body_text_en = body_text_en || ''; - if (body_text_de !== undefined) updateData.body_text_de = body_text_de || ''; + // Check which columns exist in the database + const template = await db('email_templates') + .where('template_key', req.params.key) + .first(); + + if (!template) { + return res.status(404).json({ error: 'Template not found' }); + } + + // Determine schema type and update accordingly + if (template.subject_en !== undefined) { + // New schema with language columns + if (subject_en !== undefined) updateData.subject_en = subject_en; + if (subject_de !== undefined) updateData.subject_de = subject_de; + if (body_html_en !== undefined) updateData.body_html_en = body_html_en; + if (body_html_de !== undefined) updateData.body_html_de = body_html_de; + if (body_text_en !== undefined) updateData.body_text_en = body_text_en || ''; + if (body_text_de !== undefined) updateData.body_text_de = body_text_de || ''; + + // Also update basic columns if they exist + if (template.subject !== undefined) { + updateData.subject = subject_en || updateData.subject_en; + updateData.body_html = body_html_en || updateData.body_html_en; + updateData.body_text = body_text_en || updateData.body_text_en || ''; + } + } else { + // Old schema - only update basic columns + if (subject_en !== undefined) { + updateData.subject = subject_en; + updateData.body_html = body_html_en; + updateData.body_text = body_text_en || ''; + } + } const updated = await db('email_templates') .where('template_key', req.params.key)