Add notification channels and a provider abstraction

Users get a notification_channels table (replacing users.ntfy_topic); pages fan
out to every enabled channel through a notify.Provider registry, with ntfy as
the first provider. Fallbacks are typed {type, address}. Schema edited in place:
existing databases must be recreated.

Claude-Session: https://claude.ai/code/session_016mBLURvJoMuUEr9cB2RpUN
This commit is contained in:
Niklas Ye
2026-10-12 21:00:40 +02:00
parent 6292ad6708
commit b114251f45
42 changed files with 2200 additions and 611 deletions
+8 -1
View File
@@ -23,6 +23,13 @@ let data = null; // { user, teams, allTeams }
let error = null;
let busy = false;
// Which kinds of channel the person has, never where they go: an address can be
// a secret, and the server does not send it to anybody but its owner.
function channelSummary(channels) {
if (!channels || !channels.length) return 'None of their own';
return channels.map((c) => (c.enabled ? c.type : `${c.type} (off)`)).join(', ');
}
export function show(route) {
const next = route && route.user != null ? route.user : null;
if (next !== userID) {
@@ -104,7 +111,7 @@ function identityCard() {
h('dl', { class: 'user-facts' },
fact('Email', u.email),
fact('Joined', when(u.created_at)),
fact('Notifications', u.ntfy_topic ? `ntfy: ${u.ntfy_topic}` : 'None of their own'),
fact('Notifications', channelSummary(u.channels)),
u.disabled_at && fact('Disabled', when(u.disabled_at)),
),
// Both of these refuse your own account, and the last administrator's. An