refactor: rebuild backend around role-site authorization model

This commit is contained in:
Chris
2026-04-02 23:58:13 +08:00
parent 0bc667847d
commit 2f92b94f59
43 changed files with 1593 additions and 2257 deletions

View File

@@ -1,113 +1,6 @@
from pydantic import BaseModel
from typing import Literal
from datetime import datetime
class SystemCreateRequest(BaseModel):
name: str
status: str = "active"
class SystemUpdateRequest(BaseModel):
name: str | None = None
status: str | None = None
class SystemItem(BaseModel):
id: str
system_key: str
name: str
status: str
class ModuleCreateRequest(BaseModel):
system_key: str
name: str
status: str = "active"
class ModuleUpdateRequest(BaseModel):
name: str | None = None
status: str | None = None
class ModuleItem(BaseModel):
id: str
system_key: str | None = None
module_key: str
name: str
status: str
class CompanyCreateRequest(BaseModel):
name: str
status: str = "active"
class CompanyUpdateRequest(BaseModel):
name: str | None = None
status: str | None = None
class CompanyItem(BaseModel):
id: str
company_key: str
name: str
status: str
class SiteCreateRequest(BaseModel):
company_key: str
name: str
status: str = "active"
class SiteUpdateRequest(BaseModel):
company_key: str | None = None
name: str | None = None
status: str | None = None
class SiteItem(BaseModel):
id: str
site_key: str
company_key: str
name: str
status: str
class MemberItem(BaseModel):
id: str
user_sub: str
username: str | None = None
email: str | None = None
display_name: str | None = None
is_active: bool
class MemberUpsertRequest(BaseModel):
user_sub: str | None = None
username: str | None = None
email: str | None = None
display_name: str | None = None
is_active: bool = True
sync_to_idp: bool = True
class MemberUpdateRequest(BaseModel):
username: str | None = None
email: str | None = None
display_name: str | None = None
is_active: bool | None = None
sync_to_idp: bool = True
class MemberPasswordResetResponse(BaseModel):
user_sub: str
temporary_password: str
class MemberPermissionGroupsUpdateRequest(BaseModel):
group_keys: list[str]
from pydantic import BaseModel, Field
class ListResponse(BaseModel):
@@ -117,62 +10,217 @@ class ListResponse(BaseModel):
offset: int
class PermissionGroupCreateRequest(BaseModel):
name: str
class CompanyCreateRequest(BaseModel):
display_name: str
legal_name: str | None = None
status: str = "active"
class PermissionGroupUpdateRequest(BaseModel):
name: str | None = None
class CompanyUpdateRequest(BaseModel):
display_name: str | None = None
legal_name: str | None = None
idp_group_id: str | None = None
status: str | None = None
class PermissionGroupItem(BaseModel):
class CompanyItem(BaseModel):
id: str
group_key: str
company_key: str
display_name: str
legal_name: str | None = None
idp_group_id: str | None = None
status: str
class SiteCreateRequest(BaseModel):
company_key: str
display_name: str
domain: str | None = None
status: str = "active"
class SiteUpdateRequest(BaseModel):
company_key: str | None = None
display_name: str | None = None
domain: str | None = None
idp_group_id: str | None = None
status: str | None = None
class SiteItem(BaseModel):
id: str
site_key: str
company_key: str
company_display_name: str
display_name: str
domain: str | None = None
idp_group_id: str | None = None
status: str
class SystemCreateRequest(BaseModel):
name: str
status: str
idp_client_id: str
status: str = "active"
class PermissionGroupPermissionItem(BaseModel):
class SystemUpdateRequest(BaseModel):
name: str | None = None
idp_client_id: str | None = None
status: str | None = None
class SystemItem(BaseModel):
id: str
system: str
module: str
action: Literal["view", "edit"]
scope_type: Literal["site"]
scope_id: str
class MemberPermissionGroupsResponse(BaseModel):
user_sub: str
group_keys: list[str]
class GroupBindingUpdateRequest(BaseModel):
site_keys: list[str]
system_keys: list[str]
module_keys: list[str]
member_subs: list[str]
actions: list[Literal["view", "edit"]]
class GroupBindingSnapshot(BaseModel):
group_key: str
site_keys: list[str]
system_keys: list[str]
module_keys: list[str]
member_subs: list[str]
actions: list[Literal["view", "edit"]]
class GroupRelationItem(BaseModel):
group_key: str
group_name: str
system_key: str
name: str
idp_client_id: str
status: str
class MemberRelationItem(BaseModel):
class RoleCreateRequest(BaseModel):
system_key: str
name: str
idp_role_name: str
description: str | None = None
status: str = "active"
class RoleUpdateRequest(BaseModel):
system_key: str | None = None
name: str | None = None
idp_role_name: str | None = None
description: str | None = None
status: str | None = None
class RoleItem(BaseModel):
id: str
role_key: str
system_key: str
system_name: str
name: str
idp_role_name: str
description: str | None = None
status: str
class MemberItem(BaseModel):
id: str
user_sub: str
idp_user_id: str | None = None
username: str | None = None
email: str | None = None
display_name: str | None = None
is_active: bool
status: str
class MemberUpsertRequest(BaseModel):
user_sub: str | None = None
username: str | None = None
email: str | None = None
display_name: str | None = None
is_active: bool = True
status: str = "active"
sync_to_idp: bool = True
class MemberUpdateRequest(BaseModel):
username: str | None = None
email: str | None = None
display_name: str | None = None
is_active: bool | None = None
status: str | None = None
sync_to_idp: bool = True
class MemberPasswordResetResponse(BaseModel):
user_sub: str
temporary_password: str
class SiteRoleAssignRequest(BaseModel):
role_keys: list[str] = Field(default_factory=list)
class SiteRoleItem(BaseModel):
id: str
role_key: str
role_name: str
system_key: str
system_name: str
class UserSiteAssignRequest(BaseModel):
site_keys: list[str] = Field(default_factory=list)
class UserSiteItem(BaseModel):
id: str
site_key: str
site_display_name: str
company_key: str
company_display_name: str
class UserEffectiveRoleItem(BaseModel):
site_key: str
site_display_name: str
company_key: str
company_display_name: str
system_key: str
system_name: str
role_key: str
role_name: str
idp_role_name: str
class UserEffectiveRolesResponse(BaseModel):
user_sub: str
roles: list[UserEffectiveRoleItem]
class SiteMembersResponse(BaseModel):
site_key: str
members: list[MemberItem]
class SiteRolesResponse(BaseModel):
site_key: str
roles: list[SiteRoleItem]
class UserSitesResponse(BaseModel):
user_sub: str
sites: list[UserSiteItem]
class CompanySitesResponse(BaseModel):
company_key: str
sites: list[SiteItem]
class SystemRolesResponse(BaseModel):
system_key: str
roles: list[RoleItem]
class RoleSitesResponse(BaseModel):
role_key: str
sites: list[UserSiteItem]
class ApiClientItem(BaseModel):
id: str
client_key: str
name: str
status: str
allowed_origins: list[str] = Field(default_factory=list)
allowed_ips: list[str] = Field(default_factory=list)
allowed_paths: list[str] = Field(default_factory=list)
rate_limit_per_min: int | None = None
expires_at: datetime | None = None
last_used_at: datetime | None = None
created_at: datetime
updated_at: datetime

View File

@@ -5,6 +5,7 @@ class InternalSystemItem(BaseModel):
id: str
system_key: str
name: str
idp_client_id: str
status: str
@@ -15,16 +16,19 @@ class InternalSystemListResponse(BaseModel):
offset: int
class InternalModuleItem(BaseModel):
class InternalRoleItem(BaseModel):
id: str
module_key: str
role_key: str
system_key: str
system_name: str
name: str
idp_role_name: str
description: str | None = None
status: str
class InternalModuleListResponse(BaseModel):
items: list[InternalModuleItem]
class InternalRoleListResponse(BaseModel):
items: list[InternalRoleItem]
total: int
limit: int
offset: int
@@ -33,7 +37,8 @@ class InternalModuleListResponse(BaseModel):
class InternalCompanyItem(BaseModel):
id: str
company_key: str
name: str
display_name: str
legal_name: str | None = None
status: str
@@ -47,8 +52,10 @@ class InternalCompanyListResponse(BaseModel):
class InternalSiteItem(BaseModel):
id: str
site_key: str
company_key: str | None = None
name: str
company_key: str
company_display_name: str
display_name: str
domain: str | None = None
status: str
@@ -66,6 +73,7 @@ class InternalMemberItem(BaseModel):
email: str | None = None
display_name: str | None = None
is_active: bool
status: str
class InternalMemberListResponse(BaseModel):
@@ -83,3 +91,21 @@ class InternalUpsertUserBySubResponse(BaseModel):
email: str | None = None
display_name: str | None = None
is_active: bool
status: str
class InternalUserRoleItem(BaseModel):
site_key: str
site_display_name: str
company_key: str
company_display_name: str
system_key: str
system_name: str
role_key: str
role_name: str
idp_role_name: str
class InternalUserRoleResponse(BaseModel):
user_sub: str
roles: list[InternalUserRoleItem]

View File

@@ -1,60 +1,18 @@
from datetime import datetime
from typing import Literal
from pydantic import BaseModel
ActionType = Literal["view", "edit"]
ScopeType = Literal["site"]
class RoleSnapshotItem(BaseModel):
site_key: str
site_display_name: str
company_key: str
company_display_name: str
system_key: str
system_name: str
role_key: str
role_name: str
idp_role_name: str
class PermissionGrantRequest(BaseModel):
class RoleSnapshotResponse(BaseModel):
user_sub: str
email: str | None = None
display_name: str | None = None
scope_type: ScopeType
scope_id: str
system: str
module: str | None = None
action: ActionType
class PermissionRevokeRequest(BaseModel):
user_sub: str
scope_type: ScopeType
scope_id: str
system: str
module: str | None = None
action: ActionType
class PermissionItem(BaseModel):
scope_type: ScopeType
scope_id: str
system: str | None = None
module: str
action: ActionType
class PermissionSnapshotResponse(BaseModel):
user_sub: str
permissions: list[PermissionItem]
class DirectPermissionRow(BaseModel):
permission_id: str
user_sub: str
email: str | None = None
display_name: str | None = None
scope_type: ScopeType
scope_id: str
system: str | None = None
module: str | None = None
action: ActionType
created_at: datetime
class DirectPermissionListResponse(BaseModel):
items: list[DirectPermissionRow]
total: int
limit: int
offset: int
roles: list[RoleSnapshotItem]

View File

@@ -7,3 +7,4 @@ class UserUpsertBySubRequest(BaseModel):
email: str | None = None
display_name: str | None = None
is_active: bool = True
status: str = "active"