Skip to content

Commit d7a5dad

Browse files
committed
allow for mass auditing of ranked status
1 parent f33c922 commit d7a5dad

File tree

3 files changed

+187
-1
lines changed

3 files changed

+187
-1
lines changed

assets/html/admin/index.html

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,39 @@
7878
});
7979
}
8080

81+
function audit_ranked_status_sm5() {
82+
alert("Auditing ranked status for SM5 in background...");
83+
fetch("/admin/audit_ranked_status/sm5", {
84+
method: "POST",
85+
headers: {
86+
"Content-Type": "application/json",
87+
"X-CSRFToken": getCookie("csrftoken")
88+
}
89+
});
90+
}
91+
92+
function audit_ranked_status_laserball() {
93+
alert("Auditing ranked status for Laserball in background...");
94+
fetch("/admin/audit_ranked_status/laserball", {
95+
method: "POST",
96+
headers: {
97+
"Content-Type": "application/json",
98+
"X-CSRFToken": getCookie("csrftoken")
99+
}
100+
});
101+
}
102+
103+
function audit_ranked_status_all() {
104+
alert("Auditing ranked status for all games in background...");
105+
fetch("/admin/audit_ranked_status/all", {
106+
method: "POST",
107+
headers: {
108+
"Content-Type": "application/json",
109+
"X-CSRFToken": getCookie("csrftoken")
110+
}
111+
});
112+
}
113+
81114
function flush_cache() {
82115
alert("Flushing cache in background...");
83116
fetch("/admin/flush_cache", {
@@ -121,6 +154,9 @@ <h1 style="text-align: center;">Dashboard</h1>
121154
<button onclick="recalculate_laserball_ratings()" class="button">Recalculate Laserball Ratings</button>
122155
<button onclick="migrate_games()" class="button">Migrate Games</button>
123156
<button onclick="backfill_events()" class="button">Backfill Events</button>
157+
<button onclick="audit_ranked_status_sm5()" class="button">Audit Ranked Status SM5</button>
158+
<button onclick="audit_ranked_status_laserball()" class="button">Audit Ranked Status Laserball</button>
159+
<button onclick="audit_ranked_status_all()" class="button">Audit Ranked Status All</button>
124160
<button onclick="flush_cache()" class="button">Flush Cache</button>
125161
</div>
126162

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
from sanic import Request
2+
from sanic.log import logger
3+
4+
from db.sm5 import SM5Game
5+
from db.laserball import LaserballGame
6+
from helpers import ratinghelper
7+
from db.types import IntRole
8+
from shared import app
9+
from utils import admin_only
10+
11+
@app.post("/admin/audit_ranked_status/<type:str>")
12+
@admin_only
13+
async def audit_ranked_status(request: Request, type: str) -> str:
14+
response = await request.respond(content_type="text/html")
15+
16+
logger.info(f"Starting ranked status audit for type: {type}")
17+
18+
# type is either "sm5" or "laserball" or "all"
19+
20+
if type not in ["sm5", "laserball", "all"]:
21+
return response.json({"status": "error", "message": "Invalid type"})
22+
23+
# go through each game and check ranked eligibility
24+
if type in ["sm5", "all"]:
25+
sm5_games = await SM5Game.all().order_by("-start_time")
26+
for game in sm5_games:
27+
# maybe eventually make elgibility criteria in a helper function
28+
29+
ranked = True
30+
31+
teams = await game.teams.all()
32+
entity_starts = await game.entity_starts.all()
33+
34+
team1 = None
35+
team2 = None
36+
37+
index = 1
38+
39+
for t in teams:
40+
if not t.color_name or not t.color_enum or t.name == "Neutral":
41+
continue
42+
43+
if index == 1:
44+
team1 = t
45+
else: # 2
46+
team2 = t
47+
48+
index += 1
49+
50+
team1_len = await game.entity_ends.filter(entity__team=team1, entity__type="player").count()
51+
team2_len = await game.entity_ends.filter(entity__team=team2, entity__type="player").count()
52+
53+
if team1_len > 7 or team2_len > 7 or team1_len < 5 or team2_len < 5 or team1_len != team2_len:
54+
ranked = False
55+
56+
57+
for t in teams:
58+
total_count = 0
59+
commander_count = 0
60+
heavy_count = 0
61+
scout_count = 0
62+
ammo_count = 0
63+
medic_count = 0
64+
65+
for e in entity_starts:
66+
if e.type == "player" and e.team == t:
67+
total_count += 1
68+
if e.role == IntRole.COMMANDER:
69+
commander_count += 1
70+
elif e.role == IntRole.HEAVY:
71+
heavy_count += 1
72+
elif e.role == IntRole.SCOUT:
73+
scout_count += 1
74+
elif e.role == IntRole.AMMO: # sometimes we have 2 ammos, but for ranking purposes we only want games with 1
75+
ammo_count += 1
76+
elif e.role == IntRole.MEDIC:
77+
medic_count += 1
78+
79+
if total_count == 0: # probably a neutral team
80+
continue
81+
82+
if commander_count != 1 or heavy_count != 1 or ammo_count != 1 or medic_count != 1 or scout_count < 1 or scout_count > 3:
83+
ranked = False
84+
85+
86+
for e in entity_starts:
87+
if e.type == "player" and e.entity_id.startswith("@") and e.name == e.battlesuit:
88+
ranked = False
89+
break
90+
91+
if ranked != game.ranked:
92+
logger.info(f"SM5 Game ID {game.id} ranked status changed from {game.ranked} to {ranked}")
93+
game.ranked = ranked
94+
await game.save()
95+
96+
# unranked -> ranked
97+
98+
if ranked:
99+
await ratinghelper.update_sm5_ratings(game)
100+
101+
if type in ["laserball", "all"]:
102+
laserball_games = await LaserballGame.all().order_by("-start_time")
103+
for game in laserball_games:
104+
ranked = True
105+
106+
teams = await game.teams.all()
107+
entity_starts = await game.entity_starts.all()
108+
109+
team1 = None
110+
team2 = None
111+
112+
index = 1
113+
114+
for t in teams:
115+
if not t.color_name or not t.color_enum or t.name == "Neutral":
116+
continue
117+
118+
if index == 1:
119+
team1 = t
120+
else: # 2
121+
team2 = t
122+
123+
index += 1
124+
125+
team1_len = await game.entity_ends.filter(entity__team=team1, entity__type="player").count()
126+
team2_len = await game.entity_ends.filter(entity__team=team2, entity__type="player").count()
127+
128+
if team1_len < 2 or team2_len < 2:
129+
ranked = False
130+
131+
for e in entity_starts:
132+
if e.type == "player" and e.entity_id.startswith("@") and e.name == e.battlesuit:
133+
logger.debug(f"Found non-member player {e.name}, unranking game")
134+
ranked = False
135+
break
136+
137+
if ranked != game.ranked:
138+
logger.info(f"Laserball Game ID {game.id} ranked status changed from {game.ranked} to {ranked}")
139+
game.ranked = ranked
140+
await game.save()
141+
142+
# unranked -> ranked
143+
144+
if ranked:
145+
await ratinghelper.update_laserball_ratings(game)
146+
147+
return response.json({"status": "ok"})

handlers/admin/game.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ async def admin_game_rank(request: Request, mode: str, id: Union[int, str]) -> s
7777
game.ranked = True
7878
await game.save()
7979

80-
await ratinghelper.update_sm5_ratings(game)
80+
if mode == "sm5":
81+
await ratinghelper.update_sm5_ratings(game)
82+
elif mode == "laserball":
83+
await ratinghelper.update_laserball_ratings(game)
8184

8285
return response.json({"status": "ok"})
8386

0 commit comments

Comments
 (0)