From f6af4eace8f6fd5644218269e83455299f78fc00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9A=93=E6=9C=88=E5=BD=92=E5=B0=98?= Date: Wed, 26 Feb 2025 17:07:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=B3=A8=E9=94=80=EF=BC=8C=E7=94=A8=E6=88=B7=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=89=8B=E6=9C=BA=E5=8F=B7=EF=BC=8C=E6=9B=B4=E6=96=B0=E9=82=AE?= =?UTF-8?q?=E7=AE=B1=EF=BC=8C=E6=9B=B4=E6=96=B0=E5=AF=86=E7=A0=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- annotation/log.py | 2 +- api/login.py | 35 +++++++++++++++++++- api/user.py | 84 +++++++++++++++++++++++++++++++++++++++++++++-- schemas/user.py | 22 +++++++++++++ 4 files changed, 138 insertions(+), 5 deletions(-) diff --git a/annotation/log.py b/annotation/log.py index d13c65b..f974034 100644 --- a/annotation/log.py +++ b/annotation/log.py @@ -149,7 +149,7 @@ class Log: # else: session_id = request.app.state.session_id status = 1 if request.app.state.login_status else 0 - current_user = await User.get_or_none(username=payload.get("username"),del_flag=1) + current_user = await User.get_or_none(username=payload.get("username"), del_flag=1) await LoginLog.create( user_id=current_user.id, login_ip=host, diff --git a/api/login.py b/api/login.py index af91477..5783cf6 100644 --- a/api/login.py +++ b/api/login.py @@ -18,7 +18,7 @@ from config.constant import BusinessType from config.constant import RedisKeyConfig from controller.login import CustomOAuth2PasswordRequestForm, LoginController from controller.query import QueryController -from models import Department, User, Role, UserRole +from models import Department, User, Role, UserRole, LoginLog, OperationLog, QueryCodeLog, QueryCode from schemas.common import BaseResponse from schemas.login import LoginParams, GetUserInfoResponse, LoginResponse, GetCaptchaResponse, GetEmailCodeParams, \ ResetPasswordParams @@ -271,3 +271,36 @@ async def logout(request: Request, status: bool = Depends(LoginController.logout if status: return Response.success(data="退出成功!") return Response.error(data="登出失败!") + + +@loginAPI.post("/unsubscribe", response_class=JSONResponse, response_model=BaseResponse, summary="用户注销") +@Log(title="用户注销", business_type=BusinessType.FORCE) +async def unsubscribe(request: Request, current_user: dict = Depends(LoginController.get_current_user)): + id = current_user.get("id") + session_id = current_user.get("session_id") + if user := await User.get_or_none(id=id, del_flag=1): + user.del_flag = 0 + await user.save() + redis_token = await request.app.state.redis.get(f'{RedisKeyConfig.ACCESS_TOKEN.key}:{session_id}') + if redis_token: + await request.app.state.redis.delete(f'{RedisKeyConfig.ACCESS_TOKEN.key}:{session_id}') + # 移除用户角色 + await UserRole.filter(user_id=user.id, del_flag=1).update(del_flag=0) + # 移除用户登录日志 + await LoginLog.filter(user_id=user.id, del_flag=1).update(del_flag=0) + # 移除用户操作日志 + await OperationLog.filter(user_id=user.id, del_flag=1).update(del_flag=0) + # 移除编码查询日志 + logs = await QueryCodeLog.filter(operator__id=user.id, del_flag=1).values("id") + for log in logs: + await QueryCode.filter(session_id=log["id"], del_flag=1).update(del_flag=0) + await QueryCodeLog.filter(id=log["id"], del_flag=1).update(del_flag=0) + # 更新用户信息缓存 + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{id}') + # 更新用户路由缓存 + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_ROUTES.key}:{id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_ROUTES.key}:{id}') + return Response.success(data="注销成功!") + else: + return Response.error(data="注销失败!") diff --git a/api/user.py b/api/user.py index cd15295..16e97dd 100644 --- a/api/user.py +++ b/api/user.py @@ -10,7 +10,7 @@ import os from datetime import datetime, timedelta from typing import Optional -from fastapi import APIRouter, Depends, Path, Query, UploadFile, File, Request +from fastapi import APIRouter, Depends, Path, Query, UploadFile, File, Request, Form from fastapi.responses import JSONResponse from annotation.auth import Auth @@ -29,7 +29,7 @@ from schemas.department import GetDepartmentListResponse from schemas.file import UploadFileResponse from schemas.user import AddUserParams, GetUserListResponse, GetUserInfoResponse, UpdateUserParams, \ AddUserRoleParams, GetUserRoleInfoResponse, UpdateUserRoleParams, GetUserPermissionListResponse, \ - ResetPasswordParams, GetUserStatisticsResponse + ResetPasswordParams, GetUserStatisticsResponse, UpdateBaseUserInfoParams from utils.common import filterKeyValues from utils.password import Password from utils.response import Response @@ -438,6 +438,84 @@ async def reset_user_password(request: Request, params: ResetPasswordParams, id: return Response.failure(msg="用户不存在!") +@userAPI.put("/updateBaseUserInfo", response_model=BaseResponse, response_class=JSONResponse, + summary="更新基础个人信息") +@userAPI.post("/updateBaseUserInfo", response_model=BaseResponse, response_class=JSONResponse, + summary="更新基础个人信息") +@Log(title="更新基础个人信息", business_type=BusinessType.UPDATE) +async def update_base_userinfo(params: UpdateBaseUserInfoParams, request: Request, + current_user: dict = Depends(LoginController.get_current_user)): + user = await User.get_or_none(id=current_user.get("id"), del_flag=1) + if user: + user.nickname = params.name + user.gender = params.gender + await user.save() + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{user.id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{user.id}') + return Response.success(msg="更新成功!") + return Response.error(msg="更新失败!") + + +@userAPI.put("/updatePassword", response_class=JSONResponse, response_model=BaseResponse, summary="用户更新密码") +@userAPI.post("/updatePassword", response_class=JSONResponse, response_model=BaseResponse, summary="用户更新密码") +@Log(title="用户更新密码", business_type=BusinessType.UPDATE) +async def update_user_password(request: Request, oldPassword: str = Form(description="用户旧密码"), + newPassword: str = Form(description="用户新密码"), + current_user: dict = Depends(LoginController.get_current_user)): + if user := await User.get_or_none(id=current_user.get("id"), del_flag=1): + password = await Password.get_password_hash(oldPassword) + if user.password != password: + return Response.error(msg="旧密码错误!") + newPassword = await Password.get_password_hash(newPassword) + user.password = newPassword + await user.save() + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{user.id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{user.id}') + return Response.success(msg="更新成功!") + return Response.error(msg="更新失败!") + + +@userAPI.put("/updatePhone", response_class=JSONResponse, response_model=BaseResponse, summary="用户更新手机号") +@userAPI.post("/updatePhone", response_class=JSONResponse, response_model=BaseResponse, summary="用户更新手机号") +@Log(title="用户更新手机号", business_type=BusinessType.UPDATE) +async def update_user_phone(request: Request, password: str = Form(description="用户密码"), + phone: str = Form(description="用户手机号"), + current_user: dict = Depends(LoginController.get_current_user)): + if user := await User.get_or_none(id=current_user.get("id"), del_flag=1): + password = await Password.get_password_hash(password) + if user.password != password: + return Response.error("更改失败,请正确输入旧密码") + phoneStatus = await User.filter(phone=phone,del_flag=1).count() + if phoneStatus: + return Response.error( f"更改失败,手机号:{phone}已绑定其他账号!") + user.phone=phone + await user.save() + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{user.id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{user.id}') + return Response.success(msg="更新成功!") + return Response.error(msg="更新失败!") + + +@userAPI.put("/updateEmail", response_class=JSONResponse, response_model=BaseResponse, summary="用户更新邮箱") +@userAPI.post("/updateEmail", response_class=JSONResponse, response_model=BaseResponse, summary="用户更新邮箱") +@Log(title="用户更新邮箱", business_type=BusinessType.UPDATE) +async def update_user_email(request: Request, password: str = Form(description="用户密码"), + email: str = Form(description="用户邮箱"),current_user: dict = Depends(LoginController.get_current_user)): + if user:=await User.get_or_none(id=current_user.get("id"),del_flag=1): + password = await Password.get_password_hash(password) + if user.password != password: + return Response.error("更改失败,请正确输入旧密码") + emailStatus = await User.filter(email=email,del_flag=1).count() + if emailStatus: + return Response.error(f"更改失败,邮箱:{email}已绑定其他账号!") + user.email=email + await user.save() + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{user.id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{user.id}') + return Response.success(msg="更新成功!") + return Response.error(msg="更新失败!") + + @userAPI.get("/statistics", response_model=GetUserStatisticsResponse, response_class=JSONResponse, summary="获取用户查询统计") @Log(title="获取用户查询统计", business_type=BusinessType.SELECT) @@ -531,4 +609,4 @@ async def get_user_statistics(request: Request, current_user: dict = Depends(Log "last_month_count": last_month_count, "before_14day_count_success": before_14day_count_success, "before_14day_count_fail": before_14day_count_fail, - }) \ No newline at end of file + }) diff --git a/schemas/user.py b/schemas/user.py index 564c32a..e0d66f3 100644 --- a/schemas/user.py +++ b/schemas/user.py @@ -6,6 +6,7 @@ # @Software : PyCharm # @Comment : 本程序 from datetime import datetime +from enum import IntEnum from typing import Optional, List from uuid import UUID @@ -15,6 +16,11 @@ from pydantic_validation_decorator import Xss, NotBlank, Size, Network from schemas.common import BaseResponse, ListQueryResult +class Gender(IntEnum): + MAN = 0 + WOMAN = 1 + + class UserBase(BaseModel): """ 用户表基础模型。 @@ -387,3 +393,19 @@ class GetUserStatisticsResponse(BaseResponse): 获取用户统计信息响应模型。 """ data: GetUserStatisticsResult = Field(default=None, description="响应数据") + + +class UpdateBaseUserInfoParams(BaseModel): + """修改基础信息参数""" + name: str + """姓名""" + gender: Gender + """性别""" + + class Config: + json_schema_extra = { + "example": { + "name": "张三", + "gender": 1, + } + }