feat: add notification preference system with per-type per-channel toggles and admin defaults
Implement configurable notification preferences across in-app and push channels, including a new `notification_preferences` table with soft-delete support, per-user toggle endpoints, admin defaults management, and canonical type definitions. The change introduces `NOTIFICATION_TYPES` and `NOTIFICATION_CHANNELS` constants, `NotificationPrefForm`/`NotificationDefaultForm` models, `notification_enabled` resolution logic, and UI integration via the profile notifications tab and admin panel.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .spec import Action, Param
|
||||
|
||||
|
||||
def arg(
|
||||
name: str, description: str, required: bool = False, kind: str = "string"
|
||||
) -> Param:
|
||||
return Param(
|
||||
name=name,
|
||||
location="body",
|
||||
description=description,
|
||||
required=required,
|
||||
type=kind,
|
||||
)
|
||||
|
||||
|
||||
TYPES = (
|
||||
"One of: comment, reply, mention, vote, follow, message, badge, level, bug."
|
||||
)
|
||||
|
||||
NOTIFICATION_ACTIONS: tuple[Action, ...] = (
|
||||
Action(
|
||||
name="notification_list",
|
||||
method="LOCAL",
|
||||
path="",
|
||||
summary="List the user's notification preferences (in-app and push per type)",
|
||||
description=(
|
||||
"Returns every notification type with the user's current in-app and push setting and "
|
||||
"whether it has been customized. Use this before changing a setting."
|
||||
),
|
||||
handler="notification",
|
||||
requires_auth=True,
|
||||
read_only=True,
|
||||
),
|
||||
Action(
|
||||
name="notification_set",
|
||||
method="LOCAL",
|
||||
path="",
|
||||
summary="Enable or disable one notification type on one channel",
|
||||
description=(
|
||||
"Sets whether the user receives a given notification type on a given channel. The two "
|
||||
"channels are independent: in-app (shown on DevPlace) and push (sent to subscribed devices)."
|
||||
),
|
||||
handler="notification",
|
||||
requires_auth=True,
|
||||
params=(
|
||||
arg("notification_type", TYPES, required=True),
|
||||
arg("channel", "Either 'in_app' or 'push'.", required=True),
|
||||
arg(
|
||||
"value",
|
||||
"true to deliver this notification on this channel, false to suppress it.",
|
||||
required=True,
|
||||
kind="boolean",
|
||||
),
|
||||
),
|
||||
),
|
||||
Action(
|
||||
name="notification_reset",
|
||||
method="LOCAL",
|
||||
path="",
|
||||
summary="Reset all notification preferences to the platform defaults",
|
||||
description=(
|
||||
"Clears every notification override for the user so all types fall back to the platform "
|
||||
"default. This cannot be undone."
|
||||
),
|
||||
handler="notification",
|
||||
requires_auth=True,
|
||||
params=(
|
||||
arg(
|
||||
"confirm",
|
||||
"Must be true after the user has confirmed the reset.",
|
||||
required=True,
|
||||
kind="boolean",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
Reference in New Issue
Block a user