This commit is contained in:
root 2025-07-12 20:11:12 +08:00
parent b975cac1c3
commit 6bb7b49091
2 changed files with 499 additions and 6 deletions

View File

@ -1,9 +1,479 @@
# 用户表
from python_core.kv import kv
import hashlib
import uuid
from typing import Dict, List, Any, Optional
from datetime import datetime
from .db import Db
class UserDb(Db):
from python_core.utils.logger import setup_logger
logger = setup_logger(__name__)
class UserTable(Db):
"""
用户表类
基于Db类实现的用户管理功能
"""
def __init__(self):
self.key = "model"
self.users = self.kv.get(self.key)
pass
# 使用固定的数据库键
super().__init__("user_system")
self.table_name = "users"
# 初始化用户表
self._init_user_table()
def _init_user_table(self):
"""初始化用户表"""
try:
# 检查用户表是否存在,不存在则创建
if not self._table_exists(self.table_name):
schema = {
"username": "string",
"email": "string",
"password_hash": "string",
"display_name": "string",
"avatar_url": "string",
"is_active": "boolean",
"last_login": "datetime",
"created_at": "datetime",
"updated_at": "datetime"
}
self.create_table(self.table_name, schema)
logger.info("User table initialized")
else:
logger.info("User table already exists")
except Exception as e:
logger.error(f"Failed to initialize user table: {e}")
raise e
def _hash_password(self, password: str) -> str:
"""密码哈希"""
return hashlib.sha256(password.encode()).hexdigest()
def _verify_password(self, password: str, password_hash: str) -> bool:
"""验证密码"""
return self._hash_password(password) == password_hash
def create_user(self, username: str, email: str, password: str, display_name: str = None) -> str:
"""
创建用户
Args:
username: 用户名
email: 邮箱
password: 密码
display_name: 显示名称
Returns:
用户ID
"""
try:
# 检查用户名是否已存在
if self.get_user_by_username(username):
raise ValueError(f"Username '{username}' already exists")
# 检查邮箱是否已存在
if self.get_user_by_email(email):
raise ValueError(f"Email '{email}' already exists")
# 创建用户数据
user_data = {
"username": username,
"email": email,
"password_hash": self._hash_password(password),
"display_name": display_name or username,
"avatar_url": "",
"is_active": True,
"last_login": None,
"created_at": datetime.now().isoformat(),
"updated_at": datetime.now().isoformat()
}
# 插入用户记录
user_id = self.insert(self.table_name, user_data)
logger.info(f"Created user: {username} (ID: {user_id})")
return user_id
except Exception as e:
logger.error(f"Failed to create user '{username}': {e}")
raise e
def get_user_by_id(self, user_id: str) -> Optional[Dict[str, Any]]:
"""
根据ID获取用户
Args:
user_id: 用户ID
Returns:
用户信息如果不存在返回None
"""
try:
record = self.get(self.table_name, user_id)
if record:
return {
"id": record["id"],
**record["data"],
"created_at": record.get("created_at"),
"updated_at": record.get("updated_at")
}
return None
except Exception as e:
logger.error(f"Failed to get user by ID '{user_id}': {e}")
return None
def get_user_by_username(self, username: str) -> Optional[Dict[str, Any]]:
"""
根据用户名获取用户
Args:
username: 用户名
Returns:
用户信息如果不存在返回None
"""
try:
users = self.find_by_field(self.table_name, "username", username)
if users:
record = users[0]
return {
"id": record["id"],
**record["data"],
"created_at": record.get("created_at"),
"updated_at": record.get("updated_at")
}
return None
except Exception as e:
logger.error(f"Failed to get user by username '{username}': {e}")
return None
def get_user_by_email(self, email: str) -> Optional[Dict[str, Any]]:
"""
根据邮箱获取用户
Args:
email: 邮箱
Returns:
用户信息如果不存在返回None
"""
try:
users = self.find_by_field(self.table_name, "email", email)
if users:
record = users[0]
return {
"id": record["id"],
**record["data"],
"created_at": record.get("created_at"),
"updated_at": record.get("updated_at")
}
return None
except Exception as e:
logger.error(f"Failed to get user by email '{email}': {e}")
return None
def authenticate_user(self, username_or_email: str, password: str) -> Optional[Dict[str, Any]]:
"""
用户认证
Args:
username_or_email: 用户名或邮箱
password: 密码
Returns:
认证成功返回用户信息失败返回None
"""
try:
# 尝试按用户名查找
user = self.get_user_by_username(username_or_email)
# 如果按用户名找不到,尝试按邮箱查找
if not user:
user = self.get_user_by_email(username_or_email)
# 验证用户存在且密码正确
if user and self._verify_password(password, user["password_hash"]):
# 更新最后登录时间
self.update_last_login(user["id"])
# 返回用户信息(不包含密码哈希)
user_info = user.copy()
del user_info["password_hash"]
logger.info(f"User authenticated: {user['username']}")
return user_info
logger.warning(f"Authentication failed for: {username_or_email}")
return None
except Exception as e:
logger.error(f"Authentication error for '{username_or_email}': {e}")
return None
def update_user(self, user_id: str, updates: Dict[str, Any]) -> bool:
"""
更新用户信息
Args:
user_id: 用户ID
updates: 要更新的字段
Returns:
更新成功返回True
"""
try:
# 获取现有用户信息
existing_user = self.get_user_by_id(user_id)
if not existing_user:
logger.warning(f"User not found: {user_id}")
return False
# 准备更新数据
updated_data = existing_user.copy()
# 移除不应该直接更新的字段
protected_fields = ["id", "created_at", "password_hash"]
for field in protected_fields:
if field in updates:
del updates[field]
# 应用更新
updated_data.update(updates)
updated_data["updated_at"] = datetime.now().isoformat()
# 移除元数据字段,只保留数据字段
data_fields = {k: v for k, v in updated_data.items()
if k not in ["id", "created_at", "updated_at"]}
# 执行更新
result = self.update(self.table_name, user_id, data_fields)
if result:
logger.info(f"Updated user: {user_id}")
return result
except Exception as e:
logger.error(f"Failed to update user '{user_id}': {e}")
return False
def update_password(self, user_id: str, new_password: str) -> bool:
"""
更新用户密码
Args:
user_id: 用户ID
new_password: 新密码
Returns:
更新成功返回True
"""
try:
# 获取现有用户信息
existing_user = self.get_user_by_id(user_id)
if not existing_user:
logger.warning(f"User not found: {user_id}")
return False
# 更新密码哈希
updated_data = existing_user.copy()
updated_data["password_hash"] = self._hash_password(new_password)
updated_data["updated_at"] = datetime.now().isoformat()
# 移除元数据字段
data_fields = {k: v for k, v in updated_data.items()
if k not in ["id", "created_at", "updated_at"]}
# 执行更新
result = self.update(self.table_name, user_id, data_fields)
if result:
logger.info(f"Password updated for user: {user_id}")
return result
except Exception as e:
logger.error(f"Failed to update password for user '{user_id}': {e}")
return False
def update_last_login(self, user_id: str) -> bool:
"""
更新最后登录时间
Args:
user_id: 用户ID
Returns:
更新成功返回True
"""
try:
return self.update_user(user_id, {
"last_login": datetime.now().isoformat()
})
except Exception as e:
logger.error(f"Failed to update last login for user '{user_id}': {e}")
return False
def deactivate_user(self, user_id: str) -> bool:
"""
停用用户
Args:
user_id: 用户ID
Returns:
操作成功返回True
"""
try:
return self.update_user(user_id, {"is_active": False})
except Exception as e:
logger.error(f"Failed to deactivate user '{user_id}': {e}")
return False
def activate_user(self, user_id: str) -> bool:
"""
激活用户
Args:
user_id: 用户ID
Returns:
操作成功返回True
"""
try:
return self.update_user(user_id, {"is_active": True})
except Exception as e:
logger.error(f"Failed to activate user '{user_id}': {e}")
return False
def delete_user(self, user_id: str) -> bool:
"""
删除用户
Args:
user_id: 用户ID
Returns:
删除成功返回True
"""
try:
result = self.delete(self.table_name, user_id)
if result:
logger.info(f"Deleted user: {user_id}")
return result
except Exception as e:
logger.error(f"Failed to delete user '{user_id}': {e}")
return False
def get_all_users(self, include_inactive: bool = False, limit: int = 100) -> List[Dict[str, Any]]:
"""
获取所有用户
Args:
include_inactive: 是否包含非活跃用户
limit: 最大返回数量
Returns:
用户列表
"""
try:
all_records = self.find_all(self.table_name, limit)
users = []
for record in all_records:
user_info = {
"id": record["id"],
**record["data"],
"created_at": record.get("created_at"),
"updated_at": record.get("updated_at")
}
# 移除密码哈希
if "password_hash" in user_info:
del user_info["password_hash"]
# 根据活跃状态过滤
if include_inactive or user_info.get("is_active", True):
users.append(user_info)
return users
except Exception as e:
logger.error(f"Failed to get all users: {e}")
return []
def get_user_count(self, include_inactive: bool = False) -> int:
"""
获取用户数量
Args:
include_inactive: 是否包含非活跃用户
Returns:
用户数量
"""
try:
if include_inactive:
return self.count(self.table_name)
else:
# 获取活跃用户数量(简单实现,可优化)
active_users = self.get_all_users(include_inactive=False)
return len(active_users)
except Exception as e:
logger.error(f"Failed to get user count: {e}")
return 0
def search_users(self, query: str, limit: int = 50) -> List[Dict[str, Any]]:
"""
搜索用户
Args:
query: 搜索关键词匹配用户名邮箱显示名称
limit: 最大返回数量
Returns:
匹配的用户列表
"""
try:
all_users = self.get_all_users(include_inactive=True, limit=limit * 2)
matching_users = []
query_lower = query.lower()
for user in all_users:
if len(matching_users) >= limit:
break
# 检查用户名、邮箱、显示名称是否匹配
username = user.get("username", "").lower()
email = user.get("email", "").lower()
display_name = user.get("display_name", "").lower()
if (query_lower in username or
query_lower in email or
query_lower in display_name):
matching_users.append(user)
return matching_users
except Exception as e:
logger.error(f"Failed to search users with query '{query}': {e}")
return []
# 创建全局用户表实例
user_table = UserTable()

View File

@ -154,7 +154,30 @@ class Kv:
except Exception as e:
logger.error(f"An unexpected error occurred while bulk setting keys: {e}")
raise e
def gets(self, keys: list[str]):
"""
批量获取多个键的值
Args:
keys: 要获取的键列表
Returns:
包含键值对的字典
"""
try:
# 由于Cloudflare KV的批量获取API有问题我们使用单个获取的方式
result = {}
for key in keys:
value = self.get(key)
if value is not None:
result[key] = value
return result
except Exception as e:
logger.error(f"An error occurred while bulk getting keys from cloudflare: {e}")
raise e
def removes(self, keys: list[str]):
"""
批量删除多个键