255 lines
13 KiB
Python

# _*_ coding : UTF-8 _*_
# @Time : 2025/01/27 21:40
# @UpdateTime : 2025/01/27 21:40
# @Author : sonder
# @File : log.py
# @Software : PyCharm
# @Comment : 本程序
from datetime import datetime
from typing import Optional
from fastapi import APIRouter, Depends, Path, Query, Request
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from annotation.auth import Auth
from annotation.log import Log
from config.constant import BusinessType, RedisKeyConfig
from controller.login import LoginController
from models import LoginLog, OperationLog
from schemas.common import BaseResponse, DeleteListParams
from schemas.log import GetLoginLogResponse, GetOperationLogResponse
from utils.response import Response
logAPI = APIRouter(
prefix="/log",
)
@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),
):
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["department_id"] in sub_departments, jsonable_encoder(online_user_list)))
filterArgs = {
f'{k}__contains': v for k, v in {
'username': username,
'nickname': nickname,
}.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
else:
filterArgs['user__department__id'] = department_id
result = await LoginLog.filter(**filterArgs, user__del_flag=1, del_flag=1).offset(
(page - 1) * pageSize).limit(pageSize).values(
id="id",
user_id="user__id",
username="user__username",
user_nickname="user__nickname",
department_id="user__department__id",
department_name="user__department__name",
login_ip="login_ip",
login_location="login_location",
browser="browser",
os="os",
status="status",
login_time="login_time",
session_id="session_id",
create_time="create_time",
update_time="update_time"
)
for log in result:
log["online"] = False
for item in online_user_list:
if item["session_id"] == log["session_id"]:
log["online"] = True
return Response.success(data={
"total": await LoginLog.filter(**filterArgs, del_flag=1, user__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=["login:btn:logout"])
async def logout_user(request: Request, id: str = Path(description="会话ID"),
current_user: dict = Depends(LoginController.get_current_user)):
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(request: Request, id: str = Path(..., description="登录日志ID"),
current_user: dict = Depends(LoginController.get_current_user)):
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="用户批量删除登录日志")
@logAPI.post("/deleteList/login", response_model=BaseResponse, response_class=JSONResponse,
summary="用户批量删除登录日志")
@Log(title="用户批量删除登录日志", business_type=BusinessType.DELETE)
@Auth(permission_list=["login:btn:delete"])
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, 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="删除成功")
@logAPI.get("/operation", response_class=JSONResponse, response_model=GetOperationLogResponse,
summary="用户获取操作日志")
@Auth(permission_list=["operation:btn:list"])
async def get_operation_log(request: Request,
page: int = Query(default=1, description="页码"),
name: Optional[str] = Query(default=None, description="操作名称"),
type: Optional[str] = Query(default=None, 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),
):
sub_departments = current_user.get("sub_departments")
filterArgs = {
f'{k}__contains': v for k, v in {
'operation_name': name,
'operation_type': type,
'operator__username': username,
'operator__nickname': nickname,
}.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['operation_time__range'] = [startTime, endTime]
if not department_id:
filterArgs['department__id__in'] = sub_departments
else:
filterArgs['department__id'] = department_id
result = await OperationLog.filter(**filterArgs, operator__del_flag=1, del_flag=1).offset(
(page - 1) * pageSize).limit(
pageSize).values(
id="id",
operation_name="operation_name",
operation_type="operation_type",
request_path="request_path",
request_method="request_method",
request_params="request_params",
response_result="response_result",
host="host",
location="location",
browser="browser",
os="os",
user_agent="user_agent",
operator_id="operator__id",
operator_name="operator__username",
operator_nickname="operator__nickname",
department_id="department__id",
department_name="department__name",
status="status",
operation_time="operation_time",
cost_time="cost_time"
)
return Response.success(data={
"total": await OperationLog.filter(**filterArgs, del_flag=1, operator__del_flag=1).count(),
"result": result,
"page": page,
"pageSize": pageSize
})
@logAPI.delete("/delete/operation/{id}", response_model=BaseResponse, response_class=JSONResponse,
summary="用户删除操作日志")
@logAPI.post("/delete/operation/{id}", response_model=BaseResponse, response_class=JSONResponse,
summary="用户删除操作日志")
@Log(title="用户删除操作日志", business_type=BusinessType.DELETE)
@Auth(permission_list=["operation:btn:delete"])
async def delete_operation_log(request: Request, id: str = Path(..., description="操作日志id"),
current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
if log := await OperationLog.get_or_none(id=id, department__id__in=sub_departments, del_flag=1):
log.del_flag = 0
await log.save()
return Response.success(msg="删除成功")
else:
return Response.failure(msg="删除失败,操作日志不存在!")
@logAPI.delete("/deleteList/operation", response_model=BaseResponse, response_class=JSONResponse,
summary="用户批量删除操作日志")
@logAPI.post("/deleteList/operation", response_model=BaseResponse, response_class=JSONResponse,
summary="用户批量删除操作日志")
@Log(title="用户批量删除操作日志", business_type=BusinessType.DELETE)
@Auth(permission_list=["operation:btn:delete"])
async def delete_operation_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 OperationLog.get_or_none(id=id, department__id__in=sub_departments, del_flag=1):
log.del_flag = 0
await log.save()
return Response.success(msg="删除成功")