table_game/backend/app/routers/user_group.py
2025-03-10 08:35:19 +08:00

535 lines
17 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from datetime import datetime, timedelta
from ..db import get_connection
from ..utils.jwt_handler import verify_token
from apscheduler.schedulers.background import BackgroundScheduler
from datetime import timezone, timedelta
from fastapi import FastAPI
scheduler = BackgroundScheduler()
router = APIRouter()
class CreateGroupRequest(BaseModel):
token: str
group_name: str
description: str
max_members: int
start_time: datetime
end_time: datetime
play_start_time: datetime
play_end_time: datetime
class JoinGroupRequest(BaseModel):
group_id: int
token: str
class GroupOperationRequest(BaseModel):
group_id: int
class GroupDetailsRequest(GroupOperationRequest):
token: str
class BaseTokenRequest(BaseModel):
token: str
class GroupListResponse(BaseModel):
group_id: int
group_name: str
start_date: datetime
start_time: datetime
end_time: datetime
play_start_time: datetime
play_end_time: datetime
group_status: str
max_members: int
current_members: int
class LeaveGroupRequest(GroupOperationRequest):
token: str
class DeleteGroupRequest(GroupOperationRequest):
token: str
class UpdateDescriptionRequest(GroupOperationRequest):
new_description: str
token: str
def _get_user_id(token: str):
try:
payload = verify_token(token)
phone_number = payload["sub"]
conn = get_connection()
cursor = conn.cursor()
cursor.execute("SELECT user_id FROM users WHERE phone_number = %s", (phone_number,))
result = cursor.fetchone()
if not result:
raise HTTPException(401, "用户不存在")
return result[0]
finally:
cursor.close()
conn.close()
def _check_group_timing(group_id: int):
conn = get_connection()
try:
cursor = conn.cursor()
cursor.execute("""
SELECT end_time, group_status
FROM game_groups
WHERE group_id = %s
""", (group_id,))
result = cursor.fetchone()
if not result:
raise HTTPException(404, "群组不存在")
end_time, status = result
return status
finally:
cursor.close()
conn.close()
@router.post("/create")
def create_group(request: CreateGroupRequest):
user_id = _get_user_id(request.token)
conn = get_connection()
try:
cursor = conn.cursor()
start_time = request.start_time.astimezone(timezone(timedelta(hours=8)))
end_time = request.end_time.astimezone(timezone(timedelta(hours=8)))
play_start_time = request.play_start_time.astimezone(timezone(timedelta(hours=8)))
play_end_time = request.play_end_time.astimezone(timezone(timedelta(hours=8)))
cursor.execute("""
INSERT INTO game_groups
(user_id, group_name, description, max_members, start_date,
start_time, end_time, group_status, play_start_time, play_end_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, 'recruiting', %s, %s)
""", (user_id, request.group_name, request.description,
request.max_members, start_time.date(), start_time, end_time, play_start_time, play_end_time))
# 获取新创建的群组ID
group_id = cursor.lastrowid
# 加入群组
cursor.execute("""
INSERT INTO group_members (group_id, user_id)
VALUES (%s, %s)
""", (group_id, user_id))
conn.commit()
return {"message": "群组创建成功"}
finally:
cursor.close()
conn.close()
@router.post("/join")
def join_group(request: JoinGroupRequest):
user_id = _get_user_id(request.token)
conn = get_connection()
try:
cursor = conn.cursor()
# 检查是否已加入
cursor.execute("SELECT 1 FROM group_members WHERE group_id = %s AND user_id = %s",
(request.group_id, user_id))
if cursor.fetchone():
raise HTTPException(400, "已加入该群组")
# 检查群组状态和人数
cursor.execute("""
SELECT max_members, play_start_time
FROM game_groups
WHERE group_id = %s
""", (request.group_id,))
group_info = cursor.fetchone()
# 获取当前实际人数
cursor.execute("""
SELECT COUNT(*)
FROM group_members
WHERE group_id = %s
""", (request.group_id,))
current_members = cursor.fetchone()[0]
if not group_info:
raise HTTPException(404, "群组不存在")
# 已移除的时间限制检查 ↓
if current_members >= group_info[0]:
raise HTTPException(400, "群组已满员")
# 加入群组
cursor.execute("""
INSERT INTO group_members (group_id, user_id)
VALUES (%s, %s)
""", (request.group_id, user_id))
# 自动更新群组状态
if current_members + 1 == group_info[0]:
cursor.execute("""
UPDATE game_groups
SET group_status = 'full'
WHERE group_id = %s
""", (request.group_id,))
conn.commit()
return {"message": "加入成功"}
finally:
cursor.close()
conn.close()
@router.post("/members")
def get_group_members(request: GroupOperationRequest):
conn = get_connection()
try:
cursor = conn.cursor(dictionary=True)
cursor.execute("""
SELECT u.user_id, u.username
FROM group_members gm
JOIN users u ON gm.user_id = u.user_id
WHERE gm.group_id = %s
""", (request.group_id,))
return cursor.fetchall()
finally:
cursor.close()
conn.close()
@router.post("/managed")
def my_managed_groups(request: BaseTokenRequest):
user_id = _get_user_id(request.token)
conn = get_connection()
try:
cursor = conn.cursor(dictionary=True)
cursor.execute("""
SELECT
g.group_id,
g.group_name,
g.start_date,
g.start_time,
g.end_time,
g.group_status,
g.max_members,
g.play_start_time,
g.play_end_time,
(SELECT COUNT(*) FROM group_members WHERE group_id = g.group_id) AS current_members
FROM game_groups g
WHERE user_id = %s
AND group_status IN ('recruiting', 'full', 'pause')
""", (user_id,))
return cursor.fetchall()
finally:
cursor.close()
conn.close()
# 退出群组接口
@router.post("/leave")
def leave_group(request: LeaveGroupRequest):
user_id = _get_user_id(request.token)
conn = get_connection()
try:
cursor = conn.cursor()
# 获取群组信息
cursor.execute("""
SELECT g.end_time, g.group_status, g.max_members
FROM game_groups g
WHERE g.group_id = %s
""", (request.group_id,))
group_info = cursor.fetchone()
if not group_info:
raise HTTPException(404, "群组不存在")
end_time, status, max_members = group_info
# 检查退出时间限制
current_time = datetime.now(timezone(timedelta(hours=8))).replace(tzinfo=None)
if current_time >= end_time - timedelta(hours=2):
raise HTTPException(400, "距离招募结束不足2小时无法退出")
# 删除成员记录
cursor.execute("""
DELETE FROM group_members
WHERE group_id = %s AND user_id = %s
""", (request.group_id, user_id))
if cursor.rowcount == 0:
raise HTTPException(404, "未加入该群组")
# 如果原状态是满员,检查并更新状态
if status == 'full':
cursor.execute("""
SELECT COUNT(*)
FROM group_members
WHERE group_id = %s
""", (request.group_id,))
current_members = cursor.fetchone()[0]
if current_members < max_members:
cursor.execute("""
UPDATE game_groups
SET group_status = 'recruiting'
WHERE group_id = %s
""", (request.group_id,))
conn.commit()
return {"message": "已成功退出群组"}
finally:
cursor.close()
conn.close()
# 删除群组接口
@router.post("/delete")
def delete_group(request: DeleteGroupRequest):
user_id = _get_user_id(request.token)
conn = get_connection()
try:
cursor = conn.cursor()
# 验证管理员权限
cursor.execute("""
SELECT 1 FROM game_groups
WHERE group_id = %s AND user_id = %s
""", (request.group_id, user_id))
if not cursor.fetchone():
raise HTTPException(403, "只有群主可以删除群组")
# 获取结束时间并检查时间限制
cursor.execute("""
SELECT end_time, group_status
FROM game_groups
WHERE group_id = %s
""", (request.group_id,))
result = cursor.fetchone()
if not result:
raise HTTPException(404, "群组不存在")
end_time, group_status = result
current_time = datetime.now(timezone(timedelta(hours=8))).replace(tzinfo=None)
if group_status != 'pause' and current_time >= end_time - timedelta(hours=1):
raise HTTPException(400, "距离招募结束不足1小时无法解散群组")
# 删除关联成员
cursor.execute("DELETE FROM group_members WHERE group_id = %s", (request.group_id,))
# 删除群组
cursor.execute("DELETE FROM game_groups WHERE group_id = %s", (request.group_id,))
conn.commit()
return {"message": "群组已删除"}
finally:
cursor.close()
conn.close()
# 获取我加入的群组
@router.post("/joined")
def my_joined_groups(request: BaseTokenRequest):
user_id = _get_user_id(request.token)
conn = get_connection()
try:
cursor = conn.cursor(dictionary=True)
cursor = conn.cursor(dictionary=True)
cursor.execute("""
SELECT g.group_id, g.group_name, g.start_date,
g.start_time, g.end_time, g.group_status,
g.max_members, g.play_start_time, g.play_end_time,
(SELECT COUNT(*) FROM group_members WHERE group_id = g.group_id) AS current_members
FROM game_groups g
JOIN group_members m ON g.group_id = m.group_id
WHERE m.user_id = %s
AND g.user_id != %s -- 新增排除创建者的条件
AND g.group_status IN ('recruiting', 'full', 'pause')
""", (user_id, user_id)) # 第二个user_id参数用于排除创建者
return cursor.fetchall()
finally:
cursor.close()
conn.close()
# 获取所有活跃群组
@router.get("/active")
def get_all_active_groups():
conn = get_connection()
try:
cursor = conn.cursor(dictionary=True)
cursor.execute("""
SELECT
group_id,
group_name,
start_date,
start_time,
end_time,
group_status,
max_members,
play_start_time,
play_end_time,
(SELECT COUNT(*) FROM group_members WHERE group_id = g.group_id) AS current_members
FROM game_groups g
WHERE group_status IN ('recruiting')
ORDER BY start_time ASC
""")
return cursor.fetchall()
finally:
cursor.close()
conn.close()
@router.post("/description")
def get_group_description(request: GroupOperationRequest):
conn = get_connection()
try:
cursor = conn.cursor(dictionary=True)
cursor.execute("""
SELECT description
FROM game_groups
WHERE group_id = %s
""", (request.group_id,))
result = cursor.fetchone()
if not result:
raise HTTPException(404, "群组不存在")
return {"description": result['description']}
finally:
cursor.close()
conn.close()
@router.post("/update_description")
def update_group_description(request: UpdateDescriptionRequest):
user_id = _get_user_id(request.token)
conn = get_connection()
try:
cursor = conn.cursor()
# 验证管理员权限
cursor.execute("""
SELECT 1 FROM game_groups
WHERE group_id = %s AND user_id = %s
""", (request.group_id, user_id))
if not cursor.fetchone():
raise HTTPException(403, "无权限修改该群组")
# 执行更新
cursor.execute("""
UPDATE game_groups
SET description = %s
WHERE group_id = %s
""", (request.new_description, request.group_id))
conn.commit()
return {"message": "群组简介已更新"}
finally:
cursor.close()
conn.close()
def _update_group_status():
conn = get_connection()
try:
cursor = conn.cursor()
now = datetime.now()
cursor.execute("""
UPDATE game_groups
SET group_status = 'pause'
WHERE group_status IN ('recruiting', 'full')
AND end_time < %s
""", (now,))
conn.commit()
finally:
cursor.close()
conn.close()
# 在已有路由后添加新接口
@router.get("/check_expired_groups")
def check_expired_groups():
conn = get_connection()
try:
cursor = conn.cursor()
now = datetime.now()
# 更新已满员的群组状态
cursor.execute("""
UPDATE game_groups
SET group_status = 'full'
WHERE group_status = 'recruiting'
AND (SELECT COUNT(*) FROM group_members WHERE group_id = game_groups.group_id) >= max_members
AND end_time > %s -- 仅处理未过期的群组
""", (now,))
full_count = cursor.rowcount
# 更新已过期的群组状态
cursor.execute("""
UPDATE game_groups
SET group_status = 'pause'
WHERE group_status IN ('recruiting', 'full')
AND end_time < %s
""", (now,))
expired_count = cursor.rowcount
conn.commit()
return {
"updated_to_full": full_count,
"updated_to_pause": expired_count
}
finally:
cursor.close()
conn.close()
# 在已有路由后添加新接口
@router.post("/group_details")
def get_group_details(request: GroupDetailsRequest):
user_id = _get_user_id(request.token)
conn = get_connection()
try:
cursor = conn.cursor(dictionary=True)
# 获取群组详情及创建者ID
cursor.execute("""
SELECT g.*, u.username as creator_name, (SELECT COUNT(*) FROM group_members WHERE group_id = g.group_id) AS current_members
FROM game_groups g
JOIN users u ON g.user_id = u.user_id
WHERE g.group_id = %s
""", (request.group_id,))
group_info = cursor.fetchone()
if not group_info:
raise HTTPException(404, "群组不存在")
# 判断是否为创建者
is_creator = group_info['user_id'] == user_id
is_joined = False
if not is_creator:
cursor.execute("""
SELECT 1 FROM group_members
WHERE group_id = %s AND user_id = %s
""", (request.group_id, user_id))
is_joined = cursor.fetchone() is not None
# 构建返回数据
return {
"group_name": group_info['group_name'],
"description": group_info['description'],
"start_date": group_info['start_date'],
"start_time": group_info['start_time'],
"end_time": group_info['end_time'],
"play_start_time": group_info['play_start_time'],
"play_end_time": group_info['play_end_time'],
"group_status": group_info['group_status'],
"max_members": group_info['max_members'],
"current_members": group_info['current_members'],
"creator_name": group_info['creator_name'],
"is_creator": is_creator,
"is_joined": is_joined if not is_creator else None # 创建者不返回加入状态
}
finally:
cursor.close()
conn.close()