feat(admin): user management — roles, suspend, delete + lifecycle emails
- New Users page tabs (Users & roles / Access requests / Demo) and a tab-ified Configuration page, both via a reusable Tabs component (persisted active tab). - Admin can suspend/unsuspend (migration 0023 adds users.is_suspended) and delete accounts from the Users & roles tab, with guards (demo / self / last admin). - Email notifications to the affected user: suspended (reactive, on a blocked sign-in), reinstated, role changed, and account deleted; the approval email now carries a clickable app link. The scheduled/manual demo reset also seeds sample channel subscriptions. - Hide the 'unverified email' chip for Google accounts (Google attests the email).
This commit is contained in:
parent
2aa13a6433
commit
4571800991
10 changed files with 461 additions and 32 deletions
30
backend/alembic/versions/0023_user_suspension.py
Normal file
30
backend/alembic/versions/0023_user_suspension.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
"""admin account suspension
|
||||
|
||||
Revision ID: 0023_user_suspension
|
||||
Revises: 0022_password_auth
|
||||
Create Date: 2026-06-19
|
||||
|
||||
Adds users.is_suspended — an admin-controlled access block, distinct from is_active (the
|
||||
approval lifecycle). A suspended account can't sign in (password or Google) and any live
|
||||
session is rejected; the user is told why and given the operator's contact.
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision: str = "0023_user_suspension"
|
||||
down_revision: Union[str, None] = "0022_password_auth"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column(
|
||||
"users",
|
||||
sa.Column("is_suspended", sa.Boolean(), nullable=False, server_default="false"),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("users", "is_suspended")
|
||||
Loading…
Add table
Add a link
Reference in a new issue