Nachrichten: kein Pushover wenn Empfänger aktiv im Chat

This commit is contained in:
2026-05-30 01:33:15 +02:00
parent 2c521b67b7
commit eed4f293bc
3 changed files with 55 additions and 2 deletions

View File

@@ -254,6 +254,8 @@ if (!userCols2.includes('last_active_at'))
db.exec("ALTER TABLE users ADD COLUMN last_active_at DATETIME DEFAULT NULL"); db.exec("ALTER TABLE users ADD COLUMN last_active_at DATETIME DEFAULT NULL");
if (!userCols2.includes('hidden')) if (!userCols2.includes('hidden'))
db.exec("ALTER TABLE users ADD COLUMN hidden INTEGER NOT NULL DEFAULT 0"); db.exec("ALTER TABLE users ADD COLUMN hidden INTEGER NOT NULL DEFAULT 0");
if (!userCols2.includes('chat_active_at'))
db.exec("ALTER TABLE users ADD COLUMN chat_active_at DATETIME DEFAULT NULL");
// ── Login-Sicherheit ────────────────────────────────────────────────────────── // ── Login-Sicherheit ──────────────────────────────────────────────────────────
// Spalten für Account-Lockout in users-Tabelle // Spalten für Account-Lockout in users-Tabelle

View File

@@ -38,6 +38,17 @@ router.post('/keys', authenticate, (req, res) => {
}); });
// ── Users ───────────────────────────────────────────────────────────────────── // ── Users ─────────────────────────────────────────────────────────────────────
// Presence: User ist gerade aktiv im Chat
router.post('/presence', authenticate, (req, res) => {
const { active } = req.body;
if (active) {
db.prepare("UPDATE users SET chat_active_at=datetime('now','localtime') WHERE id=?").run(req.user.id);
} else {
db.prepare("UPDATE users SET chat_active_at=NULL WHERE id=?").run(req.user.id);
}
res.json({ ok: true });
});
router.get('/users', authenticate, (req, res) => { router.get('/users', authenticate, (req, res) => {
const me = req.user.id; const me = req.user.id;
const isAdmin = req.user.role === 'admin'; const isAdmin = req.user.role === 'admin';
@@ -120,9 +131,15 @@ router.post('/messages/:userId', authenticate, async (req, res) => {
const senderName = db.prepare('SELECT username FROM users WHERE id = ?').get(me)?.username || 'Jemand'; const senderName = db.prepare('SELECT username FROM users WHERE id = ?').get(me)?.username || 'Jemand';
const pushover = db.prepare('SELECT * FROM pushover_settings WHERE user_id = ?').get(recipId); const pushover = db.prepare('SELECT * FROM pushover_settings WHERE user_id = ?').get(recipId);
if (pushover) { if (pushover) {
// Kein Push wenn Empfänger gerade im Chat ist (aktiv in letzten 45 Sekunden)
const presence = db.prepare(`
SELECT chat_active_at FROM users WHERE id=? AND chat_active_at > datetime('now','localtime','-45 seconds')
`).get(recipId);
if (!presence) {
await sendPushover(pushover.user_key, pushover.app_token, 'DickenDock', `Neue Nachricht von ${senderName}`, await sendPushover(pushover.user_key, pushover.app_token, 'DickenDock', `Neue Nachricht von ${senderName}`,
{ retry: pushover.retry, expire: pushover.expire }); { retry: pushover.retry, expire: pushover.expire });
} }
}
res.json({ id: result.lastInsertRowid }); res.json({ id: result.lastInsertRowid });
}); });

View File

@@ -95,6 +95,40 @@ export default function Nachrichten({ toast, mobile }) {
const bottomRef = useRef(null); const bottomRef = useRef(null);
const pollRef = useRef(null); const pollRef = useRef(null);
const pickerRef = useRef(null); const pickerRef = useRef(null);
const heartbeatRef = useRef(null);
// Presence Heartbeat: solange Nachrichten offen + Tab sichtbar → aktiv
useEffect(() => {
const sendPresence = (active) => api('/tools/nachrichten/presence', { method:'POST', body:{ active } }).catch(()=>{});
const start = () => {
if (document.visibilityState === 'visible') {
sendPresence(true);
heartbeatRef.current = setInterval(() => {
if (document.visibilityState === 'visible') sendPresence(true);
}, 30000);
}
};
const onVisibility = () => {
if (document.visibilityState === 'visible') {
sendPresence(true);
if (!heartbeatRef.current) heartbeatRef.current = setInterval(() => sendPresence(true), 30000);
} else {
sendPresence(false);
clearInterval(heartbeatRef.current);
heartbeatRef.current = null;
}
};
start();
document.addEventListener('visibilitychange', onVisibility);
return () => {
sendPresence(false);
clearInterval(heartbeatRef.current);
document.removeEventListener('visibilitychange', onVisibility);
};
}, []);
useEffect(() => { useEffect(() => {
if (!showPicker) return; if (!showPicker) return;