feat: multi-user UI login with admin and monitor roles

Add sac_users table, JWT roles, settings/users API guarded for admin, Users page in UI, and sac_manage_user.py CLI.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-01 09:27:14 +10:00
parent bc77f82307
commit 56c469ddbd
20 changed files with 859 additions and 85 deletions
+9 -9
View File
@@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from app.auth.jwt_auth import get_current_user
from app.auth.jwt_auth import require_admin
from app.database import get_db
from app.services.email_notify import EmailNotConfiguredError, EmailSendError, send_email_test_message
from app.services.notification_policy import (
@@ -185,7 +185,7 @@ def _email_to_response(cfg: EmailConfig, policy: NotificationPolicyConfig) -> Em
@router.get("/notifications", response_model=NotificationSettingsResponse)
def get_notification_settings(
db: Session = Depends(get_db),
_user: str = Depends(get_current_user),
_user=Depends(require_admin),
) -> NotificationSettingsResponse:
policy = get_effective_notification_policy(db)
return NotificationSettingsResponse(
@@ -200,7 +200,7 @@ def get_notification_settings(
def update_notification_policy(
body: NotificationPolicyUpdate,
db: Session = Depends(get_db),
_user: str = Depends(get_current_user),
_user=Depends(require_admin),
) -> NotificationPolicyResponse:
if body.min_severity not in VALID_SEVERITIES:
raise HTTPException(status_code=422, detail=f"min_severity must be one of: {sorted(VALID_SEVERITIES)}")
@@ -223,7 +223,7 @@ def update_notification_policy(
def update_telegram_settings(
body: TelegramSettingsUpdate,
db: Session = Depends(get_db),
_user: str = Depends(get_current_user),
_user=Depends(require_admin),
) -> TelegramSettingsResponse:
try:
cfg = upsert_telegram_channel(
@@ -242,7 +242,7 @@ def update_telegram_settings(
def update_webhook_settings(
body: WebhookSettingsUpdate,
db: Session = Depends(get_db),
_user: str = Depends(get_current_user),
_user=Depends(require_admin),
) -> WebhookSettingsResponse:
try:
cfg = upsert_webhook_channel(
@@ -262,7 +262,7 @@ def update_webhook_settings(
def update_email_settings(
body: EmailSettingsUpdate,
db: Session = Depends(get_db),
_user: str = Depends(get_current_user),
_user=Depends(require_admin),
) -> EmailSettingsResponse:
try:
cfg = upsert_email_channel(
@@ -286,7 +286,7 @@ def update_email_settings(
@router.post("/notifications/telegram/test", response_model=ChannelTestResponse)
def test_telegram_settings(
db: Session = Depends(get_db),
_user: str = Depends(get_current_user),
_user=Depends(require_admin),
) -> ChannelTestResponse:
cfg = get_effective_telegram_config(db)
try:
@@ -302,7 +302,7 @@ def test_telegram_settings(
@router.post("/notifications/webhook/test", response_model=ChannelTestResponse)
def test_webhook_settings(
db: Session = Depends(get_db),
_user: str = Depends(get_current_user),
_user=Depends(require_admin),
) -> ChannelTestResponse:
cfg = get_effective_webhook_config(db)
try:
@@ -318,7 +318,7 @@ def test_webhook_settings(
@router.post("/notifications/email/test", response_model=ChannelTestResponse)
def test_email_settings(
db: Session = Depends(get_db),
_user: str = Depends(get_current_user),
_user=Depends(require_admin),
) -> ChannelTestResponse:
cfg = get_effective_email_config(db)
try: