mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-29 16:17:25 +09:00
Reusable, non-blocking notification layer on top of the Queue Bus: notify.send(event, to, data) records a Notification + per-channel NotificationDelivery, queues them, and a daemon consumer delivers via pluggable channel adapters (in-app, email, chat) inheriting retry, backoff and dead-letter. - Jinja2 email system: branded, dark-mode, Outlook-safe base layout + per-event templates (security/backup/monitoring/welcome/invitation). The legacy inline f-string email was removed and now renders here. - In-app center API (inbox/unread-count/mark-read) + per-user Socket.IO push. - Admin delivery log (stats/filter/retry). - Email providers (SMTP/SendGrid/Postmark/SES/Mailgun) with encrypted credentials + test; the email adapter prefers the default provider and falls back to the legacy SMTP config; surfaced in ConnectionRegistry. - NotificationService.send_all() is now a non-blocking shim that routes system alerts through the bus. Migrations 023 + 024. Tests: backend/tests/test_notification_bus.py (20). Full suite: 391 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
35 lines
1.5 KiB
Python
35 lines
1.5 KiB
Python
"""Plugin/SDK surface for the Notification Bus.
|
|
|
|
Stable façade so callers (core services and plugins) depend on this rather than
|
|
the service internals:
|
|
|
|
from app.plugins_sdk import notify
|
|
notify.send('backup.completed', to='admins', data={'app': 'blog'})
|
|
|
|
Plugins can also extend the bus:
|
|
|
|
notify.register_event('myplugin.thing_ready', 'Your thing is ready',
|
|
template='generic', severity='success', category='apps')
|
|
notify.register_channel(MySmsAdapter())
|
|
"""
|
|
from app.notifications.service import NotificationBusService
|
|
|
|
|
|
class NotifySdk:
|
|
def send(self, event, to, data=None, channels=None, severity=None, title=None, category=None):
|
|
"""Emit a notification (non-blocking). See NotificationBusService.send."""
|
|
return NotificationBusService.send(
|
|
event, to, data=data, channels=channels,
|
|
severity=severity, title=title, category=category,
|
|
)
|
|
|
|
def register_event(self, event_key, title, template='generic', severity='info', category='system'):
|
|
"""Add/override a catalog event so it renders through the pipeline."""
|
|
from app.notifications import catalog
|
|
return catalog.register(event_key, title, template=template, severity=severity, category=category)
|
|
|
|
def register_channel(self, adapter):
|
|
"""Register a new channel adapter (must define ``key`` + ``deliver``)."""
|
|
from app.notifications.channels import register_adapter
|
|
return register_adapter(adapter)
|