refactor(auth): 账号类型彻底收敛为四种 + 各端口守卫改 service(去除冗余角色)
- 迁移守卫: provider/enterprise/government/investor/developer 一律 require_roles("service")
- token/profile.role 归一为四种(operator/carrier/opc_member/service); require_roles 与之一致
- 账号类型集中 app/domain/account_types.py; 子角色停用
This commit is contained in:
+4
-13
@@ -108,16 +108,7 @@ def _is_phone(account: str) -> bool:
|
||||
return bool(_PHONE_RE.match(account.strip()))
|
||||
|
||||
# 账户管理页可编辑的资料字段(username 作为登录名走 update_credentials,单独处理)
|
||||
_PROFILE_FIELDS = (
|
||||
"nickname",
|
||||
"account",
|
||||
"room",
|
||||
"avatar",
|
||||
"company_avatar",
|
||||
"email",
|
||||
"gender",
|
||||
"birthday",
|
||||
)
|
||||
_PROFILE_FIELDS = ("nickname", "account", "room", "avatar", "company_avatar", "email", "gender", "birthday")
|
||||
|
||||
|
||||
def _identity_summaries(identities: list[dict]) -> list[IdentityInfo]:
|
||||
@@ -157,7 +148,7 @@ async def _issue_token(
|
||||
scope_level = await db.regions.level(region_id)
|
||||
|
||||
token_user = dict(user)
|
||||
token_user.update(account_type=atype, role=role, sub_role=None, org_id=org_id, region_id=region_id)
|
||||
token_user.update(account_type=atype, role=atype, sub_role=None, org_id=org_id, region_id=region_id)
|
||||
await db.users.mark_login(user["id"]) # 记录最近登录时间(每次签发令牌=一次活动)
|
||||
return await db.tokens.create(
|
||||
token_user,
|
||||
@@ -199,9 +190,9 @@ async def _profile_for(
|
||||
profile["affiliation"] = user.get("affiliation", "independent")
|
||||
profile["park_id"] = user.get("park_id", "")
|
||||
profile["park_name"] = user.get("park_name", "")
|
||||
profile["account_type"] = atype # 四种账号类型(operator/carrier/opc/service)
|
||||
profile["account_type"] = atype # 四种账号类型(operator/carrier/opc/"service")
|
||||
profile["account_type_label"] = account_type_label(atype)
|
||||
profile["role"] = role # 端口角色(兼容守卫)
|
||||
profile["role"] = atype # 账号类型(四种)
|
||||
profile["sub_role"] = None # 子角色已停用
|
||||
profile["org_id"] = org_id
|
||||
profile["region_id"] = region_id
|
||||
|
||||
@@ -19,27 +19,27 @@ async def _page(port: str, page: str):
|
||||
|
||||
|
||||
@router.get("/dashboard", summary="开发者工作台")
|
||||
async def dev_dashboard(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))):
|
||||
async def dev_dashboard(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))):
|
||||
return await db.portal_pages.get("developer", "dashboard") or {"stats": []}
|
||||
|
||||
|
||||
@router.get("/apps", summary="我的应用")
|
||||
async def dev_apps(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))):
|
||||
async def dev_apps(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))):
|
||||
return await db.portal_pages.get("developer", "apps") or {"items": []}
|
||||
|
||||
|
||||
@router.get("/plugins", summary="我的插件")
|
||||
async def dev_plugins(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))):
|
||||
async def dev_plugins(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))):
|
||||
return await db.portal_pages.get("developer", "plugins") or {"items": []}
|
||||
|
||||
|
||||
@router.get("/skills", summary="技能市场")
|
||||
async def dev_skills(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))):
|
||||
async def dev_skills(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))):
|
||||
return await db.portal_pages.get("developer", "skills") or {"items": []}
|
||||
|
||||
|
||||
@router.get("/api-keys", summary="API 凭证")
|
||||
async def dev_api_keys(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))):
|
||||
async def dev_api_keys(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))):
|
||||
return {"items": [
|
||||
{"id": "key_001", "name": "生产环境", "prefix": "pa_live_****abcd", "created_at": "2026-07-01"},
|
||||
{"id": "key_002", "name": "测试环境", "prefix": "pa_test_****wxyz", "created_at": "2026-07-05"},
|
||||
|
||||
@@ -13,7 +13,7 @@ from ...infrastructure.repositories import Database
|
||||
|
||||
router = APIRouter(tags=["ecosystem"])
|
||||
|
||||
_ANY = ("opc_member", "carrier", "enterprise", "provider", "government", "operator", "investor")
|
||||
_ANY = ("opc_member", "carrier", "service", "operator")
|
||||
|
||||
|
||||
# ── 通知中心 ──────────────────────────────────────────────────────────────
|
||||
@@ -51,7 +51,7 @@ async def rate_task(
|
||||
req: RatingRequest,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("enterprise", "opc_member")),
|
||||
actor: dict = Depends(require_roles("service", "opc_member")),
|
||||
):
|
||||
if not req.to_id:
|
||||
raise HTTPException(status_code=400, detail="缺少被评对象")
|
||||
@@ -66,7 +66,7 @@ async def rate_task(
|
||||
async def get_contract(
|
||||
task_id: str,
|
||||
db: Database = Depends(get_db),
|
||||
_u: dict = Depends(require_roles("enterprise", "opc_member")),
|
||||
_u: dict = Depends(require_roles("service", "opc_member")),
|
||||
):
|
||||
contract = await db.contracts.get_for_task(task_id)
|
||||
if contract is None:
|
||||
@@ -80,7 +80,7 @@ async def sign_contract(
|
||||
req: SignRequest,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("enterprise", "opc_member")),
|
||||
actor: dict = Depends(require_roles("service", "opc_member")),
|
||||
):
|
||||
from ...services.settlement_service import SettlementService
|
||||
|
||||
@@ -96,7 +96,7 @@ async def release_escrow(
|
||||
task_id: str,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("enterprise")),
|
||||
actor: dict = Depends(require_roles("service")),
|
||||
):
|
||||
from ...services.settlement_service import SettlementService
|
||||
|
||||
@@ -122,7 +122,7 @@ async def create_dispute(
|
||||
req: DisputeRequest,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("enterprise", "opc_member")),
|
||||
actor: dict = Depends(require_roles("service", "opc_member")),
|
||||
):
|
||||
from ...services.settlement_service import SettlementService
|
||||
|
||||
@@ -151,7 +151,7 @@ async def resolve_dispute(
|
||||
@router.get("/investor/matches", summary="投资撮合(按偏好推荐)")
|
||||
async def investor_matches(
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles("investor")),
|
||||
user: dict = Depends(require_roles("service")),
|
||||
):
|
||||
from ...services.settlement_service import SettlementService
|
||||
|
||||
@@ -164,7 +164,7 @@ async def join_roadshow(
|
||||
roadshow_id: str,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("investor", "government", "operator", "carrier", "enterprise")),
|
||||
actor: dict = Depends(require_roles("service", "operator", "carrier")),
|
||||
):
|
||||
rs = await db.roadshows.get(roadshow_id)
|
||||
if rs is None:
|
||||
|
||||
@@ -19,7 +19,7 @@ from ...infrastructure.repositories import Database
|
||||
router = APIRouter(prefix="/investor", tags=["investor"])
|
||||
|
||||
# 可发布投融资活动的端口角色(审核规则见 _need_review)
|
||||
_ROADSHOW_ROLES = ("investor", "government", "operator", "carrier", "enterprise")
|
||||
_ROADSHOW_ROLES = ("service", "operator", "carrier")
|
||||
|
||||
|
||||
def _need_review(user: dict, req: RoadshowCreate, db: Database) -> bool:
|
||||
@@ -27,7 +27,7 @@ def _need_review(user: dict, req: RoadshowCreate, db: Database) -> bool:
|
||||
role = user.get("role")
|
||||
if role == "operator":
|
||||
return False
|
||||
if role == "government":
|
||||
if role == "service":
|
||||
scope = user.get("scope_region_ids", [])
|
||||
if req.scope_type == "region" and req.region_id and req.region_id in scope:
|
||||
return False # 自身权限范围内,免审
|
||||
@@ -43,7 +43,7 @@ def _pub_status(need_review: bool) -> str:
|
||||
@router.get("/dashboard", summary="投资人工作台")
|
||||
async def investor_dashboard(
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles("investor")),
|
||||
user: dict = Depends(require_roles("service")),
|
||||
):
|
||||
pref = await db.investor_prefs.get(user["id"]) or {}
|
||||
portfolio = await db.portal_pages.get("investor", "portfolio") or {}
|
||||
@@ -59,7 +59,7 @@ async def investor_dashboard(
|
||||
@router.get("/preferences", summary="投资方向")
|
||||
async def get_preferences(
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles("investor")),
|
||||
user: dict = Depends(require_roles("service")),
|
||||
):
|
||||
return await db.investor_prefs.get(user["id"]) or {}
|
||||
|
||||
@@ -69,7 +69,7 @@ async def set_preferences(
|
||||
req: PreferenceRequest,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("investor")),
|
||||
actor: dict = Depends(require_roles("service")),
|
||||
):
|
||||
pref = await db.investor_prefs.upsert(actor["id"], req.model_dump(exclude_none=True))
|
||||
await write_audit(db, action="preference.update", resource="investor", resource_id=actor["id"],
|
||||
@@ -80,7 +80,7 @@ async def set_preferences(
|
||||
@router.get("/projects", summary="项目库")
|
||||
async def list_projects(
|
||||
db: Database = Depends(get_db),
|
||||
_u: dict = Depends(require_roles("investor")),
|
||||
_u: dict = Depends(require_roles("service")),
|
||||
):
|
||||
return await db.portal_pages.get("investor", "projects") or {"items": []}
|
||||
|
||||
@@ -88,7 +88,7 @@ async def list_projects(
|
||||
@router.get("/trainings", summary="投融资培训")
|
||||
async def list_trainings(
|
||||
db: Database = Depends(get_db),
|
||||
_u: dict = Depends(require_roles("investor")),
|
||||
_u: dict = Depends(require_roles("service")),
|
||||
):
|
||||
return await db.portal_pages.get("investor", "trainings") or {"items": []}
|
||||
|
||||
@@ -98,7 +98,7 @@ async def enroll_training(
|
||||
training_id: str,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("investor")),
|
||||
actor: dict = Depends(require_roles("service")),
|
||||
):
|
||||
data = await db.portal_pages.get("investor", "trainings") or {"items": []}
|
||||
item = next((it for it in data.get("items", []) if it.get("title") == training_id), None)
|
||||
@@ -112,7 +112,7 @@ async def enroll_training(
|
||||
@router.get("/my-trainings", summary="我的培训")
|
||||
async def my_trainings(
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles("investor")),
|
||||
user: dict = Depends(require_roles("service")),
|
||||
):
|
||||
return {"items": await db.training_enrolls.list_for(user["id"])}
|
||||
|
||||
@@ -120,7 +120,7 @@ async def my_trainings(
|
||||
@router.get("/portfolio", summary="投资组合")
|
||||
async def portfolio(
|
||||
db: Database = Depends(get_db),
|
||||
_u: dict = Depends(require_roles("investor")),
|
||||
_u: dict = Depends(require_roles("service")),
|
||||
):
|
||||
return await db.portal_pages.get("investor", "portfolio") or {"items": []}
|
||||
|
||||
@@ -131,7 +131,7 @@ async def create_intent(
|
||||
req: IntentRequest,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("investor")),
|
||||
actor: dict = Depends(require_roles("service")),
|
||||
):
|
||||
intent = await db.intents.create(
|
||||
actor["id"], req.project_id or project_id, req.project_name, req.message,
|
||||
@@ -144,7 +144,7 @@ async def create_intent(
|
||||
@router.get("/intents", summary="我的投资意向")
|
||||
async def list_intents(
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles("investor")),
|
||||
user: dict = Depends(require_roles("service")),
|
||||
):
|
||||
return {"items": await db.intents.list_for(user["id"])}
|
||||
|
||||
|
||||
@@ -16,9 +16,7 @@ router = APIRouter(tags=["org"])
|
||||
@router.get("/org/me", summary="当前组织信息")
|
||||
async def org_me(
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles(
|
||||
"opc_member", "carrier", "enterprise", "provider", "government", "operator",
|
||||
)),
|
||||
user: dict = Depends(require_roles("opc_member", "carrier", "service", "operator")),
|
||||
):
|
||||
org = await db.orgs.get(user["org_id"]) if user.get("org_id") else None
|
||||
region = await db.regions.get(user["region_id"]) if user.get("region_id") else None
|
||||
@@ -34,7 +32,7 @@ async def org_me(
|
||||
@router.get("/enterprise/profile", summary="企业资料")
|
||||
async def enterprise_profile(
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles("enterprise")),
|
||||
user: dict = Depends(require_roles("service")),
|
||||
):
|
||||
org = await db.orgs.get(user["org_id"]) if user.get("org_id") else None
|
||||
if org is None:
|
||||
@@ -55,7 +53,7 @@ async def carrier_enterprises(
|
||||
|
||||
@router.get("/provider/orders", summary="服务商订单(骨架)")
|
||||
async def provider_orders(
|
||||
user: dict = Depends(require_roles("provider")),
|
||||
user: dict = Depends(require_roles("service")),
|
||||
):
|
||||
"""占位:服务商仅返回本 org 的订单(业务逻辑后续阶段补齐)。"""
|
||||
return {"org_id": user.get("org_id"), "orders": []}
|
||||
@@ -67,7 +65,7 @@ async def provider_orders(
|
||||
async def org_members(
|
||||
org_id: str,
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles("enterprise", "carrier", "provider", "investor", "operator")),
|
||||
user: dict = Depends(require_roles("service", "carrier", "operator")),
|
||||
):
|
||||
# 机构管理员本人 或 平台运营 可查看
|
||||
if user.get("role") not in ("operator",) and not await db.org_members.is_admin(org_id, user["id"]):
|
||||
@@ -80,7 +78,7 @@ async def org_add_member(
|
||||
org_id: str,
|
||||
req: OrgMemberAdd,
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles("enterprise", "carrier", "provider", "investor", "operator")),
|
||||
user: dict = Depends(require_roles("service", "carrier", "operator")),
|
||||
):
|
||||
if user.get("role") not in ("operator",) and not await db.org_members.is_admin(org_id, user["id"]):
|
||||
raise HTTPException(status_code=403, detail="Forbidden: not org admin")
|
||||
@@ -98,7 +96,7 @@ async def org_add_member(
|
||||
@router.get("/me/orgs", summary="我加入的机构")
|
||||
async def my_orgs(
|
||||
db: Database = Depends(get_db),
|
||||
user: dict = Depends(require_roles("enterprise", "carrier", "provider", "investor")),
|
||||
user: dict = Depends(require_roles("service", "carrier")),
|
||||
):
|
||||
"""返回当前账号挂靠的所有机构及成员角色(支持一账号多机构)。"""
|
||||
from ...services.org_service import OrgService
|
||||
|
||||
@@ -79,7 +79,7 @@ router.get("/government/policies", summary="政务·政策管理")(_page("govern
|
||||
@router.get("/enterprise/tasks", summary="企业·我的任务列表")
|
||||
async def enterprise_tasks(
|
||||
db: Database = Depends(get_db),
|
||||
_u: dict = Depends(require_roles("enterprise")),
|
||||
_u: dict = Depends(require_roles("service")),
|
||||
):
|
||||
return {"items": await db.tasks.list(status="published")}
|
||||
|
||||
@@ -89,7 +89,7 @@ async def enterprise_create_task(
|
||||
req: EnterpriseTaskCreate,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("enterprise")),
|
||||
actor: dict = Depends(require_roles("service")),
|
||||
):
|
||||
task = await db.tasks.create({**req.model_dump(exclude_none=True), "status": "pending"})
|
||||
await write_audit(db, action="task.publish", resource="task", resource_id=task["id"],
|
||||
@@ -102,7 +102,7 @@ async def enterprise_submit_task(
|
||||
task_id: str,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("enterprise")),
|
||||
actor: dict = Depends(require_roles("service")),
|
||||
):
|
||||
task = await db.tasks.set_status(task_id, "published")
|
||||
if task is None:
|
||||
@@ -116,7 +116,7 @@ async def enterprise_submit_task(
|
||||
async def enterprise_list_bids(
|
||||
task_id: str,
|
||||
db: Database = Depends(get_db),
|
||||
_u: dict = Depends(require_roles("enterprise")),
|
||||
_u: dict = Depends(require_roles("service")),
|
||||
):
|
||||
return {"items": await db.bids.list_for_task(task_id)}
|
||||
|
||||
@@ -126,7 +126,7 @@ async def enterprise_win_bid(
|
||||
task_id: str, bid_id: str,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("enterprise")),
|
||||
actor: dict = Depends(require_roles("service")),
|
||||
):
|
||||
bid = await db.bids.set_status(bid_id, "win")
|
||||
if bid is None:
|
||||
@@ -143,7 +143,7 @@ async def enterprise_review_task(
|
||||
req: TaskReviewRequest,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_roles("enterprise")),
|
||||
actor: dict = Depends(require_roles("service")),
|
||||
):
|
||||
task = await db.tasks.get(task_id)
|
||||
if task is None:
|
||||
|
||||
Reference in New Issue
Block a user