Skip to content

Commit 619d269

Browse files
committedMay 7, 2023
feat: api for changing a person's organizations
fix: #8
1 parent 71c05ed commit 619d269

11 files changed

+215
-34
lines changed
 

‎dbschema/migrations/00015.edgeql

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CREATE MIGRATION m1u4ogrpaes2irqcrqrvjhawbhoehnabnjviqcyzumxknee6lhx4la
2+
ONTO m1qwqxduinfru3jpz46hrkbcrzhywg5jrueyq25heou42yvbb4jxoa
3+
{
4+
ALTER TYPE default::Organization {
5+
CREATE REQUIRED PROPERTY hierarchy := (std::count([IS default::Department].ancestors));
6+
};
7+
};

‎dbschema/organizations.esdl

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module default {
1717
required property name -> str;
1818
property code -> str;
1919
property code_upper := str_upper(.code);
20+
required property hierarchy := count([is Department].ancestors);
2021

2122
multi link directly_children := .<parent[is Department];
2223
multi link children := .<ancestors[is Department];

‎src/freeauth/organizations/endpoints.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,11 @@ async def get_members_in_organization(
564564
email,
565565
mobile,
566566
departments := (
567-
SELECT .directly_organizations {{ code, name }}
567+
SELECT .directly_organizations {{
568+
id,
569+
code,
570+
name
571+
}}
568572
),
569573
is_deleted,
570574
created_at,

‎src/freeauth/query_api.py

+57-9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
# 'src/freeauth/users/queries/get_user_by_id.edgeql'
1818
# 'src/freeauth/organizations/queries/organization_add_member.edgeql'
1919
# 'src/freeauth/organizations/queries/query_org_types.edgeql'
20+
# 'src/freeauth/users/queries/resign_user.edgeql'
2021
# 'src/freeauth/auth/queries/send_code.edgeql'
2122
# 'src/freeauth/auth/queries/sign_in.edgeql'
2223
# 'src/freeauth/auth/queries/sign_up.edgeql'
@@ -25,6 +26,7 @@
2526
# 'src/freeauth/organizations/queries/update_org_type.edgeql'
2627
# 'src/freeauth/organizations/queries/update_org_type_status.edgeql'
2728
# 'src/freeauth/users/queries/update_user.edgeql'
29+
# 'src/freeauth/users/queries/update_user_organization.edgeql'
2830
# 'src/freeauth/users/queries/update_user_status.edgeql'
2931
# 'src/freeauth/settings/queries/upsert_login_setting.edgeql'
3032
# 'src/freeauth/auth/queries/validate_code.edgeql'
@@ -807,6 +809,25 @@ async def query_org_types(
807809
)
808810

809811

812+
async def resign_user(
813+
executor: edgedb.AsyncIOExecutor,
814+
*,
815+
user_ids: list[uuid.UUID],
816+
) -> list[DeleteUserResult]:
817+
return await executor.query(
818+
"""\
819+
SELECT (
820+
UPDATE User FILTER .id in array_unpack(<array<uuid>>$user_ids)
821+
SET {
822+
directly_organizations := {},
823+
deleted_at := datetime_of_transaction()
824+
}
825+
) { name } ORDER BY .created_at DESC;\
826+
""",
827+
user_ids=user_ids,
828+
)
829+
830+
810831
async def send_code(
811832
executor: edgedb.AsyncIOExecutor,
812833
*,
@@ -1210,7 +1231,6 @@ async def update_user(
12101231
username: str | None,
12111232
email: str | None,
12121233
mobile: str | None,
1213-
organization_ids: list[uuid.UUID] | None,
12141234
id: uuid.UUID,
12151235
) -> CreateUserResult | None:
12161236
return await executor.query_single(
@@ -1219,19 +1239,14 @@ async def update_user(
12191239
name := <optional str>$name,
12201240
username := <optional str>$username,
12211241
email := <optional str>$email,
1222-
mobile := <optional str>$mobile,
1223-
organization_ids := <optional array<uuid>>$organization_ids
1242+
mobile := <optional str>$mobile
12241243
SELECT (
12251244
UPDATE User FILTER .id = <uuid>$id
12261245
SET {
12271246
name := name,
12281247
username := username,
12291248
email := email,
1230-
mobile := mobile,
1231-
directly_organizations := (
1232-
SELECT Organization
1233-
FILTER .id IN array_unpack(organization_ids)
1234-
)
1249+
mobile := mobile
12351250
}
12361251
) {
12371252
name,
@@ -1250,11 +1265,44 @@ async def update_user(
12501265
username=username,
12511266
email=email,
12521267
mobile=mobile,
1253-
organization_ids=organization_ids,
12541268
id=id,
12551269
)
12561270

12571271

1272+
async def update_user_organization(
1273+
executor: edgedb.AsyncIOExecutor,
1274+
*,
1275+
id: uuid.UUID,
1276+
organization_ids: list[uuid.UUID],
1277+
) -> CreateUserResult | None:
1278+
return await executor.query_single(
1279+
"""\
1280+
SELECT (
1281+
UPDATE User FILTER .id = <uuid>$id
1282+
SET {
1283+
directly_organizations := (
1284+
SELECT Organization
1285+
FILTER .id IN array_unpack(<array<uuid>>$organization_ids)
1286+
)
1287+
}
1288+
) {
1289+
name,
1290+
username,
1291+
email,
1292+
mobile,
1293+
departments := (
1294+
SELECT .directly_organizations { code, name }
1295+
),
1296+
is_deleted,
1297+
created_at,
1298+
last_login_at
1299+
};\
1300+
""",
1301+
id=id,
1302+
organization_ids=organization_ids,
1303+
)
1304+
1305+
12581306
async def update_user_status(
12591307
executor: edgedb.AsyncIOExecutor,
12601308
*,

‎src/freeauth/users/dataclasses.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,26 @@ class UserPutBody:
9393
description="仅支持中国大陆11位手机号码,可接收短信验证邮件",
9494
regex=MOBILE_REGEX,
9595
)
96-
organization_ids: list[uuid.UUID] | None = Field(
97-
None,
96+
97+
98+
@dataclass(config=BaseModelConfig)
99+
class UserOrganizationBody:
100+
organization_ids: list[uuid.UUID] = Field(
101+
...,
98102
title="直属部门 ID 列表",
99103
description="可设置一个或多个部门分支或企业机构 ID",
100104
)
101105

102106

107+
@dataclass(config=BaseModelConfig)
108+
class UserResignationBody:
109+
user_ids: list[uuid.UUID] = Field(
110+
...,
111+
title="用户 ID 列表",
112+
description="待离职的用户 ID 列表",
113+
)
114+
115+
103116
@dataclass(config=UserBodyConfig)
104117
class UserStatusBody:
105118
user_ids: List[uuid.UUID] = Field(

‎src/freeauth/users/endpoints.py

+39-1
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,18 @@
1717
create_user,
1818
delete_user,
1919
get_user_by_id,
20+
resign_user,
2021
update_user,
22+
update_user_organization,
2123
update_user_status,
2224
)
2325
from ..utils import gen_random_string, get_password_hash
2426
from .dataclasses import (
2527
UserDeleteBody,
28+
UserOrganizationBody,
2629
UserPostBody,
2730
UserPutBody,
31+
UserResignationBody,
2832
UserStatusBody,
2933
)
3034

@@ -120,7 +124,6 @@ async def put_user(
120124
email=user.email,
121125
mobile=user.mobile,
122126
id=user_id,
123-
organization_ids=user.organization_ids,
124127
)
125128
except edgedb.errors.ConstraintViolationError as e:
126129
field = str(e).split(" ")[0]
@@ -135,6 +138,41 @@ async def put_user(
135138
return updated_user
136139

137140

141+
@router.put(
142+
"/users/{user_id}/organizations",
143+
tags=["组织管理"],
144+
summary="变更部门",
145+
description="变更指定用户的直属部门或企业机构",
146+
)
147+
async def update_member_organizations(
148+
user_id: uuid.UUID,
149+
body: UserOrganizationBody,
150+
client: edgedb.AsyncIOClient = Depends(get_edgedb_client),
151+
) -> CreateUserResult | None:
152+
user: CreateUserResult | None = await update_user_organization(
153+
client, id=user_id, organization_ids=body.organization_ids
154+
)
155+
if not user:
156+
raise HTTPException(
157+
status_code=HTTPStatus.NOT_FOUND, detail="用户不存在"
158+
)
159+
return user
160+
161+
162+
@router.post(
163+
"/users/resign",
164+
tags=["组织管理"],
165+
summary="办理离职",
166+
description="支持批量为多个成员办理离职",
167+
)
168+
async def resign_users(
169+
body: UserResignationBody,
170+
client: edgedb.AsyncIOClient = Depends(get_edgedb_client),
171+
) -> list[DeleteUserResult]:
172+
user_ids: List[uuid.UUID] = body.user_ids
173+
return await resign_user(client, user_ids=user_ids)
174+
175+
138176
@router.get(
139177
"/users/{user_id}",
140178
tags=["用户管理"],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
SELECT (
2+
UPDATE User FILTER .id in array_unpack(<array<uuid>>$user_ids)
3+
SET {
4+
directly_organizations := {},
5+
deleted_at := datetime_of_transaction()
6+
}
7+
) { name } ORDER BY .created_at DESC;

‎src/freeauth/users/queries/update_user.edgeql

+2-7
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,14 @@ WITH
22
name := <optional str>$name,
33
username := <optional str>$username,
44
email := <optional str>$email,
5-
mobile := <optional str>$mobile,
6-
organization_ids := <optional array<uuid>>$organization_ids
5+
mobile := <optional str>$mobile
76
SELECT (
87
UPDATE User FILTER .id = <uuid>$id
98
SET {
109
name := name,
1110
username := username,
1211
email := email,
13-
mobile := mobile,
14-
directly_organizations := (
15-
SELECT Organization
16-
FILTER .id IN array_unpack(organization_ids)
17-
)
12+
mobile := mobile
1813
}
1914
) {
2015
name,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
SELECT (
2+
UPDATE User FILTER .id = <uuid>$id
3+
SET {
4+
directly_organizations := (
5+
SELECT Organization
6+
FILTER .id IN array_unpack(<array<uuid>>$organization_ids)
7+
)
8+
}
9+
) {
10+
name,
11+
username,
12+
email,
13+
mobile,
14+
departments := (
15+
SELECT .directly_organizations { code, name }
16+
),
17+
is_deleted,
18+
created_at,
19+
last_login_at
20+
};

0 commit comments

Comments
 (0)