rewrited logic structure
This commit is contained in:
195
group_system/storage/groups.py
Normal file
195
group_system/storage/groups.py
Normal file
@@ -0,0 +1,195 @@
|
||||
"""学生端分组用例和班级快照查询。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
class GroupOperationsMixin:
|
||||
|
||||
def class_snapshot(self, class_name: str) -> dict[str, Any]:
|
||||
with self.lock:
|
||||
groups = self.connection.execute(
|
||||
"""SELECT g.id,g.name,g.leader_student_id,g.created_at,
|
||||
s.student_no AS leader_student_no,s.name AS leader_name
|
||||
FROM groups g LEFT JOIN students s ON s.id=g.leader_student_id
|
||||
WHERE g.class_name=? ORDER BY g.id""",
|
||||
(class_name,),
|
||||
).fetchall()
|
||||
group_ids = [row["id"] for row in groups]
|
||||
members: dict[int, list[dict[str, Any]]] = {row["id"]: [] for row in groups}
|
||||
if group_ids:
|
||||
placeholders = ",".join("?" for _ in group_ids)
|
||||
member_rows = self.connection.execute(
|
||||
f"""SELECT m.group_id,st.id,st.student_no,st.name,st.gender,g.leader_student_id
|
||||
FROM group_members m JOIN students st ON st.id=m.student_id
|
||||
JOIN groups g ON g.id=m.group_id
|
||||
WHERE m.group_id IN ({placeholders})
|
||||
ORDER BY CASE WHEN st.id=g.leader_student_id THEN 0 ELSE 1 END,m.joined_at,st.student_no""",
|
||||
group_ids,
|
||||
).fetchall()
|
||||
pending = [dict(row) for row in member_rows]
|
||||
for member in pending:
|
||||
member["is_leader"] = member["id"] == member["leader_student_id"]
|
||||
member.pop("leader_student_id", None)
|
||||
members[member["group_id"]].append(member)
|
||||
|
||||
ungrouped_rows = self.connection.execute(
|
||||
"""SELECT id,student_no,name,gender FROM students
|
||||
WHERE class_name=? AND id NOT IN (SELECT student_id FROM group_members)
|
||||
ORDER BY student_no""",
|
||||
(class_name,),
|
||||
).fetchall()
|
||||
total = self.connection.execute(
|
||||
"SELECT COUNT(*) AS n FROM students WHERE class_name=?", (class_name,)
|
||||
).fetchone()["n"]
|
||||
grouped = self.connection.execute(
|
||||
"""SELECT COUNT(*) AS n FROM group_members m
|
||||
JOIN students s ON s.id=m.student_id WHERE s.class_name=?""",
|
||||
(class_name,),
|
||||
).fetchone()["n"]
|
||||
|
||||
group_data = []
|
||||
for row in groups:
|
||||
group_data.append(
|
||||
{
|
||||
**dict(row),
|
||||
"locked": self.is_locked(class_name),
|
||||
"member_count": len(members[row["id"]]),
|
||||
"full": len(members[row["id"]]) >= self.group_limit(),
|
||||
"members": members[row["id"]],
|
||||
}
|
||||
)
|
||||
return {
|
||||
"class_name": class_name,
|
||||
"locked": self.is_locked(class_name),
|
||||
"group_limit": self.group_limit(),
|
||||
"groups": group_data,
|
||||
"ungrouped": [dict(row) for row in ungrouped_rows],
|
||||
"statistics": {"total_students": total, "grouped_students": grouped, "group_count": len(group_data)},
|
||||
}
|
||||
|
||||
def create_group(self, student_id: int, group_name: str) -> tuple[bool, str, int | None]:
|
||||
student = self.get_student(student_id)
|
||||
if student is None:
|
||||
return False, "学生不存在", None
|
||||
if self.is_locked(student["class_name"]):
|
||||
return False, "老师已停止分组操作,当前只能查看", None
|
||||
current = self.student_membership(student_id)
|
||||
if current is not None:
|
||||
return False, "你已加入其他组,不能创建组;请先退出当前组", None
|
||||
if student["must_change_password"]:
|
||||
return False, "首次登录必须先修改密码", None
|
||||
group_name = group_name.strip() or student["name"]
|
||||
with self.lock, self.connection:
|
||||
count = self.connection.execute(
|
||||
"SELECT COUNT(*) AS n FROM groups WHERE class_name=?", (student["class_name"],)
|
||||
).fetchone()["n"]
|
||||
cursor = self.connection.execute(
|
||||
"INSERT INTO groups(class_name,name,leader_student_id) VALUES(?,?,?)",
|
||||
(student["class_name"], group_name, student_id),
|
||||
)
|
||||
group_id = int(cursor.lastrowid)
|
||||
self.connection.execute(
|
||||
"INSERT INTO group_members(group_id,student_id) VALUES(?,?)",
|
||||
(group_id, student_id),
|
||||
)
|
||||
return True, f"“{group_name}”创建成功,你是组长", group_id
|
||||
|
||||
def join_group(self, student_id: int, group_id: int, confirmed: bool) -> tuple[bool, str]:
|
||||
student = self.get_student(student_id)
|
||||
if student is None:
|
||||
return False, "学生不存在"
|
||||
if student["must_change_password"]:
|
||||
return False, "首次登录必须先修改密码"
|
||||
if self.is_locked(student["class_name"]):
|
||||
return False, "老师已停止分组操作,当前只能查看"
|
||||
with self.lock:
|
||||
group = self.connection.execute(
|
||||
"SELECT * FROM groups WHERE id=?", (group_id,)
|
||||
).fetchone()
|
||||
current = self.connection.execute(
|
||||
"""SELECT m.group_id,g.name,g.leader_student_id
|
||||
FROM group_members m JOIN groups g ON g.id=m.group_id WHERE m.student_id=?""",
|
||||
(student_id,),
|
||||
).fetchone()
|
||||
if group is None:
|
||||
return False, "目标小组不存在"
|
||||
if group["class_name"] != student["class_name"]:
|
||||
return False, "不能加入其他班级的小组"
|
||||
if current and current["group_id"] == group_id:
|
||||
return False, "你已经在这个组里"
|
||||
member_count = self.connection.execute(
|
||||
"SELECT COUNT(*) AS n FROM group_members WHERE group_id=?", (group_id,)
|
||||
).fetchone()["n"]
|
||||
group_limit = self.group_limit()
|
||||
if member_count >= group_limit:
|
||||
return False, f"该组已有 {group_limit} 人,不能再加入新成员"
|
||||
if current and not confirmed:
|
||||
role = "组长,原组会被解散" if current["leader_student_id"] == student_id else "成员"
|
||||
return False, f"你当前是“{current['name']}”的{role}。加入新组前必须退出原组;确认后才会执行。"
|
||||
|
||||
with self.lock, self.connection:
|
||||
if current:
|
||||
if current["leader_student_id"] == student_id:
|
||||
self.connection.execute("DELETE FROM groups WHERE id=?", (current["group_id"],))
|
||||
else:
|
||||
self.connection.execute(
|
||||
"DELETE FROM group_members WHERE student_id=?", (student_id,)
|
||||
)
|
||||
self.connection.execute(
|
||||
"INSERT INTO group_members(group_id,student_id) VALUES(?,?)",
|
||||
(group_id, student_id),
|
||||
)
|
||||
return True, "加入成功"
|
||||
|
||||
def leave_group(self, student_id: int, confirmed: bool) -> tuple[bool, str]:
|
||||
if self.get_student(student_id) is None:
|
||||
return False, "学生不存在"
|
||||
current = self.student_membership(student_id)
|
||||
if current is None:
|
||||
return False, "你当前没有加入任何小组"
|
||||
if self.is_locked(current["class_name"]):
|
||||
return False, "老师已停止分组操作,当前只能查看"
|
||||
is_leader = current["leader_student_id"] == student_id
|
||||
if not confirmed:
|
||||
if is_leader:
|
||||
return False, "你是组长。退出时你创建的组将被解散,所有成员都会变为未分组;确认后才会执行。"
|
||||
return False, "退出后可以再加入其他组;确认后才会执行。"
|
||||
with self.lock, self.connection:
|
||||
if is_leader:
|
||||
self.connection.execute("DELETE FROM groups WHERE id=?", (current["group_id"],))
|
||||
else:
|
||||
self.connection.execute(
|
||||
"DELETE FROM group_members WHERE group_id=? AND student_id=?",
|
||||
(current["group_id"], student_id),
|
||||
)
|
||||
return True, "组长已解散小组" if is_leader else "已退出小组"
|
||||
|
||||
def leader_remove_member(self, leader_student_id: int, member_student_id: int) -> tuple[bool, str]:
|
||||
with self.lock, self.connection:
|
||||
leader_group = self.connection.execute(
|
||||
"""SELECT m.group_id,g.name,g.class_name,g.leader_student_id
|
||||
FROM group_members m JOIN groups g ON g.id=m.group_id
|
||||
WHERE m.student_id=?""",
|
||||
(leader_student_id,),
|
||||
).fetchone()
|
||||
if leader_group is None or leader_group["leader_student_id"] != leader_student_id:
|
||||
return False, "只有组长可以移出组员"
|
||||
if leader_student_id == member_student_id:
|
||||
return False, "组长不能移出自己;如需退出请解散小组"
|
||||
if self.is_locked(leader_group["class_name"]):
|
||||
return False, "老师已停止分组操作,当前只能查看"
|
||||
member = self.connection.execute(
|
||||
"""SELECT st.name
|
||||
FROM group_members m JOIN students st ON st.id=m.student_id
|
||||
WHERE m.student_id=? AND m.group_id=?""",
|
||||
(member_student_id, leader_group["group_id"]),
|
||||
).fetchone()
|
||||
if member is None:
|
||||
return False, "该学生不在你的小组中"
|
||||
self.connection.execute(
|
||||
"DELETE FROM group_members WHERE student_id=? AND group_id=?",
|
||||
(member_student_id, leader_group["group_id"]),
|
||||
)
|
||||
return True, f"已将 {member['name']} 移出小组"
|
||||
Reference in New Issue
Block a user