Files
dpb/backend/app/api/v1/module_system/log/service.py
T

150 lines
5.4 KiB
Python
Raw Normal View History

from datetime import datetime, timedelta
from typing import Any
from sqlalchemy import delete
from sqlalchemy.ext.asyncio import AsyncSession
from app.config.setting import settings
from app.core.base_schema import AuthSchema, PageResultSchema
from app.core.database import async_db_session
from app.core.exceptions import CustomException
from app.core.logger import logger
from app.utils.common_util import search_to_dict
from app.utils.excel_util import ExcelUtil
from .crud import LoginLogCRUD, OperationLogCRUD
from .model import OperationLogModel
from .schema import (
LoginLogDetailOutSchema,
LoginLogOutSchema,
LoginLogQueryParam,
OperationLogDetailOutSchema,
OperationLogOutSchema,
OperationLogQueryParam,
)
class LoginLogService:
"""登录日志管理服务"""
def __init__(self, auth: AuthSchema, db: AsyncSession) -> None:
self.auth = auth
self.db = db
async def detail(self, id: int) -> LoginLogDetailOutSchema:
obj = await LoginLogCRUD(self.auth, self.db).get_or_404(id=id)
return LoginLogDetailOutSchema.model_validate(obj)
async def page(
self,
page_no: int,
page_size: int,
search: LoginLogQueryParam | None = None,
order_by: list[dict[str, str]] | None = None,
) -> PageResultSchema[LoginLogOutSchema]:
return await LoginLogCRUD(self.auth, self.db).page(
offset=(page_no - 1) * page_size,
limit=page_size,
order_by=order_by or [{"updated_time": "desc"}],
search=search_to_dict(search),
out_schema=LoginLogOutSchema,
)
async def delete(self, ids: list[int]) -> None:
if not ids:
raise CustomException(msg="删除失败,删除对象不能为空")
existing = await LoginLogCRUD(self.auth, self.db).get_list(search={"id": ("in", ids)})
existing_map = {obj.id for obj in existing}
for nid in ids:
if nid not in existing_map:
raise CustomException(msg=f"删除失败,ID为{nid}的数据不存在")
await LoginLogCRUD(self.auth, self.db).delete(ids=ids)
class OperationLogService:
"""操作日志管理服务"""
def __init__(self, auth: AuthSchema, db: AsyncSession) -> None:
self.auth = auth
self.db = db
@staticmethod
async def cleanup_operation_log() -> bool:
from .model import LoginLogModel
retention_days = settings.OPERATION_LOG_RETENTION_DAYS
cutoff = datetime.now() - timedelta(days=retention_days)
async with async_db_session() as session:
op_stmt = delete(OperationLogModel).where(OperationLogModel.created_time < cutoff)
op_result: Any = await session.execute(op_stmt)
login_stmt = delete(LoginLogModel).where(LoginLogModel.created_time < cutoff)
login_result: Any = await session.execute(login_stmt)
await session.commit()
logger.info(f"操作日志清理完成: 操作日志 {op_result.rowcount} 条, 登录日志 {login_result.rowcount} 条")
return True
async def page(
self,
page_no: int,
page_size: int,
search: OperationLogQueryParam | None = None,
order_by: list[dict[str, str]] | None = None,
) -> PageResultSchema[OperationLogOutSchema]:
crud = OperationLogCRUD(self.auth, self.db)
return await crud.page(
offset=(page_no - 1) * page_size,
limit=page_size,
order_by=order_by or [{"id": "desc"}],
search=search_to_dict(search),
out_schema=OperationLogOutSchema,
)
async def detail(self, id: int) -> OperationLogDetailOutSchema:
crud = OperationLogCRUD(self.auth, self.db)
obj = await crud.get_or_404(id=id)
return OperationLogDetailOutSchema.model_validate(obj)
async def delete(self, ids: list[int]) -> None:
if not ids:
raise CustomException(msg="删除失败,删除对象不能为空")
existing = await OperationLogCRUD(self.auth, self.db).get_list(search={"id": ("in", ids)})
existing_map = {obj.id for obj in existing}
for nid in ids:
if nid not in existing_map:
raise CustomException(msg="删除失败,该数据不存在")
crud = OperationLogCRUD(self.auth, self.db)
await crud.delete(ids=ids)
async def get_list(
self,
search: OperationLogQueryParam | None = None,
order_by: list[dict[str, str]] | None = None,
) -> list[OperationLogOutSchema]:
crud = OperationLogCRUD(self.auth, self.db)
obj_list = await crud.get_list(
search=search_to_dict(search),
order_by=order_by or [{"id": "desc"}],
)
return [OperationLogOutSchema.model_validate(obj) for obj in obj_list]
@staticmethod
def export_list(operation_log_list: list[dict[str, Any]]) -> bytes:
"""导出操作日志列表"""
mapping_dict = {
"id": "日志编号",
"request_path": "请求路径",
"request_method": "请求方法",
"request_ip": "请求IP",
"request_payload": "请求参数",
"response_code": "响应状态码",
"process_time": "耗时(ms)",
"created_time": "操作时间",
"created_id": "操作用户ID",
}
return ExcelUtil.export_list2excel(list_data=operation_log_list, mapping_dict=mapping_dict)