Skip to content

Commit

Permalink
Merge pull request #14 from daichen-daisy/main
Browse files Browse the repository at this point in the history
feat: create 3 new apis to manage the connection between role and user
  • Loading branch information
XeniaLu authored May 11, 2023
2 parents 4390c10 + c6f01cd commit 3f99ee7
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 8 deletions.
105 changes: 97 additions & 8 deletions src/freeauth/query_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
# 'src/freeauth/organizations/queries/query_org_types.edgeql'
# 'src/freeauth/roles/queries/query_organization_roles.edgeql'
# 'src/freeauth/users/queries/resign_user.edgeql'
# 'src/freeauth/roles/queries/role_bind_users.edgeql'
# 'src/freeauth/roles/queries/role_unbind_users.edgeql'
# 'src/freeauth/auth/queries/send_code.edgeql'
# 'src/freeauth/auth/queries/sign_in.edgeql'
# 'src/freeauth/auth/queries/sign_up.edgeql'
Expand Down Expand Up @@ -250,6 +252,26 @@ class QueryOrganizationRolesResult(NoPydanticValidation):
is_department_role: bool


@dataclasses.dataclass
class RoleBindUsersResult(NoPydanticValidation):
id: uuid.UUID
name: str | None
username: str | None
email: str | None
mobile: str | None
departments: list[RoleBindUsersResultDepartmentsItem]
is_deleted: bool
created_at: datetime.datetime
last_login_at: datetime.datetime | None


@dataclasses.dataclass
class RoleBindUsersResultDepartmentsItem(NoPydanticValidation):
id: uuid.UUID
code: str | None
name: str


@dataclasses.dataclass
class SendCodeResult(NoPydanticValidation):
id: uuid.UUID
Expand Down Expand Up @@ -296,20 +318,13 @@ class UpdateUserRolesResult(NoPydanticValidation):
username: str | None
email: str | None
mobile: str | None
departments: list[UpdateUserRolesResultDepartmentsItem]
departments: list[RoleBindUsersResultDepartmentsItem]
roles: list[UpdateUserRolesResultRolesItem]
is_deleted: bool
created_at: datetime.datetime
last_login_at: datetime.datetime | None


@dataclasses.dataclass
class UpdateUserRolesResultDepartmentsItem(NoPydanticValidation):
id: uuid.UUID
code: str | None
name: str


@dataclasses.dataclass
class UpdateUserRolesResultRolesItem(NoPydanticValidation):
id: uuid.UUID
Expand Down Expand Up @@ -1080,6 +1095,80 @@ async def resign_user(
)


async def role_bind_users(
executor: edgedb.AsyncIOExecutor,
*,
user_ids: list[uuid.UUID],
role_ids: list[uuid.UUID],
) -> list[RoleBindUsersResult]:
return await executor.query(
"""\
WITH
user_ids := <array<uuid>>$user_ids,
role_ids := <array<uuid>>$role_ids
SELECT (
UPDATE User FILTER .id in array_unpack(user_ids)
SET {
roles += (
SELECT Role
FILTER .id IN array_unpack(role_ids)
)
}
) {
name,
username,
email,
mobile,
departments := (
SELECT .directly_organizations { id, code, name }
),
is_deleted,
created_at,
last_login_at
};\
""",
user_ids=user_ids,
role_ids=role_ids,
)


async def role_unbind_users(
executor: edgedb.AsyncIOExecutor,
*,
user_ids: list[uuid.UUID],
role_ids: list[uuid.UUID],
) -> list[RoleBindUsersResult]:
return await executor.query(
"""\
WITH
user_ids := <array<uuid>>$user_ids,
role_ids := <array<uuid>>$role_ids
SELECT (
UPDATE User FILTER .id in array_unpack(user_ids)
SET {
roles -= (
SELECT Role
FILTER .id IN array_unpack(role_ids)
)
}
) {
name,
username,
email,
mobile,
departments := (
SELECT .directly_organizations { id, code, name }
),
is_deleted,
created_at,
last_login_at
};\
""",
user_ids=user_ids,
role_ids=role_ids,
)


async def send_code(
executor: edgedb.AsyncIOExecutor,
*,
Expand Down
16 changes: 16 additions & 0 deletions src/freeauth/roles/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,19 @@ class OrganizationRoleQueryBody:
"支持按角色状态进行过滤,true 代表已禁用的角色,false 代表已启用的角色"
),
)


@dataclass(config=BaseModelConfig)
class RoleUserBody:
role_ids: list[uuid.UUID] = Field(
...,
title="角色 ID 列表",
description="可设置一个或多个角色D",
min_items=1,
)
user_ids: list[uuid.UUID] = Field(
...,
title="用户 ID 列表",
description="待添加的用户 ID 列表",
min_items=1,
)
103 changes: 103 additions & 0 deletions src/freeauth/roles/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
CreateRoleResult,
DeleteRoleResult,
QueryOrganizationRolesResult,
RoleBindUsersResult,
UpdateRoleStatusResult,
create_role,
delete_role,
get_role_by_id_or_code,
query_organization_roles,
role_bind_users,
role_unbind_users,
update_role,
update_role_status,
)
Expand All @@ -27,6 +30,7 @@
RolePostBody,
RolePutBody,
RoleStatusBody,
RoleUserBody,
)
from .dependencies import parse_role_id_or_code, validate_organization_ids

Expand Down Expand Up @@ -227,3 +231,102 @@ async def get_organization_roles(
role_type=body.role_type,
is_deleted=body.is_deleted,
)


@router.post(
"/roles/{role_id}/users",
tags=["角色管理"],
summary="获取角色绑定用户列表",
description="获取指定角色下绑定的用户,分页获取,支持关键字搜索、排序",
)
async def get_members_in_organization(
body: QueryBody,
role_id: uuid.UUID,
client: edgedb.AsyncIOClient = Depends(get_edgedb_client),
) -> PaginatedData:
result = await client.query_single_json(
f"""\
WITH
page := <optional int64>$page ?? 1,
per_page := <optional int64>$per_page ?? 20,
q := <optional str>$q,
role := (
SELECT Role FILTER .id = <uuid>$role_id
),
users := (
SELECT (
role.users
) FILTER (
true IF not EXISTS q ELSE
.name ?? '' ILIKE q OR
.username ?? '' ILIKE q OR
.mobile ?? '' ILIKE q OR
.email ?? '' ILIKE q
)
),
total := count(users)
SELECT (
total := total,
per_page := per_page,
page := page,
last := math::ceil(total / per_page),
rows := array_agg((
SELECT users {{
id,
name,
username,
email,
mobile,
departments := (
SELECT .directly_organizations {{
id,
code,
name
}}
),
is_deleted,
created_at,
last_login_at
}}
ORDER BY {body.ordering_expr}
OFFSET (page - 1) * per_page
LIMIT per_page
))
);\
""",
q=f"%{body.q}%" if body.q else None,
page=body.page,
per_page=body.per_page,
role_id=role_id,
)
return PaginatedData.parse_raw(result)


@router.post(
"/roles/bind_users",
tags=["角色管理"],
summary="添加用户",
description="关联一个或多个用户到角色",
)
async def bind_users_to_roles(
body: RoleUserBody,
client: edgedb.AsyncIOClient = Depends(get_edgedb_client),
) -> list[RoleBindUsersResult]:
return await role_bind_users(
client, user_ids=body.user_ids, role_ids=body.role_ids
)


@router.post(
"/roles/unbind_users",
tags=["角色管理"],
summary="添加用户",
description="关联一个或多个用户到角色",
)
async def unbind_users_to_roles(
body: RoleUserBody,
client: edgedb.AsyncIOClient = Depends(get_edgedb_client),
) -> list[RoleBindUsersResult]:
return await role_unbind_users(
client, user_ids=body.user_ids, role_ids=body.role_ids
)
23 changes: 23 additions & 0 deletions src/freeauth/roles/queries/role_bind_users.edgeql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
WITH
user_ids := <array<uuid>>$user_ids,
role_ids := <array<uuid>>$role_ids
SELECT (
UPDATE User FILTER .id in array_unpack(user_ids)
SET {
roles += (
SELECT Role
FILTER .id IN array_unpack(role_ids)
)
}
) {
name,
username,
email,
mobile,
departments := (
SELECT .directly_organizations { id, code, name }
),
is_deleted,
created_at,
last_login_at
};
23 changes: 23 additions & 0 deletions src/freeauth/roles/queries/role_unbind_users.edgeql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
WITH
user_ids := <array<uuid>>$user_ids,
role_ids := <array<uuid>>$role_ids
SELECT (
UPDATE User FILTER .id in array_unpack(user_ids)
SET {
roles -= (
SELECT Role
FILTER .id IN array_unpack(role_ids)
)
}
) {
name,
username,
email,
mobile,
departments := (
SELECT .directly_organizations { id, code, name }
),
is_deleted,
created_at,
last_login_at
};

0 comments on commit 3f99ee7

Please sign in to comment.