From ebe180f2f0177dda5e0f7a481aeb4645027929a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9A=93=E6=9C=88=E5=BD=92=E5=B0=98?= Date: Sat, 22 Feb 2025 21:48:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=99=BB=E5=BD=95=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8C=89=E9=92=AE=E7=BA=A7=E6=9D=83=E9=99=90?= =?UTF-8?q?=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/log.py | 100 +++++++++++++++++++++++++++++++------------- controller/login.py | 7 +++- 2 files changed, 76 insertions(+), 31 deletions(-) diff --git a/api/log.py b/api/log.py index 1df6454..79a3572 100644 --- a/api/log.py +++ b/api/log.py @@ -5,7 +5,8 @@ # @File : log.py # @Software : PyCharm # @Comment : 本程序 - +from typing import Optional +from datetime import datetime from fastapi import APIRouter, Depends, Path, Query, Request from fastapi.encoders import jsonable_encoder from fastapi.responses import JSONResponse @@ -21,21 +22,44 @@ from utils.response import Response logAPI = APIRouter( prefix="/log", - dependencies=[Depends(LoginController.get_current_user)] ) @logAPI.get("/login", response_class=JSONResponse, response_model=GetLoginLogResponse, summary="用户获取登录日志") +@Log(title="用户获取登录日志", business_type=BusinessType.SELECT) +@Auth(permission_list=["login:btn:list"]) async def get_login_log(request: Request, page: int = Query(default=1, description="页码"), pageSize: int = Query(default=10, description="每页数量"), + username: Optional[str] = Query(default=None, description="用户账号"), + nickname: Optional[str] = Query(default=None, description="用户昵称"), + department_id: Optional[str] = Query(default=None, description="部门ID"), + startTime: Optional[str] = Query(default=None, description="开始时间"), + endTime: Optional[str] = Query(default=None, description="结束时间"), + status: Optional[str] = Query(default=None, description="登录状态"), current_user: dict = Depends(LoginController.get_current_user), ): - online_user_list = await LoginController.get_online_user(request) + sub_departments = current_user.get("sub_departments") + online_user_list = await LoginController.get_online_user(request, sub_departments) online_user_list = list( - filter(lambda x: x["user_id"] == current_user.get("id"), jsonable_encoder(online_user_list))) - user_id = current_user.get("id") - result = await LoginLog.filter(user_id=user_id, del_flag=1).offset((page - 1) * pageSize).limit(pageSize).values( + filter(lambda x: x["department_id"] in sub_departments, jsonable_encoder(online_user_list))) + filterArgs = { + f'{k}__contains': v for k, v in { + 'username': username, + 'nickname': nickname, + 'department_id': department_id, + }.items() if v + } + if status is not None: + filterArgs['status'] = status + if startTime and endTime: + startTime = datetime.fromtimestamp(float(startTime) / 1000) + endTime = datetime.fromtimestamp(float(endTime) / 1000) + filterArgs['login_time__range'] = [startTime, endTime] + if not department_id: + filterArgs['user__department__id__in'] = sub_departments + result = await LoginLog.filter(**filterArgs, del_flag=1).offset( + (page - 1) * pageSize).limit(pageSize).values( id="id", user_id="user__id", username="user__username", @@ -58,55 +82,73 @@ async def get_login_log(request: Request, if item["session_id"] == log["session_id"]: log["online"] = True return Response.success(data={ - "total": await LoginLog.filter(user_id=user_id).count(), + "total": await LoginLog.filter(**filterArgs, del_flag=1, ).count(), "result": result, "page": page, }) -@logAPI.delete("/logout/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="用户强退") -@logAPI.post("/logout/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="用户强退") -@Log(title="用户强退", business_type=BusinessType.DELETE) -# @Auth(permission_list=["user:btn:logout"]) +@logAPI.delete("/logout/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="用户强制退出") +@logAPI.post("/logout/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="用户强制退出") +@Log(title="用户强制退出", business_type=BusinessType.DELETE) +@Auth(permission_list=["login:btn:logout"]) async def logout_user(request: Request, id: str = Path(description="会话ID"), current_user: dict = Depends(LoginController.get_current_user)): - if await LoginLog.get_or_none(user_id=current_user.get("id"), session_id=id): - await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}") - return Response.success(msg="强退成功!") + sub_departments = current_user.get("sub_departments") + if await LoginLog.get_or_none(user__department__id__in=sub_departments, session_id=id, del_flag=1): + if await request.app.state.redis.get(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}"): + await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}") + return Response.success(msg="强退成功!") return Response.failure(msg="会话不存在!") +@logAPI.delete("/logoutList", response_class=JSONResponse, response_model=BaseResponse, summary="用户批量强制退出") +@logAPI.post("/logoutList", response_class=JSONResponse, response_model=BaseResponse, summary="用户批量强制退出") +@Log(title="用户批量强制退出", business_type=BusinessType.DELETE) +@Auth(permission_list=["login:btn:logout"]) +async def logout_user_list(request: Request, params: DeleteListParams, + current_user: dict = Depends(LoginController.get_current_user)): + sub_departments = current_user.get("sub_departments") + for id in params.ids: + if await LoginLog.get_or_none(user__department__id__in=sub_departments, session_id=id, del_flag=1): + if await request.app.state.redis.get(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}"): + await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}") + return Response.success(msg="批量强退成功!") + + @logAPI.delete("/delete/login/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="用户删除登录日志") @logAPI.post("/delete/login/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="用户删除登录日志") @Log(title="用户删除登录日志", business_type=BusinessType.DELETE) @Auth(permission_list=["login:btn:delete"]) -async def delete_login_log(id: str = Path(..., description="登录日志ID"), +async def delete_login_log(request: Request, id: str = Path(..., description="登录日志ID"), current_user: dict = Depends(LoginController.get_current_user)): - if log := await LoginLog.get_or_none(id=id): - if log.user == current_user.get("id"): - log.del_flag = 0 - await log.save() - return Response.success(msg="删除成功") - else: - return Response.failure(msg="无权限删除") + sub_departments = current_user.get("sub_departments") + if log := await LoginLog.get_or_none(id=id, del_flag=1, user__department__id__in=sub_departments): + log.del_flag = 0 + await log.save() + if await request.app.state.redis.get(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{log.session_id}"): + await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{log.session_id}") + return Response.success(msg="删除成功") else: return Response.failure(msg="删除失败,登录日志不存在!") @logAPI.delete("/deleteList/login", response_model=BaseResponse, response_class=JSONResponse, - summary="用户删除登录日志") + summary="用户批量删除登录日志") @logAPI.post("/deleteList/login", response_model=BaseResponse, response_class=JSONResponse, - summary="用户删除登录日志") + summary="用户批量删除登录日志") @Log(title="用户批量删除登录日志", business_type=BusinessType.DELETE) @Auth(permission_list=["login:btn:delete"]) -async def delete_login_log(params: DeleteListParams, +async def delete_login_log(request: Request, params: DeleteListParams, current_user: dict = Depends(LoginController.get_current_user)): + sub_departments = current_user.get("sub_departments") for id in set(params.ids): - if log := await LoginLog.get_or_none(id=id): - if log.user == current_user.get("id"): - log.del_flag = 0 - await log.save() + if log := await LoginLog.get_or_none(id=id, del_flag=1, user__department__id__in=sub_departments): + log.del_flag = 0 + await log.save() + if await request.app.state.redis.get(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{log.session_id}"): + await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{log.session_id}") return Response.success(msg="删除成功") diff --git a/controller/login.py b/controller/login.py index 7810f07..b80a920 100644 --- a/controller/login.py +++ b/controller/login.py @@ -239,7 +239,7 @@ class LoginController: return complete_data @classmethod - async def get_online_user(cls, request: Request) -> list: + async def get_online_user(cls, request: Request, sub_departments: list) -> list: """ 获取在线用户 """ @@ -251,7 +251,8 @@ class LoginController: for item in access_token_values_list: payload = jwt.decode(item, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm]) session_id = payload.get("session_id") - result = await LoginLog.get_or_none(session_id=session_id).values( + result = await LoginLog.get_or_none(session_id=session_id, user__department__id__in=sub_departments, + del_flag=1).values( id="id", user_id="user__id", username="user__username", @@ -268,5 +269,7 @@ class LoginController: create_time="create_time", update_time="update_time" ) + if not result: + continue online_info_list.append(result) return online_info_list