From 034ba854b5f3d62c68dc8c9eb5fbcb721cdc77dd Mon Sep 17 00:00:00 2001 From: denshooter Date: Wed, 18 Feb 2026 13:04:20 +0100 Subject: [PATCH] feat: admin categorized display, improved CI/CD pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Admin: User timeline contributions shown in Timeline section - Admin: User memory contributions shown in Erinnerungen section - Admin: User photo uploads shown in Familien-Uploads section - All contributions still appear in unified Beiträge section - Dockerfile: fix data dir path (/data -> /app/data) - CI/CD: use checkout@v4, retry health check, auto-create proxy network - CI/CD: support SITE_PASSWORD/ADMIN_PASSWORD secrets - CI/CD: use wget instead of curl (alpine compat) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .gitea/workflows/deploy.yml | 54 ++++++++----- Dockerfile | 2 +- src/app/admin/page.tsx | 157 +++++++++++++++++++++++++++++++++++- 3 files changed, 189 insertions(+), 24 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 09d0b7f..758a91f 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -8,23 +8,25 @@ on: jobs: build-and-deploy: runs-on: ubuntu-latest - + steps: - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - + uses: actions/checkout@v4 + + - name: Create proxy network if needed + run: docker network create proxy || true + - name: Build Docker image - run: | - docker build -t oma-memorial:latest . - + run: docker build -t oma-memorial:latest . + - name: Stop and remove old container run: | - docker stop oma-memorial || true - docker rm oma-memorial || true - + docker stop oma-memorial 2>/dev/null || true + docker rm oma-memorial 2>/dev/null || true + + - name: Ensure data directory exists + run: mkdir -p ${{ gitea.workspace }}/data + - name: Run container in proxy network run: | docker run -d \ @@ -32,14 +34,28 @@ jobs: --network proxy \ --restart unless-stopped \ -e NODE_ENV=production \ - -v $(pwd)/data:/app/data \ + -e SITE_PASSWORD="${{ secrets.SITE_PASSWORD }}" \ + -e ADMIN_PASSWORD="${{ secrets.ADMIN_PASSWORD }}" \ + -v ${{ gitea.workspace }}/data:/app/data \ oma-memorial:latest - + - name: Health check run: | - sleep 10 - docker exec oma-memorial curl -f http://localhost:3000 || exit 1 - - - name: Show container logs + echo "Waiting for container to start..." + for i in $(seq 1 15); do + if docker exec oma-memorial wget -q --spider http://localhost:3000 2>/dev/null; then + echo "Container is healthy!" + exit 0 + fi + echo "Attempt $i/15..." + sleep 2 + done + echo "Health check failed" + docker logs oma-memorial --tail 30 + exit 1 + + - name: Show container status if: always() - run: docker logs oma-memorial --tail 50 + run: | + docker ps --filter name=oma-memorial + docker logs oma-memorial --tail 20 diff --git a/Dockerfile b/Dockerfile index 9dc68a9..239ef79 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/public ./public -RUN mkdir -p /data && chown nextjs:nodejs /data +RUN mkdir -p /app/data && chown nextjs:nodejs /app/data USER nextjs diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 9984076..c125152 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -17,6 +17,8 @@ import { Eye, Loader2, Flame, + User, + Heart, } from 'lucide-react' type Memory = { @@ -749,9 +751,65 @@ export default function AdminPage() { ))} )} - - {/* Candles Section */} + {/* User Memory Contributions */} + {timelineContributions.filter(c => c.type === 'memory').length > 0 && ( +
+

+ + Nutzer-Erinnerungen ({timelineContributions.filter(c => c.type === 'memory').length}) +

+
+ {timelineContributions + .filter(c => c.type === 'memory') + .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()) + .map(c => { + const photos = c.media_filenames ? c.media_filenames.split(',').filter(Boolean) : [] + return ( +
+
+
+
+ {c.title || 'Erinnerung'} + von {c.name} + {c.status === 'flagged' && 🚩} + {c.status === 'approved' && } + {c.status === 'rejected' && } +
+ {c.moderation_reason && ( +

🚩 {c.moderation_reason}

+ )} +

{c.content}

+ {photos.length > 0 && ( +
+ {photos.slice(0, 4).map((f, i) => ( + + ))} +
+ )} +
+
+ {(c.status === 'pending' || c.status === 'flagged') && ( + <> + + + + )} + +
+
+
+ ) + })} +
+
+ )} +

@@ -1118,9 +1176,50 @@ export default function AdminPage() {

))} -
- {/* Recipes Section */} + {/* User Timeline Contributions */} + {timelineContributions.filter(c => c.type === 'timeline').length > 0 && ( +
+

+ + Nutzer-Beiträge ({timelineContributions.filter(c => c.type === 'timeline').length}) +

+
+ {timelineContributions + .filter(c => c.type === 'timeline') + .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()) + .map(c => ( +
+
+
+ {c.title || 'Ohne Titel'} + {c.year && {c.day ? `${c.day}.` : ''}{c.month ? `${c.month}.` : ''}{c.year}} + {c.status === 'flagged' && 🚩} + {c.status === 'approved' && } + {c.status === 'rejected' && } +
+

{c.name} {c.content ? `· ${c.content}` : ''}

+
+
+ {(c.status === 'pending' || c.status === 'flagged') && ( + <> + + + + )} + +
+
+ ))} +
+
+ )} +

@@ -1343,6 +1442,56 @@ export default function AdminPage() { )) )}

+ + {/* User Photo Contributions */} + {timelineContributions.filter(c => c.type === 'media' && c.media_filenames).length > 0 && ( +
+

+ + Nutzer Foto-Uploads ({timelineContributions.filter(c => c.type === 'media' && c.media_filenames).length}) +

+
+ {timelineContributions + .filter(c => c.type === 'media' && c.media_filenames) + .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()) + .map(c => { + const photos = c.media_filenames ? c.media_filenames.split(',').filter(Boolean) : [] + return ( +
+
+ {photos.slice(0, 3).map((f, i) => ( + + ))} + {photos.length > 3 &&
+{photos.length - 3}
} +
+
+
+ {c.name} + {photos.length} Foto{photos.length > 1 ? 's' : ''} + {c.status === 'approved' && } + {c.status === 'flagged' && 🚩} +
+

{c.created_at ? new Date(c.created_at).toLocaleString('de-DE') : ''}

+
+
+ {(c.status === 'pending' || c.status === 'flagged') && ( + <> + + + + )} + +
+
+ ) + })} +
+
+ )}
{/* Contributions Section (New Unified) */}