- API и страницы профиля (редактирование, смена пароля, аватар), публичные карточки. - Сайдбар: блок пользователя, пункт Users для admin/root, исправлен порядок инициализации (показ admin-only после initAuthSession, currentUser). - GET /auth/me: ответ через ProfileMeResponse, исправлена валидация (is_founder bool). Команды и роли - Маршруты и UI команд; при редактировании роли: видимость Team, выбор команды в модалке, только команды с активным членством; API team_id в details/ update. - GET /api/v1/teams?membership=active для списка «своих» команд. - Форма роли: сегмент Team, панель выбора команды только при Team и не при с
41 lines
1.3 KiB
Python
41 lines
1.3 KiB
Python
"""Rules around the founding (first-registered) user — highest priority, protected from other admins."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncpg
|
|
from fastapi import HTTPException, status
|
|
|
|
|
|
async def founder_user_id(conn: asyncpg.Connection) -> str | None:
|
|
return await conn.fetchval(
|
|
"select id::text from users where is_founder = true limit 1",
|
|
)
|
|
|
|
|
|
async def ensure_actor_may_modify_protected_user(
|
|
conn: asyncpg.Connection,
|
|
*,
|
|
actor_id: str,
|
|
target_id: str,
|
|
) -> None:
|
|
"""Non-founders cannot ban, delete, demote, or otherwise change the founding account."""
|
|
fid = await founder_user_id(conn)
|
|
if fid and target_id == fid and actor_id != fid:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="The founding administrator can only be changed by that account.",
|
|
)
|
|
|
|
|
|
async def ensure_founder_role_not_changed(*, target_is_founder: bool, new_role: str) -> None:
|
|
"""Founding user always keeps the root role."""
|
|
if target_is_founder and new_role != "root":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="The founding user always has the root chief role.",
|
|
)
|
|
|
|
|
|
def account_group_from_role(role: str | None) -> str:
|
|
return "root" if (role or "") == "root" else "users"
|