Nachrichten: kein Pushover wenn Empfänger aktiv im Chat
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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,8 +131,14 @@ 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) {
|
||||||
await sendPushover(pushover.user_key, pushover.app_token, 'DickenDock', `Neue Nachricht von ${senderName}`,
|
// Kein Push wenn Empfänger gerade im Chat ist (aktiv in letzten 45 Sekunden)
|
||||||
{ retry: pushover.retry, expire: pushover.expire });
|
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}`,
|
||||||
|
{ retry: pushover.retry, expire: pushover.expire });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({ id: result.lastInsertRowid });
|
res.json({ id: result.lastInsertRowid });
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user