feat: Whiteboard Badge - Punkt bei neuen Änderungen/Teilen

This commit is contained in:
2026-06-29 13:33:41 +02:00
parent fbc3acb2c6
commit 31cb7f7411
2 changed files with 67 additions and 13 deletions

View File

@@ -25,11 +25,41 @@ const router = express.Router();
role TEXT NOT NULL DEFAULT 'edit',
UNIQUE(whiteboard_id, user_id)
);
CREATE TABLE IF NOT EXISTS whiteboard_unread (
whiteboard_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
reason TEXT NOT NULL DEFAULT 'updated',
created_at TEXT NOT NULL DEFAULT (datetime('now','localtime')),
PRIMARY KEY (whiteboard_id, user_id)
);
`);
})();
const uid = req => req.user.id;
function getAccessUsers(whiteboardId, exceptUserId) {
const wb = db.prepare('SELECT owner_id FROM whiteboards WHERE id=?').get(whiteboardId);
if (!wb) return [];
const users = new Set();
if (wb.owner_id !== exceptUserId) users.add(wb.owner_id);
const perms = db.prepare('SELECT user_id FROM whiteboard_permissions WHERE whiteboard_id=?').all(whiteboardId);
for (const p of perms) if (p.user_id !== exceptUserId) users.add(p.user_id);
return [...users];
}
function markUnread(whiteboardId, userIds, reason = 'updated') {
const upsert = db.prepare(`
INSERT INTO whiteboard_unread (whiteboard_id, user_id, reason, created_at)
VALUES (?, ?, ?, datetime('now','localtime'))
ON CONFLICT(whiteboard_id, user_id) DO UPDATE SET reason=excluded.reason, created_at=excluded.created_at
`);
for (const u of userIds) upsert.run(whiteboardId, u, reason);
}
function markRead(whiteboardId, userId) {
db.prepare('DELETE FROM whiteboard_unread WHERE whiteboard_id=? AND user_id=?').run(whiteboardId, userId);
}
// Hilfsfunktion: Hat User Zugriff? Gibt 'owner'|'edit'|'view'|null zurück
function access(whiteboardId, userId) {
const wb = db.prepare('SELECT owner_id FROM whiteboards WHERE id=?').get(whiteboardId);
@@ -39,6 +69,13 @@ function access(whiteboardId, userId) {
return perm?.role || null;
}
// ── Unread count ──────────────────────────────────────────────────────────────
router.get('/unread', authenticate, (req, res) => {
const me = uid(req);
const { count } = db.prepare('SELECT COUNT(*) as count FROM whiteboard_unread WHERE user_id=?').get(me);
res.json({ count });
});
// ── Liste ─────────────────────────────────────────────────────────────────────
router.get('/', authenticate, (req, res) => {
const me = uid(req);
@@ -100,6 +137,7 @@ router.get('/:id/data', authenticate, (req, res) => {
JOIN users u ON u.id=p.user_id WHERE p.whiteboard_id=?
`).all(req.params.id);
const owner = db.prepare('SELECT username FROM users WHERE id=?').get(wb.owner_id);
markRead(req.params.id, me);
res.json({ ...data, role, title: wb.title, owner: owner.username, permissions: perms });
});
@@ -123,12 +161,10 @@ router.post('/:id/save', authenticate, async (req, res) => {
const message = `${saver?.username || 'Jemand'} hat das Whiteboard "${wb?.title || ''}" gespeichert.`;
// Alle User mit Zugriff: Owner + alle Permissions — außer dem Speichernden selbst
const notify = [];
if (wb && wb.owner_id !== me) notify.push(wb.owner_id);
const perms = db.prepare('SELECT user_id FROM whiteboard_permissions WHERE whiteboard_id=?').all(req.params.id);
for (const p of perms) { if (p.user_id !== me) notify.push(p.user_id); }
const notify = getAccessUsers(req.params.id, me);
markUnread(req.params.id, notify, 'updated');
for (const userId of [...new Set(notify)]) {
for (const userId of notify) {
const poCfg = db.prepare('SELECT user_key, app_token FROM pushover_settings WHERE user_id=?').get(userId);
if (!poCfg?.app_token || !poCfg?.user_key) continue;
fetch('https://api.pushover.net/1/messages.json', {
@@ -175,9 +211,10 @@ router.put('/:id/permissions', authenticate, async (req, res) => {
}
})();
// Pushover an neu hinzugekommene User (fire & forget)
const owner = db.prepare('SELECT username FROM users WHERE id=?').get(me);
const newlyAdded = permissions.filter(p => p.role && p.role !== 'none' && !before.includes(p.user_id));
if (newlyAdded.length) markUnread(req.params.id, newlyAdded.map(p => p.user_id), 'shared');
for (const p of newlyAdded) {
try {
const poCfg = db.prepare('SELECT user_key, app_token FROM pushover_settings WHERE user_id=?').get(p.user_id);