Files
AgentLab/backend/app/apps/access.py
T

59 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""应用级权限(§3.12):use 能用(入口、视图、自己的实例);observe 另能看全部实例;manage 能搭建、发布、授权、管钩子。
- 关登录:全部放行,等同 manage(界面上挂横幅说明,签批人是自报的署名);
- admin:所有应用 manage;
- builder:所有应用至少 observe(能用、能看全部实例);自己建的、或者有 manage 授权的才 manage;
- user:按授权(给本人、给所在的组、给所有人)取最高的那一档,最高到 observe:搭建、发布、绑定岗位、授权、钩子、按草稿
预览、改派催办都不给 user 角色(§3.12),授给它的 manage 按 observe 算。没有授权就看不到这个应用。
"""
from __future__ import annotations
from typing import Any
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.deps import Principal
from app.db.models_apps import AppGrant
RANK = {"use": 1, "observe": 2, "manage": 3}
def at_least(role: str | None, need: str) -> bool:
return RANK.get(role or "", 0) >= RANK[need]
def granted_role(principal: Principal, grants: list[Any]) -> str | None:
"""授权里这个人能拿到的最高一档。"""
best: str | None = None
groups = set(principal.groups)
for g in grants:
hit = (g.principal_kind == "everyone"
or (g.principal_kind == "user" and principal.username and g.principal == principal.username)
or (g.principal_kind == "group" and g.principal in groups))
if hit and RANK.get(g.role, 0) > RANK.get(best or "", 0):
best = g.role
return best
def role_of(principal: Principal, app: Any, grants: list[Any]) -> str | None:
if principal.mode == "off" or principal.role == "admin":
return "manage"
granted = granted_role(principal, grants)
if principal.role == "builder":
if app.created_by and principal.username and app.created_by == principal.username:
return "manage"
return granted if at_least(granted, "manage") else "observe"
return "observe" if at_least(granted, "manage") else granted
async def grants_of(session: AsyncSession, app_id: str) -> list[AppGrant]:
return list((await session.execute(select(AppGrant).where(AppGrant.app_id == app_id)
.order_by(AppGrant.created_at))).scalars())
async def app_role(session: AsyncSession, principal: Principal, app: Any) -> str | None:
if principal.mode == "off" or principal.role == "admin":
return "manage"
return role_of(principal, app, await grants_of(session, app.id))