chore(lint): make ruff happy

This commit is contained in:
MingxuanGame
2025-08-17 16:57:27 +00:00
parent 3c460f1d82
commit 86bea5d4b5
13 changed files with 316 additions and 181 deletions

View File

@@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
"""
[GeoIP] Scheduled Update Service
Periodically update the MaxMind GeoIP database
"""
from __future__ import annotations
import asyncio
from datetime import datetime
from app.config import settings
from app.dependencies.geoip import get_geoip_helper
from app.dependencies.scheduler import get_scheduler
@@ -18,11 +20,11 @@ async def update_geoip_database():
try:
logger.info("[GeoIP] Starting scheduled GeoIP database update...")
geoip = get_geoip_helper()
# Run the synchronous update method in a background thread
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, lambda: geoip.update(force=False))
logger.info("[GeoIP] Scheduled GeoIP database update completed successfully")
except Exception as e:
logger.error(f"[GeoIP] Scheduled GeoIP database update failed: {e}")
@@ -33,20 +35,21 @@ def schedule_geoip_updates():
Schedule the GeoIP database update task
"""
scheduler = get_scheduler()
# Use settings to configure the update time: update once a week
scheduler.add_job(
update_geoip_database,
'cron',
"cron",
day_of_week=settings.geoip_update_day,
hour=settings.geoip_update_hour,
minute=0,
id='geoip_weekly_update',
name='Weekly GeoIP database update',
replace_existing=True
id="geoip_weekly_update",
name="Weekly GeoIP database update",
replace_existing=True,
)
logger.info(
f"[GeoIP] Scheduled update task registered: "
f"every week on day {settings.geoip_update_day} at {settings.geoip_update_hour}:00"
f"every week on day {settings.geoip_update_day} "
f"at {settings.geoip_update_hour}:00"
)

View File

@@ -1,12 +1,16 @@
# -*- coding: utf-8 -*-
"""
[GeoIP] Initialization Service
Initialize the GeoIP database when the application starts
"""
from __future__ import annotations
import asyncio
from app.dependencies.geoip import get_geoip_helper
from app.log import logger
async def init_geoip():
"""
Asynchronously initialize the GeoIP database
@@ -14,11 +18,11 @@ async def init_geoip():
try:
geoip = get_geoip_helper()
logger.info("[GeoIP] Initializing GeoIP database...")
# Run the synchronous update method in a background thread
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, geoip.update)
logger.info("[GeoIP] GeoIP database initialization completed")
except Exception as e:
logger.error(f"[GeoIP] GeoIP database initialization failed: {e}")

View File

@@ -1,21 +1,23 @@
# -*- coding: utf-8 -*-
"""
用户登录记录服务
"""
from __future__ import annotations
import asyncio
from datetime import datetime
from typing import Optional
from fastapi import Request
from sqlmodel.ext.asyncio.session import AsyncSession
from app.database.user_login_log import UserLoginLog
from app.dependencies.geoip import get_geoip_helper, get_client_ip, normalize_ip
from app.dependencies.geoip import get_client_ip, get_geoip_helper, normalize_ip
from app.log import logger
from fastapi import Request
from sqlmodel.ext.asyncio.session import AsyncSession
class LoginLogService:
"""用户登录记录服务"""
@staticmethod
async def record_login(
db: AsyncSession,
@@ -23,11 +25,11 @@ class LoginLogService:
request: Request,
login_success: bool = True,
login_method: str = "password",
notes: Optional[str] = None
notes: str | None = None,
) -> UserLoginLog:
"""
记录用户登录信息
Args:
db: 数据库会话
user_id: 用户ID
@@ -35,17 +37,17 @@ class LoginLogService:
login_success: 登录是否成功
login_method: 登录方式
notes: 备注信息
Returns:
UserLoginLog: 登录记录对象
"""
# 获取客户端IP并标准化格式
raw_ip = get_client_ip(request)
ip_address = normalize_ip(raw_ip)
# 获取User-Agent
user_agent = request.headers.get("User-Agent", "")
# 创建基本的登录记录
login_log = UserLoginLog(
user_id=user_id,
@@ -54,20 +56,19 @@ class LoginLogService:
login_time=datetime.utcnow(),
login_success=login_success,
login_method=login_method,
notes=notes
notes=notes,
)
# 异步获取GeoIP信息
try:
geoip = get_geoip_helper()
# 在后台线程中运行GeoIP查询避免阻塞
loop = asyncio.get_event_loop()
geo_info = await loop.run_in_executor(
None,
lambda: geoip.lookup(ip_address)
None, lambda: geoip.lookup(ip_address)
)
if geo_info:
login_log.country_code = geo_info.get("country_iso", "")
login_log.country_name = geo_info.get("country_name", "")
@@ -75,7 +76,7 @@ class LoginLogService:
login_log.latitude = geo_info.get("latitude", "")
login_log.longitude = geo_info.get("longitude", "")
login_log.time_zone = geo_info.get("time_zone", "")
# 处理 ASN可能是字符串需要转换为整数
asn_value = geo_info.get("asn")
if asn_value is not None:
@@ -83,42 +84,47 @@ class LoginLogService:
login_log.asn = int(asn_value)
except (ValueError, TypeError):
login_log.asn = None
login_log.organization = geo_info.get("organization", "")
logger.debug(f"GeoIP lookup for {ip_address}: {geo_info.get('country_name', 'Unknown')}")
logger.debug(
f"GeoIP lookup for {ip_address}: "
f"{geo_info.get('country_name', 'Unknown')}"
)
else:
logger.warning(f"GeoIP lookup failed for {ip_address}")
except Exception as e:
logger.warning(f"GeoIP lookup error for {ip_address}: {e}")
# 保存到数据库
db.add(login_log)
await db.commit()
await db.refresh(login_log)
logger.info(f"Login recorded for user {user_id} from {ip_address} ({login_method})")
logger.info(
f"Login recorded for user {user_id} from {ip_address} ({login_method})"
)
return login_log
@staticmethod
async def record_failed_login(
db: AsyncSession,
request: Request,
attempted_username: Optional[str] = None,
attempted_username: str | None = None,
login_method: str = "password",
notes: Optional[str] = None
notes: str | None = None,
) -> UserLoginLog:
"""
记录失败的登录尝试
Args:
db: 数据库会话
request: HTTP请求对象
attempted_username: 尝试登录的用户名
login_method: 登录方式
notes: 备注信息
Returns:
UserLoginLog: 登录记录对象
"""
@@ -129,17 +135,19 @@ class LoginLogService:
request=request,
login_success=False,
login_method=login_method,
notes=f"Failed login attempt: {attempted_username}" if attempted_username else "Failed login attempt"
notes=f"Failed login attempt: {attempted_username}"
if attempted_username
else "Failed login attempt",
)
def get_request_info(request: Request) -> dict:
"""
提取请求的详细信息
Args:
request: HTTP请求对象
Returns:
dict: 包含请求信息的字典
"""