Skip to content

Commit c4c543a

Browse files
committed
fix: polish game queue table
[pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci fix: polish queue table [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci
1 parent 67143fd commit c4c543a

15 files changed

Lines changed: 293 additions & 126 deletions

File tree

config/docker/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ RUN apt-get update && apt-get install -y \
1010
firejail \
1111
&& rm -rf /var/lib/apt/lists/*
1212

13+
ENV UV_LINK_MODE copy
14+
1315
EXPOSE 8000

othello/apps/games/consumers.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,20 +97,27 @@ def match_update(self, event: dict[str, Any]) -> None:
9797
def send_match_update(self, object_id: int) -> None:
9898
if self.connected:
9999
match = Match.objects.get(id=object_id)
100-
score = "-"
100+
score = "? - ? - ?"
101101
if match.status == "completed":
102-
score = f"{match.player1_wins}-{match.ties}-{match.player2_wins}"
102+
score = f"{match.player1_wins} - {match.ties} - {match.player2_wins}"
103103
self.send_json(
104104
{
105105
"type": "match_update",
106106
"match_id": match.id,
107107
"status": match.status,
108-
"player1": match.player1.get_game_name(),
109-
"player2": match.player2.get_game_name(),
108+
"status_display": match.get_status_display(),
109+
"player1": match.player1.user.username,
110+
"player2": match.player2.user.username,
110111
"ranked": "Yes" if match.is_ranked else "No",
111112
"num_games": match.num_games,
112113
"score": score,
113114
"created_at": match.created_at.isoformat(),
115+
"player1_rating_delta": match.player1_rating_delta
116+
if match.player1_rating_delta
117+
else None,
118+
"player2_rating_delta": match.player2_rating_delta
119+
if match.player2_rating_delta
120+
else None,
114121
}
115122
)
116123

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 5.2.10 on 2026-02-05 18:27
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('games', '0035_game_is_scrimmage'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='match',
15+
name='player1_rating_delta',
16+
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True),
17+
),
18+
migrations.AddField(
19+
model_name='match',
20+
name='player2_rating_delta',
21+
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True),
22+
),
23+
]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 5.2.10 on 2026-02-07 14:36
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('games', '0036_match_player1_rating_delta_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='match',
15+
name='player1_rating_delta',
16+
field=models.IntegerField(blank=True, null=True),
17+
),
18+
migrations.AlterField(
19+
model_name='match',
20+
name='player2_rating_delta',
21+
field=models.IntegerField(blank=True, null=True),
22+
),
23+
]

othello/apps/games/models.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ class Match(models.Model):
143143
player1_wins = models.IntegerField(default=0)
144144
player2_wins = models.IntegerField(default=0)
145145
ties = models.IntegerField(default=0)
146+
player1_rating_delta = models.IntegerField(null=True, blank=True)
147+
player2_rating_delta = models.IntegerField(null=True, blank=True)
146148

147149
@property
148150
def channels_group_name(self) -> str:
@@ -212,6 +214,9 @@ def calculate_results(self) -> None:
212214
ties=ties,
213215
)
214216

217+
self.player1_rating_delta = int(change1)
218+
self.player2_rating_delta = int(change2)
219+
215220
user1.rating = rating1 + change1
216221
user2.rating = rating2 + change2
217222

@@ -232,6 +237,22 @@ def calculate_results(self) -> None:
232237
task_logger.info(f"User {user1} new rating: {user1.rating}")
233238
task_logger.info(f"User {user2} new rating: {user2.rating}")
234239

240+
self.save(
241+
update_fields=[
242+
"player1_rating_delta",
243+
"player2_rating_delta",
244+
]
245+
)
246+
else:
247+
self.player1_rating_delta = None
248+
self.player2_rating_delta = None
249+
self.save(
250+
update_fields=[
251+
"player1_rating_delta",
252+
"player2_rating_delta",
253+
]
254+
)
255+
235256
def __str__(self) -> str:
236257
return f"{self.player1.get_game_name()} vs {self.player2.get_game_name()} ({self.num_games} games)"
237258

othello/apps/games/views.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from django.db import models
88
from django.http import FileResponse, HttpRequest, HttpResponse, JsonResponse
99
from django.shortcuts import get_object_or_404, redirect, render
10-
from django.utils import timezone
10+
from django.utils import formats, timezone
1111

1212
from .forms import DownloadSubmissionForm, GameForm, MatchForm, SubmissionForm
1313
from .models import Game, Match, Submission
@@ -189,15 +189,25 @@ def queue_json(request: HttpRequest) -> HttpResponse:
189189
matches_data.append(
190190
{
191191
"id": match.id,
192-
"player1_name": match.player1.get_game_name(),
193-
"player2_name": match.player2.get_game_name(),
194-
"score": f"{match.player1_wins}-{match.ties}-{match.player2_wins}"
192+
"player1_name": match.player1.user.username,
193+
"player2_name": match.player2.user.username,
194+
"score": f"{match.player1_wins} - {match.ties} - {match.player2_wins}"
195195
if match.status == "completed"
196196
else "-",
197197
"is_ranked": "Yes" if match.is_ranked else "No",
198198
"status": match.status,
199-
"created_at": match.created_at.isoformat(),
199+
"status_display": match.get_status_display(),
200+
"created_at": formats.date_format(
201+
timezone.localtime(match.created_at),
202+
"DATETIME_FORMAT",
203+
),
200204
"can_view_replay": request.user in [match.player1.user, match.player2.user],
205+
"player1_rating_delta": match.player1_rating_delta
206+
if match.player1_rating_delta
207+
else None,
208+
"player2_rating_delta": match.player2_rating_delta
209+
if match.player2_rating_delta
210+
else None,
201211
}
202212
)
203213

@@ -211,6 +221,7 @@ def queue_json(request: HttpRequest) -> HttpResponse:
211221
)
212222

213223

224+
@login_required
214225
def queue(request: HttpRequest) -> HttpResponse:
215226
matches = Match.objects.all().order_by("-created_at")
216227
my_matches_only = request.GET.get("my_matches") == "1"

othello/settings/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,6 @@
245245
integrations=[DjangoIntegration(), CeleryIntegration()],
246246
send_default_pii=True,
247247
)
248+
249+
250+
DATETIME_FORMAT = "F d, Y, h:i a"

othello/static/css/base.css

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
@charset "UTF-8";
22

3-
@import url('https://fonts.googleapis.com/css?family=Roboto+Mono');
3+
@import url('https://fonts.googleapis.com/css2?family=Inter');
44

55
body {
6-
font-family: 'Roboto Mono', monospace;
6+
font-family: 'Inter', sans-serif;
77
}
88

99
html, body {
@@ -102,19 +102,19 @@ html, body {
102102

103103

104104
pre, code {
105-
font-family: 'Roboto Mono', monospace;
105+
font-family: 'Inter', sans-serif;
106106
font-size: 16px;
107107
color: #805229;
108108
}
109109

110110
h1,h2,h3,h4,h5,h6 {
111-
font-family: 'Roboto Mono', monospace;
111+
font-family: 'Inter', sans-serif;
112112
display: block;
113113
font-weight: bold;
114114
}
115115

116116
input, button{
117-
font-family: 'Roboto Mono', monospace;
117+
font-family: 'Inter', sans-serif;
118118
font-size: 16px;
119119
color: #805229;
120120
border: #a06633 2px solid;
@@ -164,4 +164,53 @@ input, button{
164164
.status-btn:focus {
165165
outline: none !important;
166166
box-shadow: none !important;
167+
}
168+
169+
.score-column {
170+
white-space: nowrap;
171+
}
172+
173+
.result-circle {
174+
display: inline-flex;
175+
align-items: center;
176+
justify-content: center;
177+
border-radius: 50%;
178+
width: 32px;
179+
height: 32px;
180+
margin: 0 4px;
181+
flex-shrink: 0;
182+
}
183+
184+
.result-circle.result-win {
185+
background-color: #bbf7d0;
186+
}
187+
188+
.result-circle.result-loss {
189+
background-color: #fecaca;
190+
}
191+
192+
.result-circle.result-tie {
193+
background-color: #e5e7eb;
194+
}
195+
196+
.score {
197+
display: inline-block;
198+
}
199+
200+
.rating-delta {
201+
font-size: 0.75rem;
202+
}
203+
204+
.rating-delta.delta-win {
205+
color: #16a34a;
206+
font-weight: 600;
207+
}
208+
209+
.rating-delta.delta-loss {
210+
color: #dc2626;
211+
font-weight: 600;
212+
}
213+
214+
.rating-delta.delta-tie {
215+
color: #6b7280;
167216
}

othello/static/css/games/design.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.selectize-input {
2-
font-family: 'Roboto Mono', monospace;
2+
font-family: 'Inter', sans-serif;
33
font-size: 16px;
44
background-color: transparent;
55
color: #805229;

othello/static/css/tournaments/create.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
.selectize-input {
66
margin-left: 10px;
7-
font-family: 'Roboto Mono', monospace;
7+
font-family: 'Inter', sans-serif;
88
font-size: 16px;
99
background-color: transparent;
1010
color: #805229;

0 commit comments

Comments
 (0)