style: apply ruff format across backend + scripts (line-length 100)
Mechanical, whole-tree `ruff format` pass — no behaviour change. Recorded in .git-blame-ignore-revs (next commit) so git blame skips it.
This commit is contained in:
+55
-32
@@ -1,5 +1,6 @@
|
||||
"""Admin-only onboarding: review access requests (Invites), approve/deny, manual add.
|
||||
Also the demo-account admin surface: the demo email whitelist + a manual state reset."""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
|
||||
@@ -144,7 +145,9 @@ def add_invite(
|
||||
inv.status = "approved"
|
||||
inv.decided_at = datetime.now(timezone.utc)
|
||||
inv.decided_by = admin.email
|
||||
audit.record(db, admin.id, AuditAction.INVITE_ADD, target_type="invite", target_id=inv.id, summary=email)
|
||||
audit.record(
|
||||
db, admin.id, AuditAction.INVITE_ADD, target_type="invite", target_id=inv.id, summary=email
|
||||
)
|
||||
db.commit()
|
||||
_activate_user_by_email(db, email)
|
||||
return _serialize(inv)
|
||||
@@ -152,6 +155,7 @@ def add_invite(
|
||||
|
||||
# --- Users & roles --------------------------------------------------------------------
|
||||
|
||||
|
||||
def _serialize_user(u: User) -> dict:
|
||||
return {
|
||||
"id": u.id,
|
||||
@@ -208,9 +212,14 @@ def set_user_role(
|
||||
changed = target.role != role
|
||||
if changed:
|
||||
audit.record(
|
||||
db, admin.id, AuditAction.USER_ROLE_CHANGE,
|
||||
target_type="user", target_id=target.id, summary=target.email,
|
||||
before={"role": target.role}, after={"role": role},
|
||||
db,
|
||||
admin.id,
|
||||
AuditAction.USER_ROLE_CHANGE,
|
||||
target_type="user",
|
||||
target_id=target.id,
|
||||
summary=target.email,
|
||||
before={"role": target.role},
|
||||
after={"role": role},
|
||||
)
|
||||
target.role = role
|
||||
db.commit()
|
||||
@@ -254,16 +263,17 @@ def set_user_suspended(
|
||||
was_suspended = target.is_suspended
|
||||
if was_suspended != suspended:
|
||||
audit.record(
|
||||
db, admin.id,
|
||||
db,
|
||||
admin.id,
|
||||
AuditAction.USER_SUSPEND if suspended else AuditAction.USER_UNSUSPEND,
|
||||
target_type="user", target_id=target.id, summary=target.email,
|
||||
target_type="user",
|
||||
target_id=target.id,
|
||||
summary=target.email,
|
||||
)
|
||||
target.is_suspended = suspended
|
||||
db.commit()
|
||||
if was_suspended and not suspended:
|
||||
background.add_task(
|
||||
email_mod.send_account_unsuspended, target.email, operator_contact()
|
||||
)
|
||||
background.add_task(email_mod.send_account_unsuspended, target.email, operator_contact())
|
||||
return _serialize_user(target)
|
||||
|
||||
|
||||
@@ -286,12 +296,20 @@ def admin_delete_user(
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Delete your own account from Settings → Account."
|
||||
)
|
||||
if target.role == "admin" and not target.is_suspended and count_admins(db, active_only=True) <= 1:
|
||||
if (
|
||||
target.role == "admin"
|
||||
and not target.is_suspended
|
||||
and count_admins(db, active_only=True) <= 1
|
||||
):
|
||||
raise HTTPException(status_code=400, detail="Can't delete the last admin.")
|
||||
# Record BEFORE the purge — the target row (and its email) is gone afterwards.
|
||||
audit.record(
|
||||
db, admin.id, AuditAction.USER_DELETE,
|
||||
target_type="user", target_id=target.id, summary=target.email,
|
||||
db,
|
||||
admin.id,
|
||||
AuditAction.USER_DELETE,
|
||||
target_type="user",
|
||||
target_id=target.id,
|
||||
summary=target.email,
|
||||
)
|
||||
purge_user(db, target, background)
|
||||
return {"deleted": user_id}
|
||||
@@ -299,6 +317,7 @@ def admin_delete_user(
|
||||
|
||||
# --- Demo account: email whitelist + state reset -------------------------------------
|
||||
|
||||
|
||||
def _serialize_demo(row: DemoWhitelist) -> dict:
|
||||
return {
|
||||
"id": row.id,
|
||||
@@ -310,13 +329,9 @@ def _serialize_demo(row: DemoWhitelist) -> dict:
|
||||
|
||||
|
||||
@router.get("/demo/whitelist")
|
||||
def list_demo_whitelist(
|
||||
_: User = Depends(admin_user), db: Session = Depends(get_db)
|
||||
) -> list[dict]:
|
||||
def list_demo_whitelist(_: User = Depends(admin_user), db: Session = Depends(get_db)) -> list[dict]:
|
||||
rows = (
|
||||
db.execute(select(DemoWhitelist).order_by(DemoWhitelist.created_at.desc()))
|
||||
.scalars()
|
||||
.all()
|
||||
db.execute(select(DemoWhitelist).order_by(DemoWhitelist.created_at.desc())).scalars().all()
|
||||
)
|
||||
return [_serialize_demo(r) for r in rows]
|
||||
|
||||
@@ -337,9 +352,7 @@ def add_demo_whitelist(
|
||||
email = body.email.strip().lower()
|
||||
if not valid_email(email):
|
||||
raise HTTPException(status_code=400, detail="Enter a valid email address.")
|
||||
row = db.execute(
|
||||
select(DemoWhitelist).where(DemoWhitelist.email == email)
|
||||
).scalar_one_or_none()
|
||||
row = db.execute(select(DemoWhitelist).where(DemoWhitelist.email == email)).scalar_one_or_none()
|
||||
if row is None:
|
||||
row = DemoWhitelist(
|
||||
email=email,
|
||||
@@ -347,7 +360,9 @@ def add_demo_whitelist(
|
||||
added_by=admin.email,
|
||||
)
|
||||
db.add(row)
|
||||
audit.record(db, admin.id, AuditAction.DEMO_ADD, target_type="demo", target_id=email, summary=email)
|
||||
audit.record(
|
||||
db, admin.id, AuditAction.DEMO_ADD, target_type="demo", target_id=email, summary=email
|
||||
)
|
||||
db.commit()
|
||||
return _serialize_demo(row)
|
||||
|
||||
@@ -360,29 +375,34 @@ def remove_demo_whitelist(
|
||||
) -> dict:
|
||||
row = db.get(DemoWhitelist, entry_id)
|
||||
if row is not None:
|
||||
audit.record(db, admin.id, AuditAction.DEMO_REMOVE, target_type="demo", target_id=row.email, summary=row.email)
|
||||
audit.record(
|
||||
db,
|
||||
admin.id,
|
||||
AuditAction.DEMO_REMOVE,
|
||||
target_type="demo",
|
||||
target_id=row.email,
|
||||
summary=row.email,
|
||||
)
|
||||
db.delete(row)
|
||||
db.commit()
|
||||
return {"deleted": entry_id}
|
||||
|
||||
|
||||
@router.post("/demo/reset")
|
||||
def reset_demo(
|
||||
admin: User = Depends(admin_user), db: Session = Depends(get_db)
|
||||
) -> dict:
|
||||
def reset_demo(admin: User = Depends(admin_user), db: Session = Depends(get_db)) -> dict:
|
||||
"""Manually clean up the shared demo sandbox back to a baseline. A scheduled job does the
|
||||
same automatically (admin-tunable interval); this is the admin's on-demand button."""
|
||||
demo = get_or_create_demo_user(db)
|
||||
seeded = reset_demo_state(db, demo)
|
||||
audit.record(db, admin.id, AuditAction.DEMO_RESET, summary=f"{seeded} sample playlists re-seeded")
|
||||
audit.record(
|
||||
db, admin.id, AuditAction.DEMO_RESET, summary=f"{seeded} sample playlists re-seeded"
|
||||
)
|
||||
db.commit()
|
||||
return {"reset": True, "playlists_seeded": seeded}
|
||||
|
||||
|
||||
@router.post("/purge-discovery")
|
||||
def purge_discovery(
|
||||
admin: User = Depends(admin_user), db: Session = Depends(get_db)
|
||||
) -> dict:
|
||||
def purge_discovery(admin: User = Depends(admin_user), db: Session = Depends(get_db)) -> dict:
|
||||
"""Reclaim all un-kept discovery content NOW (ignoring the grace period): live-search result
|
||||
videos nobody watched/saved/subscribed to, plus explored-but-unsubscribed channels. The
|
||||
scheduled discovery-cleanup job does the same on its interval; this is the on-demand button."""
|
||||
@@ -390,8 +410,11 @@ def purge_discovery(
|
||||
|
||||
result = {**purge_unkept_search(db, grace_days=0), **purge_unkept_explored(db)}
|
||||
audit.record(
|
||||
db, admin.id, AuditAction.DISCOVERY_PURGE,
|
||||
summary=", ".join(f"{k}: {v}" for k, v in result.items()) or None, after=result,
|
||||
db,
|
||||
admin.id,
|
||||
AuditAction.DISCOVERY_PURGE,
|
||||
summary=", ".join(f"{k}: {v}" for k, v in result.items()) or None,
|
||||
after=result,
|
||||
)
|
||||
db.commit()
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user