refactor: replace global WAHA notifications with granular user and group-specific templates and dispatch logic

This commit is contained in:
root
2026-03-30 01:02:23 +07:00
parent 68a764c0df
commit 596a233898
8 changed files with 502 additions and 131 deletions

View File

@@ -43,7 +43,8 @@ if($_SERVER['REQUEST_METHOD'] === 'POST') {
}
$stmt = $pdo->prepare("INSERT INTO notes (title, content, owner_id, color, image_path, label_name) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$_POST['title'] ?? 'Untitled', $_POST['content'], $user_id, $_POST['color'] ?? null, $image_path, trim($_POST['label_name'] ?? '') ?: null]);
notify_waha('Created', 'Note', $_POST['title'] ?? 'Untitled');
// Note creation only notifies owner in UI, but we can trigger a WAHA self-alert if they have it enabled
notify_user($user_id, "You created a new note: " . ($_POST['title'] ?? 'Untitled'), ['action'=>'Created', 'module'=>'Note', 'item'=>$_POST['title']??'Untitled']);
}
if(isset($_POST['update_note'])) {
@@ -68,7 +69,16 @@ if($_SERVER['REQUEST_METHOD'] === 'POST') {
}
$stmt = $pdo->prepare("UPDATE notes SET title=?, content=?, color=?, image_path=?, label_name=?, updated_at=CURRENT_TIMESTAMP WHERE id=? AND owner_id=?");
$stmt->execute([$_POST['title'] ?? 'Untitled', $_POST['content'], $_POST['color'] ?? null, $image_path, trim($_POST['label_name'] ?? '') ?: null, $_POST['note_id'], $user_id]);
notify_waha('Updated', 'Note', $_POST['title'] ?? 'Untitled');
$ctx = ['action'=>'Updated', 'module'=>'Note', 'item'=>$_POST['title']??'Untitled'];
// Notify owner
notify_user($user_id, "Note '{$_POST['title']}' updated.", $ctx);
// Notify anyone this note is shared with
$shares = query("SELECT share_type, share_id FROM note_shares WHERE note_id=?", [$_POST['note_id']])->fetchAll();
foreach($shares as $sh) {
if($sh['share_type'] === 'user') notify_user($sh['share_id'], "Shared note '{$_POST['title']}' updated.", $ctx);
else notify_group($sh['share_id'], "Shared group note '{$_POST['title']}' updated.", $ctx);
}
}
}
@@ -76,8 +86,15 @@ if($_SERVER['REQUEST_METHOD'] === 'POST') {
$n = query("SELECT owner_id, image_path, title FROM notes WHERE id=?", [$_POST['note_id']])->fetch();
if($n && $n['owner_id'] == $user_id) {
if($n['image_path'] && file_exists($n['image_path'])) @unlink($n['image_path']);
$ctx = ['action'=>'Deleted', 'module'=>'Note', 'item'=>$n['title']??'Untitled'];
// Notify anyone it was shared with before deleting
$shares = query("SELECT share_type, share_id FROM note_shares WHERE note_id=?", [$_POST['note_id']])->fetchAll();
foreach($shares as $sh) {
if($sh['share_type'] === 'user') notify_user($sh['share_id'], "Shared note '{$n['title']}' has been deleted.", $ctx);
else notify_group($sh['share_id'], "Shared group note '{$n['title']}' has been deleted.", $ctx);
}
query("DELETE FROM notes WHERE id=? AND owner_id=?", [$_POST['note_id'], $user_id]);
notify_waha('Deleted', 'Note', $n['title'] ?? 'Untitled');
notify_user($user_id, "Note '{$n['title']}' has been deleted.", $ctx);
}
}
@@ -90,9 +107,9 @@ if($_SERVER['REQUEST_METHOD'] === 'POST') {
$stmt->execute([$n_id, $parts[0], $parts[1]]);
$n = query("SELECT title FROM notes WHERE id=?", [$n_id])->fetch();
$msg = "A note '{$n['title']}' has been shared with you.";
if($parts[0] === 'user') notify_user($parts[1], $msg);
else notify_group($parts[1], $msg);
notify_waha('Shared', 'Note', $n['title'] ?? 'Untitled');
$ctx = ['action'=>'Shared', 'module'=>'Note', 'item'=>$n['title']??'Untitled', 'user'=>$_SESSION['username']??'System'];
if($parts[0] === 'user') notify_user($parts[1], $msg, $ctx);
else notify_group($parts[1], $msg, $ctx);
}
}
@@ -398,7 +415,7 @@ $note_colors = [
$preview = mb_substr($preview, 0, 120) . (mb_strlen($preview) > 120 ? '...' : '');
$note_shares = [];
if($n['is_mine']) {
$note_shares = query("SELECT ns.id, ns.share_type, ns.share_id, u.username, g.name as gname FROM note_shares ns LEFT JOIN users u ON (ns.share_type='user' AND ns.share_id=u.id) LEFT JOIN groups g ON (ns.share_type='group' AND ns.share_id=g.id) WHERE ns.note_id=?", [$n['id']])->fetchAll();
$note_shares = query("SELECT ns.id, ns.share_type, ns.share_id, u.username, u.profile_pic as upic, g.name as gname, g.profile_pic as gpic FROM note_shares ns LEFT JOIN users u ON (ns.share_type='user' AND ns.share_id=u.id) LEFT JOIN groups g ON (ns.share_type='group' AND ns.share_id=g.id) WHERE ns.note_id=?", [$n['id']])->fetchAll();
}
$shares_json = htmlspecialchars(json_encode($note_shares), ENT_QUOTES, 'UTF-8');
?>
@@ -623,17 +640,28 @@ function renderNoteShares(jsonShares) {
try { shares = JSON.parse(jsonShares || '[]'); } catch(e) { shares = []; }
if(shares.length === 0) return;
shares.forEach(sh => {
const label = sh.share_type === 'user' ? ('👤 ' + (sh.username || 'User')) : ('👥 ' + (sh.gname || 'Group'));
const pic = sh.share_type === 'user' ? sh.upic : sh.gpic;
const name = sh.share_type === 'user' ? (sh.username || 'User') : (sh.gname || 'Group');
const icon = sh.share_type === 'user' ? '👤' : '👥';
const chip = document.createElement('div');
chip.className = 'share-chip';
chip.style.display = 'inline-flex';
chip.style.alignItems = 'center';
chip.style.gap = '0.35rem';
chip.style.gap = '0.4rem';
chip.style.fontSize = '0.72rem';
chip.style.padding = '3px 7px';
chip.style.padding = '2px 8px 2px 2px';
chip.style.borderRadius = '999px';
chip.style.background = 'rgba(var(--primary-rgb),0.12)';
chip.style.background = 'rgba(var(--primary-rgb),0.1)';
chip.style.color = 'var(--primary)';
chip.innerHTML = `<span>${label}</span><button type="button" style="border:none;background:transparent;color:inherit;cursor:pointer;line-height:1;" title="Unshare" onclick="removeNoteShare(${Number(sh.id)})">×</button>`;
chip.style.border = '1px solid rgba(var(--primary-rgb),0.2)';
let avatarHtml = `<div style="width:20px; height:20px; border-radius:50%; background:var(--primary); color:white; display:flex; align-items:center; justify-content:center; font-size:0.6rem; font-weight:700; overflow:hidden;">${name.charAt(0).toUpperCase()}</div>`;
if(pic) {
avatarHtml = `<img src="${pic}" style="width:20px; height:20px; border-radius:50%; object-fit:cover;">`;
}
chip.innerHTML = `${avatarHtml}<span style="font-weight:600;">${name}</span><button type="button" style="border:none;background:transparent;color:inherit;cursor:pointer;line-height:1;margin-left:2px;font-size:0.9rem;" title="Unshare" onclick="removeNoteShare(${Number(sh.id)})">×</button>`;
list.appendChild(chip);
});
}