Files
server-core/app/domain/membership.py
T
Pine dbc29eee59 feat(membership): 成员制归属重构与叠加制身份(多对多成员表+转园两级审核)
- park_members/company_members 多对多成员表(0028),users.affiliation 为派生缓存由 sync_user_affiliation 刷新
- 转园两级审核状态机(0029):pending_from→pending_to→approved,支持用户/企业整体转园与运营端兜底
- 叠加制身份(0030):身份恒为运营/载体/OPC,企业管理员为能力叠加非身份,去除 enterprise/carrier 直写角色
- rbac 新增 memberships/park-transfers/企业管理员工作台 /admin/ent/* 接口

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-31 20:36:26 +08:00

67 lines
2.8 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.
# -*- coding: utf-8 -*-
"""成员关系领域规则(用户↔园区 / 用户↔企业)—— 权限矩阵与归属铁律集中于此。
铁律:**任何端口不允许直接调整用户/企业的所属园区**,必须通过转园申请
app/domain/park_transfer.py 审批通过后的 transfer 动作是唯一写路径)。
users.affiliation / park_id / park_name 仅作派生展示缓存,由 sync_user_affiliation 刷新。
"""
from __future__ import annotations
MEMBER_TYPES = ("admin", "staff", "owner", "migrated")
COMPANY_KINDS = ("park_entered", "independent") # 企业类型:园区入驻 | 独立
USER_KINDS = ("park", "independent") # 用户类型:园区入驻 | 独立(由园区成员派生)
class MembershipError(Exception):
"""成员/归属操作违规(由路由层转 400/403)。"""
def assert_not_changing_park(actor_role: str, target_park_id: str | None = None, new_park_id: str | None = None):
"""禁止任何端口直接改写所属园区(唯一豁免:转园申请审批通过后的内部迁移)。"""
raise MembershipError("不允许直接调整所属园区,请通过转园申请")
def can_create_user(actor_role: str) -> bool:
"""创建用户:运营端(全局) / 园区端(本园区)。企业管理员不可建号(防提权)。"""
return actor_role in ("operator", "carrier")
def can_create_company(actor_role: str, kind: str) -> bool:
"""创建企业:运营端(含独立企业)/ 园区端(仅园区入驻企业)。"""
if actor_role == "operator":
return kind in COMPANY_KINDS
if actor_role == "carrier":
return kind == "park_entered"
return False
def can_bind_park_admin(actor_role: str) -> bool:
"""绑定园区管理员:仅运营端。"""
return actor_role == "operator"
def can_bind_company_admin(actor_role: str, company_tenant_id: str, my_park_id: str = "") -> bool:
"""绑定企业管理员:运营端(任意企业)/ 园区端(本园区企业)。"""
if actor_role == "operator":
return True
if actor_role == "carrier":
return bool(company_tenant_id) and company_tenant_id == my_park_id
return False
def can_bind_company_member(actor_role: str, company_tenant_id: str, my_park_id: str = "",
is_company_admin: bool = False) -> bool:
"""绑定企业用户:运营端 / 园区端(本园区企业) / 企业管理员(本企业)。"""
if actor_role == "operator":
return True
if actor_role == "carrier":
return bool(company_tenant_id) and company_tenant_id == my_park_id
if actor_role == "enterprise":
return is_company_admin
return False
def can_view_park_scope(actor_role: str) -> bool:
"""园区端可查看/编辑本园区企业与用户(不可删除)。"""
return actor_role in ("operator", "carrier")