from fastapi import APIRouter, HTTPException, Depends from app.models.models import UserInfo, PasswordChangeRequest, UserListResponse, CreateUserRequest, UpdateUserRequest from app.core.database import get_db_connection from app.core.auth import get_current_user from app.core.config import DEFAULT_RESET_PASSWORD import hashlib import datetime import re router = APIRouter() def validate_email(email: str) -> bool: """Basic email validation""" pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' return re.match(pattern, email) is not None def hash_password(password: str) -> str: return hashlib.sha256(password.encode()).hexdigest() @router.post("/users", status_code=201) def create_user(request: CreateUserRequest, current_user: dict = Depends(get_current_user)): if current_user['role_id'] != 1: # 1 is admin raise HTTPException(status_code=403, detail="仅管理员有权限创建用户") # Validate email format if not validate_email(request.email): raise HTTPException(status_code=400, detail="邮箱格式不正确") with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) # Check if username exists cursor.execute("SELECT user_id FROM users WHERE username = %s", (request.username,)) if cursor.fetchone(): raise HTTPException(status_code=400, detail="用户名已存在") # Use provided password or default password password = request.password if request.password else DEFAULT_RESET_PASSWORD hashed_password = hash_password(password) # Insert new user query = "INSERT INTO users (username, password_hash, caption, email, role_id, created_at) VALUES (%s, %s, %s, %s, %s, %s)" created_at = datetime.datetime.utcnow() cursor.execute(query, (request.username, hashed_password, request.caption, request.email, request.role_id, created_at)) connection.commit() return {"message": "用户创建成功"} @router.put("/users/{user_id}", response_model=UserInfo) def update_user(user_id: int, request: UpdateUserRequest, current_user: dict = Depends(get_current_user)): if current_user['role_id'] != 1: # 1 is admin raise HTTPException(status_code=403, detail="仅管理员有权限修改用户信息") # Validate email format if provided if request.email and not validate_email(request.email): raise HTTPException(status_code=400, detail="邮箱格式不正确") with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) # Check if user exists cursor.execute("SELECT user_id, username, caption, email, role_id FROM users WHERE user_id = %s", (user_id,)) existing_user = cursor.fetchone() if not existing_user: raise HTTPException(status_code=404, detail="用户不存在") # Check if username is being changed and if it already exists if request.username and request.username != existing_user['username']: cursor.execute("SELECT user_id FROM users WHERE username = %s AND user_id != %s", (request.username, user_id)) if cursor.fetchone(): raise HTTPException(status_code=400, detail="用户名已存在") # Prepare update data, using existing values if not provided update_data = { 'username': request.username if request.username else existing_user['username'], 'caption': request.caption if request.caption else existing_user['caption'], 'email': request.email if request.email else existing_user['email'], 'role_id': request.role_id if request.role_id is not None else existing_user['role_id'] } # Update user query = "UPDATE users SET username = %s, caption = %s, email = %s, role_id = %s WHERE user_id = %s" cursor.execute(query, (update_data['username'], update_data['caption'], update_data['email'], update_data['role_id'], user_id)) connection.commit() # Return updated user info cursor.execute("SELECT user_id, username, caption, email, created_at FROM users WHERE user_id = %s", (user_id,)) updated_user = cursor.fetchone() return UserInfo( user_id=updated_user['user_id'], username=updated_user['username'], caption=updated_user['caption'], email=updated_user['email'], created_at=updated_user['created_at'], meetings_created=0, # This is not accurate, but it is not displayed in the list meetings_attended=0 ) @router.delete("/users/{user_id}") def delete_user(user_id: int, current_user: dict = Depends(get_current_user)): if current_user['role_id'] != 1: # 1 is admin raise HTTPException(status_code=403, detail="仅管理员有权限删除用户") with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) # Check if user exists cursor.execute("SELECT user_id FROM users WHERE user_id = %s", (user_id,)) if not cursor.fetchone(): raise HTTPException(status_code=404, detail="用户不存在") # Delete user cursor.execute("DELETE FROM users WHERE user_id = %s", (user_id,)) connection.commit() return {"message": "用户删除成功"} @router.post("/users/{user_id}/reset-password") def reset_password(user_id: int, current_user: dict = Depends(get_current_user)): if current_user['role_id'] != 1: # 1 is admin raise HTTPException(status_code=403, detail="仅管理员有权限重置密码") with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) # Check if user exists cursor.execute("SELECT user_id FROM users WHERE user_id = %s", (user_id,)) if not cursor.fetchone(): raise HTTPException(status_code=404, detail="用户不存在") # Hash password hashed_password = hash_password(DEFAULT_RESET_PASSWORD) # Update user password query = "UPDATE users SET password_hash = %s WHERE user_id = %s" cursor.execute(query, (hashed_password, user_id)) connection.commit() return {"message": f"用户 {user_id} 的密码已重置"} @router.get("/users", response_model=UserListResponse) def get_all_users(page: int = 1, size: int = 10, current_user: dict = Depends(get_current_user)): with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) # Get total count cursor.execute("SELECT COUNT(*) as total FROM users") total = cursor.fetchone()['total'] # Get paginated users offset = (page - 1) * size query = ''' SELECT user_id, username, caption, email, created_at, (SELECT COUNT(*) FROM meetings WHERE user_id = u.user_id) as meetings_created, (SELECT COUNT(*) FROM attendees WHERE user_id = u.user_id) as meetings_attended FROM users u ORDER BY user_id ASC LIMIT %s OFFSET %s ''' cursor.execute(query, (size, offset)) users = cursor.fetchall() user_list = [UserInfo(**user) for user in users] return UserListResponse(users=user_list, total=total) @router.get("/users/{user_id}", response_model=UserInfo) def get_user_info(user_id: int, current_user: dict = Depends(get_current_user)): with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) user_query = "SELECT user_id, username, caption, email, created_at FROM users WHERE user_id = %s" cursor.execute(user_query, (user_id,)) user = cursor.fetchone() if not user: raise HTTPException(status_code=404, detail="用户不存在") created_query = "SELECT COUNT(*) as count FROM meetings WHERE user_id = %s" cursor.execute(created_query, (user_id,)) meetings_created = cursor.fetchone()['count'] attended_query = "SELECT COUNT(*) as count FROM attendees WHERE user_id = %s" cursor.execute(attended_query, (user_id,)) meetings_attended = cursor.fetchone()['count'] return UserInfo( user_id=user['user_id'], username=user['username'], caption=user['caption'], email=user['email'], created_at=user['created_at'], meetings_created=meetings_created, meetings_attended=meetings_attended ) @router.put("/users/{user_id}/password") def update_password(user_id: int, request: PasswordChangeRequest, current_user: dict = Depends(get_current_user)): if user_id != current_user['user_id'] and current_user['role_id'] != 1: raise HTTPException(status_code=403, detail="没有权限修改其他用户的密码") with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) cursor.execute("SELECT password_hash FROM users WHERE user_id = %s", (user_id,)) user = cursor.fetchone() if not user: raise HTTPException(status_code=404, detail="用户不存在") # If not admin, verify old password if current_user['role_id'] != 1: if user['password_hash'] != hash_password(request.old_password): raise HTTPException(status_code=400, detail="旧密码错误") new_password_hash = hash_password(request.new_password) cursor.execute("UPDATE users SET password_hash = %s WHERE user_id = %s", (new_password_hash, user_id)) connection.commit() return {"message": "密码修改成功"}