feat: complete memorial website features

- Add user contribution system (memories, timeline entries)
- Add AI content moderation with Ollama (bad word detection + qwen3:4b)
- Add family photo/video upload with admin approval
- Add candle lighting feature
- Add timeline and recipe sections
- Add QR code page and OG image
- Add site authentication (password-protected access)
- Add proxy middleware for auth routing
- Add admin dashboard for content management
- Remove email fields, make name optional (default: Anonym)
- Add CI/CD pipeline for Gitea Actions
- Add Docker deployment configuration
- Optimize Ollama RAM usage (42GB → 2.9GB)
- Fix API routes accessibility through proxy middleware

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
denshooter
2026-02-18 12:20:33 +01:00
parent 43e9d49620
commit a34d406375
54 changed files with 5989 additions and 248 deletions
+63
View File
@@ -0,0 +1,63 @@
import { NextResponse } from 'next/server'
import { getDb } from '@/lib/db'
export async function PUT(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params
const body = await request.json()
const db = getDb()
// Check if only updating status
if (Object.keys(body).length === 1 && 'status' in body) {
db.prepare('UPDATE contributions SET status = ? WHERE id = ?').run(body.status, id)
} else {
// Full update
const { name, email, type, year, month, day, title, content, location, media_filenames, status } = body
db.prepare(`
UPDATE contributions
SET name = ?, email = ?, type = ?, year = ?, month = ?, day = ?, title = ?, content = ?, location = ?, media_filenames = ?, status = ?
WHERE id = ?
`).run(
name,
email || null,
type,
year || null,
month || null,
day || null,
title || null,
content || null,
location || null,
media_filenames || null,
status || 'pending',
id
)
}
return NextResponse.json({ success: true })
} catch (error) {
console.error('Error updating contribution:', error)
return NextResponse.json({ error: 'Failed to update contribution' }, { status: 500 })
}
}
export async function DELETE(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params
const db = getDb()
db.prepare('DELETE FROM contributions WHERE id = ?').run(id)
return NextResponse.json({ success: true })
} catch (error) {
console.error('Error deleting contribution:', error)
return NextResponse.json({ error: 'Failed to delete contribution' }, { status: 500 })
}
}