SSE: не рассылать ratings на правки без влияния на рейтинг; событие group при смене настроек группы

- notify.match_changed получил флаг ratings: фото (игрок и админ) его не шлют, правка
  партии — только если изменились входы рейтинга (match_service.rating_inputs до/после).
- PATCH /api/groups/{id} публикует group — переименование и правило 9 раундов видны
  остальным участникам сразу.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 13:52:44 +03:00
co-authored by Claude Opus 5.5
parent 0b33b442e9
commit ef0e75aef2
6 changed files with 97 additions and 9 deletions
+6 -3
View File
@@ -243,6 +243,7 @@ def update_match(
admin: User = Depends(get_current_admin),
) -> s.MatchRead:
match = match_service.get_match(session, match_id)
rating_before = match_service.rating_inputs(session, match)
match = match_service.update_match(
session,
match,
@@ -265,7 +266,9 @@ def update_match(
ip=client_ip(request),
)
session.commit()
notify.match_changed(session, match)
notify.match_changed(
session, match, ratings=match_service.rating_inputs(session, match) != rating_before
)
return build_match_read(session, match, can_modify=True)
@@ -356,7 +359,7 @@ def admin_add_attachment(
att = attachment_service.add_photo(
session, match, admin, content, ext, user_service.avatar_media_type(ext)
)
notify.match_changed(session, match)
notify.match_changed(session, match, ratings=False)
return attachment_read(att, f"/api/admin/matches/{match_id}")
@@ -369,7 +372,7 @@ def admin_delete_attachment(
) -> s.OkResponse:
match = match_service.get_match(session, match_id)
attachment_service.delete(session, match, attachment_id)
notify.match_changed(session, match)
notify.match_changed(session, match, ratings=False)
return s.OkResponse()
+1
View File
@@ -93,6 +93,7 @@ def update_group(
group_service.rename_group(session, group, body.name)
if body.nine_rounds_rule is not None:
group_service.set_nine_rounds_rule(session, group, body.nine_rounds_rule)
notify.group_changed(session, group_id) # остальным участникам — живое обновление настроек
return _detail(session, group_id, user.id) # type: ignore[arg-type]
+6 -3
View File
@@ -234,6 +234,7 @@ def update_match(
) -> s.MatchRead:
match = match_service.get_match(session, match_id)
match_service.assert_can_modify(session, match, user)
rating_before = match_service.rating_inputs(session, match)
match = match_service.update_match(
session,
match,
@@ -257,7 +258,9 @@ def update_match(
user_agent=request.headers.get("user-agent"),
)
session.commit()
notify.match_changed(session, match)
notify.match_changed(
session, match, ratings=match_service.rating_inputs(session, match) != rating_before
)
return build_match_read(session, match, can_modify=match_service.can_modify(session, match, user))
@@ -304,7 +307,7 @@ def add_attachment(
att = attachment_service.add_photo(
session, match, user, content, ext, user_service.avatar_media_type(ext)
)
notify.match_changed(session, match)
notify.match_changed(session, match, ratings=False)
return attachment_read(att, f"/api/matches/{match_id}")
@@ -318,7 +321,7 @@ def delete_attachment(
match = match_service.get_match(session, match_id)
_assert_can_attach(session, match, user)
attachment_service.delete(session, match, attachment_id)
notify.match_changed(session, match)
notify.match_changed(session, match, ratings=False)
return s.OkResponse()
+21
View File
@@ -479,6 +479,27 @@ def assert_can_modify(session: Session, match: Match, user: User) -> None:
raise ForbiddenError("Недостаточно прав для изменения партии.")
def rating_inputs(session: Session, match: Match) -> tuple:
"""Снимок всего, что из партии читает рейтинг (stats_service.load_history): порядок
в истории, итоги и места. Сравнение снимков до и после правки показывает, сдвинула ли
она рейтинг, — комментарий или фото его не трогают."""
seats = session.exec(
select(MatchParticipant).where(MatchParticipant.match_id == match.id)
).all()
return (
match.status,
match.played_at,
match.finished_at,
match.win_reason,
match.end_round,
match.nine_rounds_rule,
sorted(
(p.user_id, p.faction_id, p.place, p.eliminated, p.objectives, p.worlds)
for p in seats
),
)
def update_match(
session: Session,
match: Match,
+6 -3
View File
@@ -32,12 +32,15 @@ def _ratings_changed(session: Session, notified: list[int]) -> None:
hub.publish(ids, {"type": "ratings"})
def match_changed(session: Session, match: Match) -> None:
def match_changed(session: Session, match: Match, *, ratings: bool = True) -> None:
"""Партия изменилась — уведомить всех участников её группы, а если она завершена —
и остальных игроков (_ratings_changed)."""
и остальных игроков (_ratings_changed).
ratings=False — правка, которая рейтинг не двигает (фото, комментарий): тогда
остальным игрокам незачем перезапрашивать все рейтинговые витрины."""
members = _group_member_ids(session, match.group_id)
hub.publish(members, {"type": "match", "match_id": match.id, "group_id": match.group_id})
if match.status == "finished":
if ratings and match.status == "finished":
_ratings_changed(session, members)