Группа: в рейтинге группы только текущие участники

Удалённый из группы игрок больше не остаётся в «Списке игроков»: leaderboard
получает набор текущих участников, и group_stats фильтрует по нему вывод до
сортировки, так что места нумеруются без пропусков. Расчёт не меняется —
групповая цепочка проигрывает все партии группы, и партии с ушедшим по-прежнему
влияют на рейтинг оставшихся; счётчик партий и статистика фракций группы тоже
прежние. Общий топ и главная без изменений. После удаления участника фронт
сразу перезапрашивает статистику группы.

Тесты: удалённый пропадает из группы, но остаётся в общем топе, рейтинг
оставшегося не меняется, после возврата игрок снова в списке; ранги после
удаления перенумерованы. #76

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqSoRj99iwVEH5U5fnZgsd
This commit is contained in:
2026-09-14 23:47:24 +03:00
co-authored by Claude Opus 5
parent 171aebb6f8
commit ba69b9f21d
3 changed files with 105 additions and 4 deletions
+18 -4
View File
@@ -109,8 +109,13 @@ def leaderboard(
*,
history: list[RatedMatch] | None = None,
rep: Replay | None = None,
member_ids: set[int] | None = None,
) -> dict:
"""Топ: общий или группы. history/rep — уже посчитанные (home их переиспользует)."""
"""Топ: общий или группы. history/rep — уже посчитанные (home их переиспользует).
member_ids — показывать только этих игроков (топ группы — её текущий состав, #76).
Фильтруется вывод, а не расчёт: партии с ушедшим игроком остаются в цепочке и влияют
на рейтинг оставшихся. Места нумеруются уже после фильтра."""
if history is None:
history = load_history(session, group_id)
if rep is None:
@@ -119,7 +124,8 @@ def leaderboard(
by_user: dict[int, list[tuple[RatedMatch, RatedSeat]]] = defaultdict(list)
for m in history:
for s in m.seats:
by_user[s.user_id].append((m, s))
if member_ids is None or s.user_id in member_ids:
by_user[s.user_id].append((m, s))
users = (
{u.id: u for u in session.exec(select(User).where(User.id.in_(list(by_user)))).all()}
if by_user
@@ -263,7 +269,15 @@ def profile_stats(
def group_stats(session: Session, group_id: int) -> dict:
history = load_history(session, group_id)
board = leaderboard(session, group_id, history=history, rep=replay(history))
members = membership_service.list_members(session, group_id)
# Список игроков группы — только её текущий состав: удалённый из группы в нём не висит.
board = leaderboard(
session,
group_id,
history=history,
rep=replay(history),
member_ids={u.id for _m, u in members}, # type: ignore[misc]
)
last_played = max((m.played_at for m in history), default=None)
games: dict[int, int] = defaultdict(int)
@@ -293,7 +307,7 @@ def group_stats(session: Session, group_id: int) -> dict:
e["user_id"] for e in board["provisional"]
}
inactive = []
for _m, u in membership_service.list_members(session, group_id):
for _m, u in members:
if u.id in played_ids:
continue
inactive.append(