From dc6252ff56851c9e9dc39ab4b13e13ccc23b8e18 Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 14 Jul 2025 10:14:14 +0200 Subject: [PATCH] fix: complete email template and CMS page fixes for production MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix email templates list endpoint to handle both schema variations - Add migration for default CMS pages with language-specific columns - Create debug script to identify 500 error causes - Update CMS migration to use correct column names (title_en/de, content_en/de) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- backend/data/photo_sharing.db | Bin 176128 -> 188416 bytes .../migrations/021_add_default_cms_pages.js | 121 ++++++++++++++++++ backend/scripts/debug-500-errors.js | 92 +++++++++++++ backend/src/routes/adminEmail.js | 43 +++++-- 4 files changed, 242 insertions(+), 14 deletions(-) create mode 100644 backend/migrations/021_add_default_cms_pages.js create mode 100644 backend/scripts/debug-500-errors.js diff --git a/backend/data/photo_sharing.db b/backend/data/photo_sharing.db index b5ef2135f6c06eb7da59ae23a35d1f317e0be23b..64895455e492605eee2fb7728f9de3694e6e370d 100644 GIT binary patch delta 1225 zcmaJ>O=#O@82(;Kj%r)}ixX@xT|~02F^+A?n%kuHVc9S}Bwd@)pTn9-imf_YB-@E) z=CX!F2~Be85~B{Cb|~8@jIPl7pvxc|y#-3!LD_M;t%r>;*kLR%_SsFk5xfWl&-dzi z-}n2T=X$K>Bik^aRefXm&ghWyq|1uB#Bg8_V@l=n78aM5SD-FDM6jR$Pn? z|A#jgqR^DU@nhmOwIM3HtZJg6=v7TNl$ym(_m%#wc_v7qOPD*_*+^kQ!JMKf8=_I! z&z!F-b*1};UJFntCa7iA=>EO6b2VE7;^9-^2C$M0!J)u?zsP9huJ;$O=KhV~+>^)N zqrdIpu`EHtvzlY*NFo7iY3BqD4Y1N=^oOZ7#$xooNlwB4I3N}(T3s)TM>?<8; z7q^~X9dz8E!X9`C*K_0#x}L)`e2honJZl0)MYl$Ye#B2~xXn*Y5GFSI&85!5`RNX9 zx}4wdz-=P>#YyN#iTvio+IjPgklz|wALuNs$2+H-%x(A_da-dMKIR1?&`m`BiEc74 ztWfad$VQdwL&FAg_L4PIR#I*FESV9nUv#86ulH*@qIPwfM^Qyr8ZND~lcM zEZ>D$m$P{n<_QWRGV1(#527_P3}u^Ui6M%>2p{EbD42sOI+D$TSu*4qP3bmn-D0VC z-_MU<%(EBA-Q?gth|HW0&r+e95>#=MOQOXQh3`4cv?D>(8?a5Eb-#%JfHR>YU2 z<`%>!=9HusnHpQNOis|3X5`ykqu-&x%*S(TGJAmRWeStj@tMuB^=1COX-R z?fLfi%#8n7xtbYx*u}NA8C%V_TQMx=P)y#VPHJNp2zb7sAwPKbk@m?kGJog#<-tFpsSpj zpFumlO|z-e)i|@=c=E%8h1=_vGX7*?X%l7P-~MI|qeL;YAk(Gk>Legal Notice +

Information according to § 5 TMG

+ +

Responsible for content

+

[Your Name]
+[Your Address]
+[Postal Code City]

+ +

Contact

+

Email: [Your Email Address]
+Phone: [Your Phone Number]

+ +

Disclaimer

+

Liability for content

+

The contents of our pages were created with great care. However, we cannot guarantee the accuracy, completeness and timeliness of the content.

+ +

Liability for links

+

Our website contains links to external third-party websites over whose content we have no influence. Therefore, we cannot accept any liability for this third-party content.

`, + content_de: `

Impressum

+

Angaben gemäß § 5 TMG

+ +

Verantwortlich für den Inhalt

+

[Ihr Name]
+[Ihre Adresse]
+[PLZ Ort]

+ +

Kontakt

+

E-Mail: [Ihre E-Mail-Adresse]
+Telefon: [Ihre Telefonnummer]

+ +

Haftungsausschluss

+

Haftung für Inhalte

+

Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte können wir jedoch keine Gewähr übernehmen.

+ +

Haftung für Links

+

Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen.

`, + updated_at: new Date() + }); + } + + // Add Datenschutz page if it doesn't exist + if (!datenschutzExists) { + pagesToInsert.push({ + slug: 'datenschutz', + title_en: 'Privacy Policy', + title_de: 'Datenschutzerklärung', + content_en: `

Privacy Policy

+ +

1. Privacy at a Glance

+

General Information

+

The following information provides a simple overview of what happens to your personal data when you visit this website.

+ +

Data Collection on This Website

+

Who is responsible for data collection on this website?

+

Data processing on this website is carried out by the website operator. Their contact details can be found in the legal notice of this website.

+ +

How do we collect your data?

+

Your data is collected when you provide it to us. This could be data that you enter into a contact form, for example.

+ +

What do we use your data for?

+

Some of the data is collected to ensure error-free provision of the website. Other data may be used to analyze your user behavior.

+ +

2. Hosting

+

This website is hosted externally. The personal data collected on this website is stored on the servers of the host.

+ +

3. General Information and Mandatory Information

+

Data Protection

+

The operators of these pages take the protection of your personal data very seriously. We treat your personal data confidentially and in accordance with the statutory data protection regulations and this privacy policy.

`, + content_de: `

Datenschutzerklärung

+ +

1. Datenschutz auf einen Blick

+

Allgemeine Hinweise

+

Die folgenden Hinweise geben einen einfachen Überblick darüber, was mit Ihren personenbezogenen Daten passiert, wenn Sie diese Website besuchen.

+ +

Datenerfassung auf dieser Website

+

Wer ist verantwortlich für die Datenerfassung auf dieser Website?

+

Die Datenverarbeitung auf dieser Website erfolgt durch den Websitebetreiber. Dessen Kontaktdaten können Sie dem Impressum dieser Website entnehmen.

+ +

Wie erfassen wir Ihre Daten?

+

Ihre Daten werden zum einen dadurch erhoben, dass Sie uns diese mitteilen. Hierbei kann es sich z.B. um Daten handeln, die Sie in ein Kontaktformular eingeben.

+ +

Wofür nutzen wir Ihre Daten?

+

Ein Teil der Daten wird erhoben, um eine fehlerfreie Bereitstellung der Website zu gewährleisten. Andere Daten können zur Analyse Ihres Nutzerverhaltens verwendet werden.

+ +

2. Hosting

+

Diese Website wird extern gehostet. Die personenbezogenen Daten, die auf dieser Website erfasst werden, werden auf den Servern des Hosters gespeichert.

+ +

3. Allgemeine Hinweise und Pflichtinformationen

+

Datenschutz

+

Die Betreiber dieser Seiten nehmen den Schutz Ihrer persönlichen Daten sehr ernst. Wir behandeln Ihre personenbezogenen Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften sowie dieser Datenschutzerklärung.

`, + updated_at: new Date() + }); + } + + // Insert pages if any need to be added + if (pagesToInsert.length > 0) { + await knex('cms_pages').insert(pagesToInsert); + } +}; + +exports.down = async function(knex) { + // Don't remove CMS pages on rollback as they might have been customized +}; \ No newline at end of file diff --git a/backend/scripts/debug-500-errors.js b/backend/scripts/debug-500-errors.js new file mode 100644 index 0000000..330017e --- /dev/null +++ b/backend/scripts/debug-500-errors.js @@ -0,0 +1,92 @@ +require('dotenv').config(); +const { db } = require('../src/database/db'); + +async function debugEndpoints() { + console.log('Debugging 500 errors...\n'); + + try { + // Test email templates query + console.log('1. Testing email templates query:'); + try { + const templates = await db('email_templates') + .select('*') + .orderBy('template_key'); + + console.log(`Found ${templates.length} templates`); + if (templates.length > 0) { + console.log('First template columns:', Object.keys(templates[0])); + console.log('Template keys:', templates.map(t => t.template_key)); + } + } catch (error) { + console.error('Email templates query failed:', error.message); + console.error('Error code:', error.code); + } + + // Test notifications query + console.log('\n2. Testing notifications query:'); + try { + const notifications = await db('activity_logs') + .select( + 'activity_logs.*', + 'events.event_name' + ) + .leftJoin('events', 'activity_logs.event_id', 'events.id') + .whereNull('activity_logs.read_at') + .orderBy('activity_logs.created_at', 'desc') + .limit(5); + + console.log(`Found ${notifications.length} unread notifications`); + } catch (error) { + console.error('Notifications query failed:', error.message); + console.error('Error code:', error.code); + + // Check if it's a column issue + if (error.message.includes('column')) { + console.log('\nChecking activity_logs columns:'); + const columns = await db('activity_logs').columnInfo(); + console.log('Columns:', Object.keys(columns)); + } + } + + // Test specific template query + console.log('\n3. Testing specific template query (gallery_created):'); + try { + const template = await db('email_templates') + .where('template_key', 'gallery_created') + .first(); + + if (template) { + console.log('Template found:', template.template_key); + console.log('Has subject_en?', template.subject_en !== undefined); + console.log('Has subject?', template.subject !== undefined); + } else { + console.log('Template not found'); + } + } catch (error) { + console.error('Template query failed:', error.message); + } + + // Check CMS pages + console.log('\n4. Checking CMS pages:'); + try { + const pages = await db('cms_pages') + .select('slug', 'title', 'is_published') + .orderBy('slug'); + + console.log(`Found ${pages.length} CMS pages:`); + pages.forEach(page => { + console.log(` - ${page.slug}: ${page.title} (published: ${page.is_published})`); + }); + } catch (error) { + console.error('CMS pages query failed:', error.message); + } + + } catch (error) { + console.error('General error:', error); + } finally { + await db.destroy(); + process.exit(0); + } +} + +debugEndpoints(); \ No newline at end of file diff --git a/backend/src/routes/adminEmail.js b/backend/src/routes/adminEmail.js index cc25e52..615dade 100644 --- a/backend/src/routes/adminEmail.js +++ b/backend/src/routes/adminEmail.js @@ -160,20 +160,35 @@ router.get('/templates', adminAuth, async (req, res) => { .orderBy('template_key'); // Parse variables JSON and format for multi-language support - const formattedTemplates = templates.map(template => ({ - 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 - })); + const formattedTemplates = templates.map(template => { + const result = { + id: template.id, + template_key: template.template_key, + variables: template.variables ? JSON.parse(template.variables) : [], + updated_at: template.updated_at + }; + + // Handle both old and new schema formats + if (template.subject_en !== undefined) { + // New schema with language columns + result.subject_en = template.subject_en; + result.body_html_en = template.body_html_en; + result.body_text_en = template.body_text_en; + result.subject_de = template.subject_de; + result.body_html_de = template.body_html_de; + result.body_text_de = template.body_text_de; + } else { + // Old schema - use basic columns for both languages + result.subject_en = template.subject; + result.body_html_en = template.body_html; + result.body_text_en = template.body_text; + result.subject_de = template.subject; + result.body_html_de = template.body_html; + result.body_text_de = template.body_text; + } + + return result; + }); res.json(formattedTemplates); } catch (error) {