Skip to content

Commit 7d0c20e

Browse files
committed
Add some interfaces for user profiles
1 parent 24a487e commit 7d0c20e

File tree

3 files changed

+132
-80
lines changed

3 files changed

+132
-80
lines changed

backend/app/admin/api/v1/sys/user.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# -*- coding: utf-8 -*-
33
from typing import Annotated
44

5-
from fastapi import APIRouter, Depends, Path, Query, Request
5+
from fastapi import APIRouter, Body, Depends, Path, Query, Request
66

77
from backend.app.admin.schema.role import GetRoleDetail
88
from backend.app.admin.schema.user import (
@@ -71,7 +71,7 @@ async def create_user(request: Request, obj: AddUserParam) -> ResponseSchemaMode
7171
return response_base.success(data=data)
7272

7373

74-
@router.put('/{pk}', summary='更新用户信息', dependencies=[DependsJwtAuth])
74+
@router.put('/{pk}', summary='更新用户信息', dependencies=[DependsRBAC])
7575
async def update_user(
7676
request: Request, pk: Annotated[int, Path(description='用户 ID')], obj: UpdateUserParam
7777
) -> ResponseModel:
@@ -93,11 +93,41 @@ async def update_user_permission(
9393
return response_base.fail()
9494

9595

96-
@router.put('/{pk}/password', summary='重置用户密码', dependencies=[DependsJwtAuth])
96+
@router.put('/me/password', summary='更新当前用户密码', dependencies=[DependsJwtAuth])
97+
async def update_user_password(request: Request, obj: ResetPasswordParam) -> ResponseModel:
98+
count = await user_service.update_password(request=request, obj=obj)
99+
if count > 0:
100+
return response_base.success()
101+
return response_base.fail()
102+
103+
104+
@router.put('/{pk}/password', summary='重置用户密码', dependencies=[DependsRBAC])
97105
async def reset_user_password(
98-
pk: Annotated[int, Path(description='用户 ID')], obj: ResetPasswordParam
106+
request: Request,
107+
pk: Annotated[int, Path(description='用户 ID')],
108+
password: Annotated[str, Body(embed=True, description='新密码')],
109+
) -> ResponseModel:
110+
count = await user_service.reset_password(request=request, pk=pk, password=password)
111+
if count > 0:
112+
return response_base.success()
113+
return response_base.fail()
114+
115+
116+
@router.put('/me/nickname', summary='更新当前用户昵称', dependencies=[DependsJwtAuth])
117+
async def update_user_nickname(
118+
request: Request, nickname: Annotated[str, Body(embed=True, description='用户昵称')]
119+
) -> ResponseModel:
120+
count = await user_service.update_nickname(request=request, nickname=nickname)
121+
if count > 0:
122+
return response_base.success()
123+
return response_base.fail()
124+
125+
126+
@router.put('/me/avatar', summary='更新当前用户头像', dependencies=[DependsJwtAuth])
127+
async def update_user_avatar(
128+
request: Request, avatar: Annotated[str, Body(embed=True, description='用户头像地址')]
99129
) -> ResponseModel:
100-
count = await user_service.reset_pwd(pk=pk, obj=obj)
130+
count = await user_service.update_avatar(request=request, avatar=avatar)
101131
if count > 0:
102132
return response_base.success()
103133
return response_base.fail()

backend/app/admin/crud/crud_user.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@ async def update(self, db: AsyncSession, input_user: User, obj: UpdateUserParam)
117117
input_user.roles = roles.scalars().all()
118118
return count
119119

120+
async def update_nickname(self, db: AsyncSession, user_id: int, nickname: str) -> int:
121+
"""
122+
更新用户昵称
123+
124+
:param db: 数据库会话
125+
:param user_id: 用户 ID
126+
:param nickname: 用户昵称
127+
:return:
128+
"""
129+
return await self.update_model(db, user_id, {'nickname': nickname})
130+
120131
async def update_avatar(self, db: AsyncSession, user_id: int, avatar: str) -> int:
121132
"""
122133
更新用户头像
@@ -148,17 +159,17 @@ async def check_email(self, db: AsyncSession, email: str) -> User | None:
148159
"""
149160
return await self.select_model_by_column(db, email=email)
150161

151-
async def reset_password(self, db: AsyncSession, pk: int, new_pwd: str) -> int:
162+
async def reset_password(self, db: AsyncSession, pk: int, password: str) -> int:
152163
"""
153164
重置用户密码
154165
155166
:param db: 数据库会话
156167
:param pk: 用户 ID
157-
:param new_pwd: 新密码
168+
:param password: 新密码
158169
:return:
159170
"""
160171
salt = bcrypt.gensalt()
161-
new_pwd = get_hash_password(new_pwd, salt)
172+
new_pwd = get_hash_password(password, salt)
162173
return await self.update_model(db, pk, {'password': new_pwd, 'salt': salt})
163174

164175
async def get_list(self, dept: int | None, username: str | None, phone: str | None, status: int | None) -> Select:

backend/app/admin/service/user_service.py

Lines changed: 83 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,10 @@ async def update(*, request: Request, pk: int, obj: UpdateUserParam) -> int:
103103
:return:
104104
"""
105105
async with async_db_session.begin() as db:
106+
superuser_verify(request)
106107
user = await user_dao.get_with_relation(db, user_id=pk)
107108
if not user:
108109
raise errors.NotFoundError(msg='用户不存在')
109-
if request.user.username != user.username:
110-
raise errors.ForbiddenError(msg='只能修改自己的信息')
111110
if obj.username != user.username:
112111
if await user_dao.get_by_username(db, obj.username):
113112
raise errors.ConflictError(msg='用户名已注册')
@@ -119,130 +118,142 @@ async def update(*, request: Request, pk: int, obj: UpdateUserParam) -> int:
119118
return count
120119

121120
@staticmethod
122-
async def update_superuser(*, request: Request, pk: int) -> int:
121+
async def update_permission(*, request: Request, pk: int, type: UserPermissionType) -> int:
123122
"""
124-
更新用户管理员状态
123+
更新用户权限
125124
126125
:param request: FastAPI 请求对象
127126
:param pk: 用户 ID
127+
:param type: 权限类型
128128
:return:
129129
"""
130130
async with async_db_session.begin() as db:
131131
superuser_verify(request)
132-
user = await user_dao.get(db, pk)
133-
if not user:
134-
raise errors.NotFoundError(msg='用户不存在')
135-
if pk == request.user.id:
136-
raise errors.ForbiddenError(msg='禁止修改自身权限')
137-
count = await user_dao.set_super(db, pk, not user.status)
138-
await redis_client.delete(f'{settings.JWT_USER_REDIS_PREFIX}:{user.id}')
139-
return count
132+
match type:
133+
case UserPermissionType.superuser:
134+
user = await user_dao.get(db, pk)
135+
if not user:
136+
raise errors.NotFoundError(msg='用户不存在')
137+
if pk == request.user.id:
138+
raise errors.ForbiddenError(msg='禁止修改自身权限')
139+
count = await user_dao.set_super(db, pk, not user.status)
140+
case UserPermissionType.staff:
141+
user = await user_dao.get(db, pk)
142+
if not user:
143+
raise errors.NotFoundError(msg='用户不存在')
144+
if pk == request.user.id:
145+
raise errors.ForbiddenError(msg='禁止修改自身权限')
146+
count = await user_dao.set_staff(db, pk, not user.is_staff)
147+
case UserPermissionType.status:
148+
user = await user_dao.get(db, pk)
149+
if not user:
150+
raise errors.NotFoundError(msg='用户不存在')
151+
if pk == request.user.id:
152+
raise errors.ForbiddenError(msg='禁止修改自身权限')
153+
count = await user_dao.set_status(db, pk, 0 if user.status == 1 else 1)
154+
case UserPermissionType.multi_login:
155+
user = await user_dao.get(db, pk)
156+
if not user:
157+
raise errors.NotFoundError(msg='用户不存在')
158+
multi_login = user.is_multi_login if pk != user.id else request.user.is_multi_login
159+
new_multi_login = not multi_login
160+
count = await user_dao.set_multi_login(db, pk, new_multi_login)
161+
token = get_token(request)
162+
token_payload = jwt_decode(token)
163+
if pk == user.id:
164+
# 系统管理员修改自身时,除当前 token 外,其他 token 失效
165+
if not new_multi_login:
166+
key_prefix = f'{settings.TOKEN_REDIS_PREFIX}:{user.id}'
167+
await redis_client.delete_prefix(
168+
key_prefix, exclude=f'{key_prefix}:{token_payload.session_uuid}'
169+
)
170+
else:
171+
# 系统管理员修改他人时,他人 token 全部失效
172+
if not new_multi_login:
173+
key_prefix = f'{settings.TOKEN_REDIS_PREFIX}:{user.id}'
174+
await redis_client.delete_prefix(key_prefix)
175+
case _:
176+
raise errors.RequestError(msg='权限类型不存在')
177+
178+
await redis_client.delete(f'{settings.JWT_USER_REDIS_PREFIX}:{user.id}')
179+
return count
140180

141181
@staticmethod
142-
async def update_staff(*, request: Request, pk: int) -> int:
182+
async def reset_password(*, request: Request, pk: int, password: str) -> int:
143183
"""
144-
更新用户职员状态
184+
重置用户密码
145185
146186
:param request: FastAPI 请求对象
147187
:param pk: 用户 ID
188+
:param password: 新密码
148189
:return:
149190
"""
150191
async with async_db_session.begin() as db:
151192
superuser_verify(request)
152193
user = await user_dao.get(db, pk)
153194
if not user:
154195
raise errors.NotFoundError(msg='用户不存在')
155-
if pk == request.user.id:
156-
raise errors.ForbiddenError(msg='禁止修改自身权限')
157-
count = await user_dao.set_staff(db, pk, not user.is_staff)
158-
await redis_client.delete(f'{settings.JWT_USER_REDIS_PREFIX}:{user.id}')
196+
count = await user_dao.reset_password(db, user.id, password)
197+
key_prefix = [
198+
f'{settings.TOKEN_REDIS_PREFIX}:{user.id}',
199+
f'{settings.TOKEN_REFRESH_REDIS_PREFIX}:{user.id}',
200+
f'{settings.JWT_USER_REDIS_PREFIX}:{user.id}',
201+
]
202+
for prefix in key_prefix:
203+
await redis_client.delete(prefix)
159204
return count
160205

161206
@staticmethod
162-
async def update_status(*, request: Request, pk: int) -> int:
207+
async def update_nickname(*, request: Request, nickname: str) -> int:
163208
"""
164-
更新用户状态
209+
更新用户昵称
165210
166211
:param request: FastAPI 请求对象
167-
:param pk: 用户 ID
212+
:param nickname: 用户昵称
168213
:return:
169214
"""
170215
async with async_db_session.begin() as db:
171-
superuser_verify(request)
172-
user = await user_dao.get(db, pk)
216+
token = get_token(request)
217+
token_payload = jwt_decode(token)
218+
user = await user_dao.get(db, token_payload.id)
173219
if not user:
174220
raise errors.NotFoundError(msg='用户不存在')
175-
if pk == request.user.id:
176-
raise errors.ForbiddenError(msg='禁止修改自身权限')
177-
count = await user_dao.set_status(db, pk, 0 if user.status == 1 else 1)
221+
count = await user_dao.update_nickname(db, token_payload.id, nickname)
178222
await redis_client.delete(f'{settings.JWT_USER_REDIS_PREFIX}:{user.id}')
179223
return count
180224

181225
@staticmethod
182-
async def update_multi_login(*, request: Request, pk: int) -> int:
226+
async def update_avatar(*, request: Request, avatar: str) -> int:
183227
"""
184-
更新用户多端登录状态
228+
更新用户头像
185229
186230
:param request: FastAPI 请求对象
187-
:param pk: 用户 ID
231+
:param avatar: 头像地址
188232
:return:
189233
"""
190234
async with async_db_session.begin() as db:
191-
superuser_verify(request)
192-
user = await user_dao.get(db, pk)
235+
token = get_token(request)
236+
token_payload = jwt_decode(token)
237+
user = await user_dao.get(db, token_payload.id)
193238
if not user:
194239
raise errors.NotFoundError(msg='用户不存在')
195-
multi_login = user.is_multi_login if pk != user.id else request.user.is_multi_login
196-
new_multi_login = not multi_login
197-
count = await user_dao.set_multi_login(db, pk, new_multi_login)
240+
count = await user_dao.update_avatar(db, token_payload.id, avatar)
198241
await redis_client.delete(f'{settings.JWT_USER_REDIS_PREFIX}:{user.id}')
199-
token = get_token(request)
200-
token_payload = jwt_decode(token)
201-
if pk == user.id:
202-
# 系统管理员修改自身时,除当前 token 外,其他 token 失效
203-
if not new_multi_login:
204-
key_prefix = f'{settings.TOKEN_REDIS_PREFIX}:{user.id}'
205-
await redis_client.delete_prefix(key_prefix, exclude=f'{key_prefix}:{token_payload.session_uuid}')
206-
else:
207-
# 系统管理员修改他人时,他人 token 全部失效
208-
if not new_multi_login:
209-
key_prefix = f'{settings.TOKEN_REDIS_PREFIX}:{user.id}'
210-
await redis_client.delete_prefix(key_prefix)
211242
return count
212243

213-
async def update_permission(self, *, request: Request, pk: int, type: UserPermissionType) -> int:
214-
"""
215-
更新用户权限
216-
217-
:param request: FastAPI 请求对象
218-
:param pk: 用户 ID
219-
:param type: 权限类型
220-
:return:
221-
"""
222-
match type:
223-
case UserPermissionType.superuser:
224-
count = await self.update_superuser(request=request, pk=pk)
225-
case UserPermissionType.staff:
226-
count = await self.update_staff(request=request, pk=pk)
227-
case UserPermissionType.status:
228-
count = await self.update_status(request=request, pk=pk)
229-
case UserPermissionType.multi_login:
230-
count = await self.update_multi_login(request=request, pk=pk)
231-
case _:
232-
raise errors.RequestError(msg='权限类型不存在')
233-
return count
234-
235244
@staticmethod
236-
async def reset_pwd(*, pk: int, obj: ResetPasswordParam) -> int:
245+
async def update_password(*, request: Request, obj: ResetPasswordParam) -> int:
237246
"""
238-
重置用户密码
247+
更新用户密码
239248
240-
:param pk: 用户 ID
249+
:param request: FastAPI 请求对象
241250
:param obj: 密码重置参数
242251
:return:
243252
"""
244253
async with async_db_session.begin() as db:
245-
user = await user_dao.get(db, pk)
254+
token = get_token(request)
255+
token_payload = jwt_decode(token)
256+
user = await user_dao.get(db, token_payload.id)
246257
if not user:
247258
raise errors.NotFoundError(msg='用户不存在')
248259
if not password_verify(obj.old_password, user.password):

0 commit comments

Comments
 (0)