From e953e6a9ac6c4c7c2f4b5e8ab83ffe1e08c9b95a Mon Sep 17 00:00:00 2001 From: Dicken Date: Thu, 18 Jun 2026 15:31:11 +0200 Subject: [PATCH] feat: User-Benachrichtigung wenn Admin Favoriten quittiert --- backend/src/db.js | 2 ++ backend/src/tools/media/routes.js | 24 +++++++++++++++++------- frontend/src/App.jsx | 18 ++++++++++++++---- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/backend/src/db.js b/backend/src/db.js index f332e47..016590d 100644 --- a/backend/src/db.js +++ b/backend/src/db.js @@ -560,6 +560,8 @@ if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='mov db.exec("ALTER TABLE movie_favorites ADD COLUMN acknowledged INTEGER NOT NULL DEFAULT 0"); if (!cols.includes('acknowledged_at')) db.exec("ALTER TABLE movie_favorites ADD COLUMN acknowledged_at DATETIME DEFAULT NULL"); + if (!cols.includes('user_notified')) + db.exec("ALTER TABLE movie_favorites ADD COLUMN user_notified INTEGER NOT NULL DEFAULT 0"); if (!cols.includes('media_type')) db.exec("ALTER TABLE movie_favorites ADD COLUMN media_type TEXT NOT NULL DEFAULT 'movie'"); } diff --git a/backend/src/tools/media/routes.js b/backend/src/tools/media/routes.js index 76ecbf2..80db234 100644 --- a/backend/src/tools/media/routes.js +++ b/backend/src/tools/media/routes.js @@ -503,18 +503,28 @@ router.get('/favorites/all', authenticate, requireAdmin, (req, res) => { res.json(favs); }); -// GET /favorites/unacked – unquittierte Zählung +// GET /favorites/unacked – unquittierte Zählung (Admin: neue Favoriten; User: quittierte aber unbestätigte) router.get('/favorites/unacked', authenticate, (req, res) => { const isAdmin = req.user.role === 'admin'; - const count = isAdmin - ? db.prepare('SELECT COUNT(*) as n FROM movie_favorites WHERE acknowledged=0').get() - : db.prepare('SELECT COUNT(*) as n FROM movie_favorites WHERE user_id=? AND acknowledged=0').get(req.user.id); - res.json({ count: count.n }); + if (isAdmin) { + const count = db.prepare('SELECT COUNT(*) as n FROM movie_favorites WHERE acknowledged=0').get(); + res.json({ count: count.n, isAdmin: true }); + } else { + // User: Favoriten die vom Admin quittiert wurden aber User noch nicht gesehen hat + const count = db.prepare('SELECT COUNT(*) as n FROM movie_favorites WHERE user_id=? AND acknowledged=1 AND user_notified=0').get(req.user.id); + res.json({ count: count.n, isAdmin: false }); + } +}); + +// POST /favorites/user-notify – User bestätigt Kenntnis der quittierten Favoriten +router.post('/favorites/user-notify', authenticate, (req, res) => { + db.prepare('UPDATE movie_favorites SET user_notified=1 WHERE user_id=? AND acknowledged=1 AND user_notified=0').run(req.user.id); + res.json({ ok: true }); }); // POST /favorites/acknowledge-all – Admin: alle quittieren router.post('/favorites/acknowledge-all', authenticate, requireAdmin, (req, res) => { - db.prepare('UPDATE movie_favorites SET acknowledged=1, acknowledged_at=CURRENT_TIMESTAMP WHERE acknowledged=0').run(); + db.prepare('UPDATE movie_favorites SET acknowledged=1, acknowledged_at=CURRENT_TIMESTAMP, user_notified=0 WHERE acknowledged=0').run(); res.json({ ok: true }); }); @@ -563,7 +573,7 @@ router.delete('/favorites/:tmdb_id', authenticate, (req, res) => { // POST /favorites/:id/acknowledge – Admin: einzelnen quittieren router.post('/favorites/:id/acknowledge', authenticate, requireAdmin, (req, res) => { - db.prepare('UPDATE movie_favorites SET acknowledged=1, acknowledged_at=CURRENT_TIMESTAMP WHERE id=?').run(req.params.id); + db.prepare('UPDATE movie_favorites SET acknowledged=1, acknowledged_at=CURRENT_TIMESTAMP, user_notified=0 WHERE id=?').run(req.params.id); res.json({ ok: true }); }); diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index f474639..1a02fdb 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1983,12 +1983,22 @@ function Dashboard({ toast, mobile, setActive, setDevToolsNav, unreadMsgs=0, unr {/* Unquittierte Favoriten für alle User */} {unackedFavs > 0 && ( - )} @@ -3618,7 +3628,7 @@ export default function App() { const [unreadBoard, setUnreadBoard] = useState(0); const [unreadPromoted, setUnreadPromoted] = useState(0); const [unreadChangelog,setUnreadChangelog]= useState(0); - const [unackedFavs, setUnackedFavs] = useState(0); + const [unackedFavs, setUnackedFavs] = useState({count:0,isAdmin:false}); const [mediaInitTab, setMediaInitTab] = useState(null); const [authChecked, setAuthChecked] = useState(false); @@ -3658,7 +3668,7 @@ export default function App() { useEffect(()=>{ if(!user)return; - const poll=()=>api('/tools/media/favorites/unacked').then(d=>setUnackedFavs(d.count||0)).catch(()=>{}); + const poll=()=>api('/tools/media/favorites/unacked').then(d=>setUnackedFavs({count:d.count||0,isAdmin:d.isAdmin})).catch(()=>{}); poll(); const ti=setInterval(poll,60000); return()=>clearInterval(ti); },[user]);