Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add all proper icons #78

Merged
merged 6 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions 502.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>502 bad gateway - DMOJ</title>
<title>502 bad gateway - WLMOJ</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css">
<style>
hr {
margin: 0 22em;
}
Expand Down Expand Up @@ -49,9 +49,9 @@
<br>
<div class="popup">
<div>
<img class="logo" src="/logo.png" alt="DMOJ">
<img class="logo" src="/logo.png" alt="WLMOJ">
</div>
<h1 style="width: 100%;">Oops, the DMOJ is down.</h1>
<h1 style="width: 100%;">Oops, the WLMOJ is down.</h1>
</div>
<br>
<hr>
Expand Down
13 changes: 4 additions & 9 deletions dmoj/urls.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import os
from os.path import join

from django.conf import settings
from django.contrib import admin
from django.contrib.auth import views as auth_views
Expand Down Expand Up @@ -368,15 +371,7 @@ def paged_list_view(view, name):
])),
]

favicon_paths = ['apple-touch-icon-180x180.png', 'apple-touch-icon-114x114.png', 'android-chrome-72x72.png',
'apple-touch-icon-57x57.png', 'apple-touch-icon-72x72.png', 'apple-touch-icon.png', 'mstile-70x70.png',
'android-chrome-36x36.png', 'apple-touch-icon-precomposed.png', 'apple-touch-icon-76x76.png',
'apple-touch-icon-60x60.png', 'android-chrome-96x96.png', 'mstile-144x144.png', 'mstile-150x150.png',
'safari-pinned-tab.svg', 'android-chrome-144x144.png', 'apple-touch-icon-152x152.png',
'favicon-96x96.png',
'favicon-32x32.png', 'favicon-16x16.png', 'android-chrome-192x192.png', 'android-chrome-48x48.png',
'mstile-310x150.png', 'apple-touch-icon-144x144.png', 'browserconfig.xml', 'manifest.json',
'apple-touch-icon-120x120.png', 'mstile-310x310.png']
favicon_paths = os.listdir(join(settings.DMOJ_RESOURCES, 'icons'))

static_lazy = lazy(static, str)
for favicon in favicon_paths:
Expand Down
2 changes: 2 additions & 0 deletions judge/contest_format/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from judge.contest_format.atcoder import AtCoderContestFormat
from judge.contest_format.bonuses import BonusesContestFormat
from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.ecoo import ECOOContestFormat
from judge.contest_format.icpc import ICPCContestFormat
from judge.contest_format.ics3u import ICS3UContestFormat
from judge.contest_format.ioi import IOIContestFormat
from judge.contest_format.legacy_ioi import LegacyIOIContestFormat
from judge.contest_format.registry import choices, formats
144 changes: 144 additions & 0 deletions judge/contest_format/bonuses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from datetime import timedelta

from django.core.exceptions import ValidationError
from django.db.models import (
ExpressionWrapper,
F,
FloatField,
Max,
Min,
OuterRef,
Subquery,
)
from django.template.defaultfilters import floatformat
from django.urls import reverse
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy

from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
from judge.utils.timedelta import nice_repr


@register_contest_format('bonuses')
class BonusesContestFormat(DefaultContestFormat):
name = gettext_lazy('Bonuses')
config_defaults = {
'time_bonus': 0,
'first_submission_bonus': 0,
}
"""
time_bonus: Number of minutes to award an extra point for submitting before the contest end.
first_submission_bonus: Bonus points for fully solving on first submission.
"""

@classmethod
def validate(cls, config):
if not isinstance(config, dict):
raise ValidationError('bonuses contest expects a dict as config')
for key in config.keys():
if key not in cls.config_defaults:
raise ValidationError('unknown config key "%s"' % key)

def __init__(self, contest, config):
super().__init__(contest, self.config_defaults.copy())
self.config.update(config)

def update_participation(self, participation):
cumtime = 0
score = 0
format_data = {}

total_wrapper = ExpressionWrapper(
F('points') + F('bonus'), output_field=FloatField(),
)
queryset = (
participation.submissions.values('problem_id')
.annotate(total=total_wrapper)
.filter(
total=Subquery(
participation.submissions.filter(problem_id=OuterRef('problem_id'))
.annotate(best=total_wrapper)
.order_by('-best')
.values('best')[:1],
),
)
.annotate(time=Min('submission__date'), points=Max('points'))
.values_list('problem_id', 'time', 'points', 'total')
)

for problem_id, time, points, total in queryset:
dt = (time - participation.start).total_seconds()
if total:
score += total
cumtime += dt
format_data[str(problem_id)] = {
'points': points,
'bonus': total - points,
'time': dt,
}

queryset = (
participation.submissions.values('problem_id', 'problem__points')
.filter(
submission__date=Subquery(
participation.submissions.filter(problem_id=OuterRef('problem_id'))
.order_by('submission__date')
.values('submission__date')[:1],
),
)
.annotate(points=Max('points'))
.values_list('problem_id', 'points', 'problem__points')
)

for problem_id, points, problem_points in queryset:
format_data[str(problem_id)].update(
{
'first_solve': points == problem_points,
},
)

participation.cumtime = max(cumtime, 0)
participation.score = score
participation.tiebreaker = 0
participation.format_data = format_data
participation.save()

def display_user_problem(self, participation, contest_problem):
format_data = (participation.format_data or {}).get(str(contest_problem.id))
if format_data:
pretest = (
'pretest-'
if self.contest.run_pretests_only and contest_problem.is_pretested
else ''
)
first_solve = ' first-solve' if format_data['first_solve'] else ''
bonus = (
format_html(
'<font style="font-size:10px;"> +{bonus}</font>',
bonus=floatformat(format_data['bonus']),
)
if format_data['bonus']
else ''
)

return format_html(
'<td class="{state}"><a href="{url}">{points}{bonus}<div class="solving-time">{time}</div></a></td>',
state=pretest + self.best_solution_state(
format_data['points'], contest_problem.points,
) + first_solve,
url=reverse(
'contest_user_submissions',
args=[
self.contest.key,
participation.user.user.username,
contest_problem.problem.code,
],
),
points=floatformat(format_data['points']),
bonus=bonus,
time=nice_repr(timedelta(seconds=format_data['time']), 'noday'),
)
else:
return mark_safe('<td></td>')
89 changes: 89 additions & 0 deletions judge/contest_format/ics3u.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from django.core.exceptions import ValidationError
from django.db.models import Max, OuterRef, Subquery
from django.template.defaultfilters import floatformat
from django.urls import reverse
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy

from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format


@register_contest_format('ics3u')
class ICS3UContestFormat(DefaultContestFormat):
name = gettext_lazy('ICS3U')

@classmethod
def validate(cls, config):
if config is not None and (not isinstance(config, dict) or config):
raise ValidationError(
'ICS3U contest expects no config or empty dict as config',
)

def __init__(self, contest, config):
super().__init__(contest, config)

def update_participation(self, participation):
score = 0
format_data = {}

queryset = (
participation.submissions.values('problem_id')
.filter(
points=Subquery(
participation.submissions.filter(problem_id=OuterRef('problem_id'))
.order_by('-points')
.values('points')[:1],
),
)
.annotate(disqualified=Max('is_disqualified'))
.values_list('problem_id', 'disqualified', 'points')
)

for problem_id, disqualified, points in queryset:
format_data[str(problem_id)] = {
'points': points,
'disqualified': disqualified,
}
score += points

participation.cumtime = 0
participation.score = score
participation.tiebreaker = 0
participation.format_data = format_data
participation.save()

def display_user_problem(self, participation, contest_problem):
format_data = (participation.format_data or {}).get(str(contest_problem.id))
if format_data:
pretest = (
'pretest-'
if self.contest.run_pretests_only and contest_problem.is_pretested
else ''
)
extra = ' disqualified' if format_data['disqualified'] else ''

return format_html(
'<td class="{state}"><a href="{url}">{points}</a></td>',
state=pretest + self.best_solution_state(
format_data['points'], contest_problem.points,
) + extra,
url=reverse(
'contest_user_submissions',
args=[
self.contest.key,
participation.user.user.username,
contest_problem.problem.code,
],
),
points=floatformat(format_data['points']),
)
else:
return mark_safe('<td></td>')

def display_participation_result(self, participation):
return format_html(
'<td class="user-points">{points}</td>',
points=floatformat(participation.score, -self.contest.points_precision),
)
Loading
Loading