Files
ThearchyHelios 277982ead3 普通用户建应用(后端):
- 蓝图:bp_* 操作和逐卡白名单、蓝图检查、留痕、按蓝图判权限;五个场景模板加自由形(骨架、关节、应用骨架、定时任务),实例化与骨架比对;BlueprintApplier / TemplateApplier(只收模板声明过的关节)与自查;look 新类别口径卡;蓝图对话和填关节两个流式接口,不同组的关节并行填、出错的组串行重试;模板列表
- 试运行与发布单:四种起点(对话、模板、问数据的一轮、已发布版本);试运行是探索运行,草稿应用按这次运行解析、印章写试运行,流程类派给自己、不触发升级;发布单九步、预检只读、每步留痕、停下后接着做、核对卡片指纹和应用管理权、启动时整理中断的单;白话层覆盖全部问题编号
- 记录表与文件:平台托管只追加的记录表、按高水位固定数据、连接上的临时视图做行级可见、写入走动作(records_append)、表版本在发布时切换、草稿不影响线上、记录列表遮敏感列;文件按哈希存、两步上传、提交时绑定运行、下载按读权限、清理、file_text、按配方导入一期(table_import_period)
- 个人应用:存成个人应用(问数据的约束)、刷新(遮罩、只读、每日上限)、只有拥有者看得见、提交审核与共享副本、开关下发到认人接口;页面编辑的候选;隐藏组件不下发;三条新检查
2026-10-15 12:09:29 +08:00

73 lines
3.2 KiB
Python
Raw Permalink 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.
"""记录表的行级可见(docs/design/normal-user-apps.md N8、§3.7、§3.12)。
谁看得到哪些行,只有三种:all(全部)、mine(只看自己提交的,_submitted_by = 看的人)、none(一行都不给)。
- 正式运行以服务身份跑,看全部:看板读的是正式运行的封存结果,汇总是全量的(作者的选择,发布摘要里写明);
- 别的运行(问数据、试运行、个人应用的刷新)按发起人和这张表所属应用的授权:use 只看自己的,observe、manage 看全部;
- 记录列表(records_list、GET /api/apps/{id}/records)按看的人,同一套规则;
- 关登录时所有人等同管理员,看全部;管理员看全部。
过滤在查询连接的临时视图上做(records/store.view_prelude),模型和 SQL 都绕不过去。
"""
from __future__ import annotations
from typing import Any
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
SCOPES = ("all", "mine", "none")
def scope_of_role(principal: Any, role: str | None) -> str:
"""看的人在应用上拿到的那一档 → 看哪些行。"""
from app.apps.access import at_least
if principal.mode == "off" or principal.role == "admin":
return "all"
if at_least(role, "observe"):
return "all"
return "mine" if role == "use" else "none"
async def scope_of(session: AsyncSession, principal: Any, app_id: str | None) -> str:
"""看的人对这张表(所属应用 app_id)看哪些行。还没归到应用的(试运行时按蓝图建的):搭建者看全部,使用者看自己的。"""
from app.apps.access import app_role
from app.db.models_apps import App
if principal.mode == "off" or principal.role == "admin":
return "all"
if not app_id:
return "all" if principal.at_least("builder") else "mine"
app = await session.get(App, app_id)
if app is None:
return "all" if principal.at_least("builder") else "none"
return scope_of_role(principal, await app_role(session, principal, app))
async def scope_of_run(session: AsyncSession, app_id: str | None, *, run_class: str | None,
started_by: str | None) -> dict[str, Any]:
"""一次运行看哪些行,记进 data_versions:{"rows": all|mine|none, "viewer"?: 发起人}。发起时定下,续跑、恢复沿用。"""
from app.api.deps import auth_mode
if run_class == "formal":
return {"rows": "all"}
mode = auth_mode()
if mode == "off":
return {"rows": "all"}
principal = await _principal(session, started_by, mode)
if principal is None:
return {"rows": "none"}
scope = await scope_of(session, principal, app_id)
return {"rows": scope, **({"viewer": principal.username} if scope == "mine" else {})}
async def _principal(session: AsyncSession, username: str | None, mode: str) -> Any | None:
from app.auth.sessions import principal_of
from app.db.models import User
if not username:
return None
user = (await session.execute(select(User).where(User.username == username))).scalar_one_or_none()
if user is None or user.disabled:
return None
return await principal_of(session, user, mode)