[^<]*(?]*>([^<]+)
', page)
+ if not match:
+ continue
+ title = match.group(1).strip()
+
+ if string_iou(slug(title), slug(self.name)) > 0.95:
+ return url
+
+ raise ExceptionParseStandings('No standings url, not found title matching')
+
def get_standings(self, users=None, statistics=None, **kwargs):
if not self.standings_url:
- raise ExceptionParseStandings('No standings url')
+ self.standings_url = self._detect_standings()
season = self.info.get('parse', {}).get('season')
season_ratings = {}
@@ -279,6 +309,7 @@ def process_submission_page(page):
pass
standings = {
+ 'url': self.standings_url,
'result': result,
'problems': problems_infos,
'hidden_fields': ['total_rating', 'original_handle', 'affiliation', 'rating', 'standings_rating',
diff --git a/src/ranking/management/modules/usaco.py b/src/ranking/management/modules/usaco.py
index 9216413e..5866c012 100644
--- a/src/ranking/management/modules/usaco.py
+++ b/src/ranking/management/modules/usaco.py
@@ -1,24 +1,40 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+import os
import re
import urllib.parse
from collections import OrderedDict
from copy import deepcopy
-from datetime import datetime
-from pprint import pprint
from ranking.management.modules.common import REQ, BaseModule, parsed_table
from ranking.management.modules.excepts import InitModuleException
+def get_curl_args():
+ if not hasattr('get_curl_args', '_curl_args'):
+ curl_args_filepath = 'sharedfiles/resource/usaco/curl.args'
+ if os.path.exists(curl_args_filepath):
+ with open(curl_args_filepath) as file:
+ get_curl_args._curl_args = file.read().strip()
+ else:
+ get_curl_args._curl_args = None
+ return get_curl_args._curl_args
+
+
+def req_get(*args, **kwargs):
+ kwargs['with_curl'] = True
+ kwargs['curl_args'] = get_curl_args()
+ return REQ.get(*args, **kwargs)
+
+
class Statistic(BaseModule):
def __init__(self, **kwargs):
super(Statistic, self).__init__(**kwargs)
if not self.standings_url:
url = 'http://usaco.org/index.php?page=contests'
- page = REQ.get(url)
+ page = req_get(url)
matches = re.finditer(']*href="(?P]*>.*?
)', page, re.DOTALL)
for table_match in tables:
diff --git a/src/ranking/migrations/0136_rating_update_time_field.py b/src/ranking/migrations/0136_rating_update_time_field.py
new file mode 100644
index 00000000..95709116
--- /dev/null
+++ b/src/ranking/migrations/0136_rating_update_time_field.py
@@ -0,0 +1,34 @@
+# Generated by Django 5.1.4 on 2024-12-25 22:40
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('ranking', '0136_statistics_penalty_and_more'), ('ranking', '0137_account_rating_update_time')]
+
+ dependencies = [
+ ('clist', '0166_contest_promotion'),
+ ('ranking', '0135_alter_parsestatistics_contest'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='statistics',
+ name='penalty',
+ field=models.FloatField(blank=True, default=None, null=True),
+ ),
+ migrations.AddIndex(
+ model_name='statistics',
+ index=models.Index(fields=['place_as_int', '-solving', 'penalty'], name='ranking_sta_place_a_280c4a_idx'),
+ ),
+ migrations.AddIndex(
+ model_name='statistics',
+ index=models.Index(fields=['contest', 'place_as_int', '-solving', 'penalty', 'id'], name='ranking_sta_contest_5962eb_idx'),
+ ),
+ migrations.AddField(
+ model_name='account',
+ name='rating_update_time',
+ field=models.DateTimeField(blank=True, default=None, null=True),
+ ),
+ ]
diff --git a/src/ranking/models.py b/src/ranking/models.py
index ca8bbc05..d5e0f067 100644
--- a/src/ranking/models.py
+++ b/src/ranking/models.py
@@ -10,7 +10,7 @@
from django.contrib.contenttypes.models import ContentType
from django.core.management import call_command
from django.db import models
-from django.db.models import F, OuterRef, Q, Sum
+from django.db.models import F, OuterRef, Prefetch, Q, Sum
from django.db.models.functions import Coalesce, Upper
from django.db.models.signals import m2m_changed, post_delete, post_save, pre_save
from django.dispatch import receiver
@@ -50,6 +50,7 @@ class Account(BaseModel):
last_rating_activity = models.DateTimeField(default=None, null=True, blank=True, db_index=True)
rating = models.IntegerField(default=None, null=True, blank=True, db_index=True)
rating50 = models.SmallIntegerField(default=None, null=True, blank=True, db_index=True)
+ rating_update_time = models.DateTimeField(default=None, null=True, blank=True)
resource_rank = models.IntegerField(null=True, blank=True, default=None, db_index=True)
info = models.JSONField(default=dict, blank=True)
updated = models.DateTimeField(auto_now_add=True)
@@ -436,6 +437,7 @@ class Statistics(BaseModel):
place_as_int = models.IntegerField(default=None, null=True, blank=True)
solving = models.FloatField(default=0, blank=True)
upsolving = models.FloatField(default=0, blank=True)
+ penalty = models.FloatField(default=None, null=True, blank=True)
addition = models.JSONField(default=dict, blank=True)
url = models.TextField(null=True, blank=True)
new_global_rating = models.IntegerField(null=True, blank=True, default=None, db_index=True)
@@ -498,8 +500,10 @@ class Meta:
indexes = [
models.Index(fields=['place_as_int', 'created']),
models.Index(fields=['place_as_int', '-solving']),
+ models.Index(fields=['place_as_int', '-solving', 'penalty']),
models.Index(fields=['place_as_int', '-created']),
models.Index(fields=['contest', 'place_as_int', '-solving', 'id']),
+ models.Index(fields=['contest', 'place_as_int', '-solving', 'penalty', 'id']),
models.Index(fields=['contest', 'account']),
models.Index(fields=['contest', 'advanced', 'place_as_int']),
models.Index(fields=['contest', 'account', 'advanced', 'place_as_int']),
@@ -581,9 +585,12 @@ class Meta:
indexes = [models.Index(fields=['coder', 'content_type', 'object_id'])]
@classmethod
- def filter_by_content_type(cls, model_class):
+ def filter_by_content_type(cls, model_class, prefetch=True):
content_type = ContentType.objects.get_for_model(model_class)
- return cls.objects.filter(content_type=content_type)
+ qs = cls.objects.filter(content_type=content_type)
+ if prefetch:
+ qs = qs.prefetch_related(Prefetch('entity', queryset=model_class.objects.all()))
+ return qs
@staticmethod
def contests_filter(coder):
diff --git a/src/ranking/views.py b/src/ranking/views.py
index 7ce40ecb..234e4c00 100644
--- a/src/ranking/views.py
+++ b/src/ranking/views.py
@@ -12,7 +12,7 @@
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.db import models
-from django.db.models import Avg, Case, Count, Exists, F, OuterRef, Prefetch, Q, Value, When
+from django.db.models import Avg, Case, Count, Exists, F, OuterRef, Prefetch, Q, Subquery, Value, When
from django.db.models.expressions import RawSQL
from django.db.models.functions import Cast, window
from django.http import HttpRequest, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound, JsonResponse
@@ -41,7 +41,7 @@
from ranking.management.modules.excepts import ExceptionParseStandings
from ranking.models import Account, AccountRenaming, Module, Stage, Statistics, VirtualStart
from tg.models import Chat
-from true_coders.models import Coder, CoderList, Party
+from true_coders.models import Coder, CoderList, ListGroup, Party
from true_coders.views import get_ratings_data
from utils.chart import make_bins, make_histogram
from utils.colors import get_n_colors
@@ -712,6 +712,8 @@ def timeline_format(t):
def render_standings_paging(contest, statistics, with_detail=True):
+ contest_fields = contest.info.get('fields', [])
+
n_total = None
if isinstance(statistics, list):
per_page = contest.standings_per_page
@@ -720,13 +722,18 @@ def render_standings_paging(contest, statistics, with_detail=True):
statistics = statistics[:per_page]
statistics = Statistics.objects.filter(pk__in=statistics)
- order = contest.get_statistics_order() + ['pk']
+ order = contest.get_statistics_order()
statistics = statistics.order_by(*order)
+ inplace_division = '_division_addition' in contest_fields
divisions_order = get_standings_divisions_order(contest)
division = divisions_order[0] if divisions_order else None
if division:
- statistics = statistics.filter(addition__division=division)
+ if inplace_division:
+ field = f'addition___division_addition__{division}'
+ statistics = statistics.filter(**{f'{field}__isnull': False})
+ else:
+ statistics = statistics.filter(addition__division=division)
problems = get_standings_problems(contest, division)
@@ -737,7 +744,6 @@ def render_standings_paging(contest, statistics, with_detail=True):
mod_penalty = get_standings_mod_penalty(contest, division, problems, statistics)
colored_by_group_score = contest.info.get('standings', {}).get('colored_by_group_score')
- contest_fields = contest.info.get('fields', [])
has_country = (
'country' in contest_fields or
'_countries' in contest_fields or
@@ -857,7 +863,7 @@ def get_standings_fields(contest, division, with_detail, hidden_fields=None, hid
fixed_fields = (
'penalty',
('total_time', 'Time'),
- ('advanced', 'Advance'),
+ ('advanced', 'Adv'),
)
fixed_fields += tuple(options.get('fixed_fields', []))
if not with_detail:
@@ -983,14 +989,17 @@ def standings(request, contest, other_contests=None, template='standings.html',
with_detail = is_optional_yes(request.GET.get('detail'))
with_solution = is_optional_yes(request.GET.get('solution'))
+ with_autoreload = is_optional_yes(request.GET.get('autoreload'))
if request.user.is_authenticated:
coder = request.user.coder
with_detail = coder.update_or_get_setting('standings_with_detail', with_detail)
with_solution = coder.update_or_get_setting('standings_with_solution', with_solution)
+ with_autoreload = coder.update_or_get_setting('standings_with_autoreload', with_autoreload)
else:
coder = None
- with_detail = with_detail if with_detail is not None else settings.STANDINGS_WITH_DETAIL_DEFAULT
- with_solution = with_solution if with_solution is not None else settings.STANDINGS_WITH_SOLUTION_DEFAULT
+ with_detail = with_detail if with_detail is not None else settings.STANDINGS_WITH_DETAIL_DEFAULT
+ with_solution = with_solution if with_solution is not None else settings.STANDINGS_WITH_SOLUTION_DEFAULT
+ with_autoreload = with_autoreload if with_autoreload is not None else settings.STANDINGS_WITH_AUTORELOAD_DEFAULT
with_row_num = False
@@ -1102,8 +1111,9 @@ def standings(request, contest, other_contests=None, template='standings.html',
fields[v] = v
hidden_fields.append(v)
- if (n_advanced := request.GET.get('n_advanced')) and n_advanced.isdigit() and 'n_highlight' in options:
- options['n_highlight'] = int(n_advanced)
+ if n_advanced := request.GET.get('n_advanced'):
+ if n_advanced.isdigit() and int(n_advanced) and 'n_highlight' in options:
+ options['n_highlight'] = int(n_advanced)
n_highlight_context = _standings_highlight(contest, statistics, options) if not contests_ids else {}
# field to select
@@ -1379,6 +1389,11 @@ def add_field_to_select(f):
# subquery = Chat.objects.filter(coder=OuterRef('account__coders'), is_group=False).values('name')[:1]
# statistics = statistics.annotate(chat_name=Subquery(subquery))
elif field == 'list':
+ if values:
+ groups = ListGroup.objects.filter(coder_list__uuid__in=values, name__isnull=False)
+ groups = groups.filter(Q(values__account=OuterRef('account')) |
+ Q(values__coder__account=OuterRef('account')))
+ statistics = statistics.annotate(value_instead_key=Subquery(groups.values('name')[:1]))
coders, accounts = CoderList.coders_and_accounts_ids(uuids=values, coder=coder)
filt |= Q(account__coders__in=coders) | Q(account__in=accounts)
else:
@@ -1576,6 +1591,11 @@ def add_field_to_select(f):
):
context['my_statistics_rev'] = True
+ # field_instead_key
+ if field_instead_key := request.GET.get('field_instead_key'):
+ if field_instead_key in contest_fields:
+ context['field_instead_key'] = f'addition__{field_instead_key}'
+
relative_problem_time = contest.resource.info.get('standings', {}).get('relative_problem_time')
relative_problem_time = contest.info.get('standings', {}).get('relative_problem_time', relative_problem_time)
context['relative_problem_time'] = relative_problem_time
@@ -1641,6 +1661,7 @@ def add_field_to_select(f):
'truncatechars_name_problem': 10 * (2 if merge_problems else 1),
'with_detail': with_detail,
'with_solution': with_solution,
+ 'with_autoreload': with_autoreload,
'groupby': groupby,
'pie_limit_rows_groupby': 50,
'labels_groupby': labels_groupby,
@@ -1709,7 +1730,7 @@ def add_field_to_select(f):
return render(request, template, context)
-@ratelimit(key='user', rate='1000/h', block=True)
+@ratelimit(key='user', rate='20/m', block=True)
def solutions(request, sid, problem_key):
is_modal = request.is_ajax()
if not request.user.is_authenticated:
diff --git a/src/static/css/base.css b/src/static/css/base.css
index f32b7d69..00d53db1 100644
--- a/src/static/css/base.css
+++ b/src/static/css/base.css
@@ -88,7 +88,6 @@ input[type="search"]::-webkit-search-cancel-button {
object-fit: cover;
border-radius: 50%;
vertical-align: top;
- margin-right: 5px;
}
.avatar-width-fixed {
@@ -97,7 +96,6 @@ input[type="search"]::-webkit-search-cancel-button {
display: inline-block;
text-align: center;
vertical-align: top;
- margin-right: 5px;
}
/* Space out content a bit */
@@ -837,6 +835,10 @@ a[disabled] {
padding: 0px;
}
+#filter-collapse .form-group {
+ margin-bottom: 0px;
+}
+
#filter-collapse .input-group {
display: inline-table;
vertical-align: middle;
@@ -848,6 +850,7 @@ a[disabled] {
}
#filter-toggle {
+ position: relative;
margin-bottom: 5px;
font-size: 10px;
line-height: 1.0;
@@ -994,6 +997,10 @@ a[data-toggle="tooltip"][disabled],
* Table inner scroll
*/
+#table-inner-scroll.firefox table tr.starred td.sticky-column {
+ z-index: 21;
+}
+
#table-inner-scroll table thead tr,
#table-inner-scroll:not(.firefox) table tr.starred,
#table-inner-scroll.firefox table tr.starred td /* https://bugzilla.mozilla.org/show_bug.cgi?id=1745323 */
@@ -1048,3 +1055,39 @@ table.table-border-collapse-separate {
.field-to-input {
max-width: 100px;
}
+
+
+/*
+ * Countdown
+ */
+
+.countdown {
+ white-space: nowrap !important;
+}
+
+
+/*
+ * toastify notifications
+ */
+
+.toastify-bootstrap {
+ border-radius: 3px 3px 0px 0px !important;
+ background-image: initial !important;
+ margin: 0px !important;
+ padding: 10px 15px !important;
+}
+
+.alert-undefined {
+ background-color: #f0f0f0 !important;
+ border-color: #ccc !important;
+ color: #333 !important;
+}
+
+.progress-bar-undefined {
+ background-color: #333 !important;
+}
+
+@keyframes progress-animation {
+ from { width: 100% }
+ to { width: 0% }
+}
diff --git a/src/static/css/toastify.min.css b/src/static/css/toastify.min.css
new file mode 100644
index 00000000..01174dcf
--- /dev/null
+++ b/src/static/css/toastify.min.css
@@ -0,0 +1,15 @@
+/**
+ * Minified by jsDelivr using clean-css v5.3.2.
+ * Original file: /npm/toastify-js@1.12.0/src/toastify.css
+ *
+ * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
+ */
+/*!
+ * Toastify js 1.12.0
+ * https://github.com/apvarun/toastify-js
+ * @license MIT licensed
+ *
+ * Copyright (C) 2018 Varun A P
+ */
+.toastify{padding:12px 20px;color:#fff;display:inline-block;box-shadow:0 3px 6px -1px rgba(0,0,0,.12),0 10px 36px -4px rgba(77,96,232,.3);background:-webkit-linear-gradient(315deg,#73a5ff,#5477f5);background:linear-gradient(135deg,#73a5ff,#5477f5);position:fixed;opacity:0;transition:all .4s cubic-bezier(.215, .61, .355, 1);border-radius:2px;cursor:pointer;text-decoration:none;max-width:calc(50% - 20px);z-index:2147483647}.toastify.on{opacity:1}.toast-close{background:0 0;border:0;color:#fff;cursor:pointer;font-family:inherit;font-size:1em;opacity:.4;padding:0 5px}.toastify-right{right:15px}.toastify-left{left:15px}.toastify-top{top:-150px}.toastify-bottom{bottom:-150px}.toastify-rounded{border-radius:25px}.toastify-avatar{width:1.5em;height:1.5em;margin:-7px 5px;border-radius:2px}.toastify-center{margin-left:auto;margin-right:auto;left:0;right:0;max-width:fit-content;max-width:-moz-fit-content}@media only screen and (max-width:360px){.toastify-left,.toastify-right{margin-left:auto;margin-right:auto;left:0;right:0;max-width:fit-content}}
+/*# sourceMappingURL=/sm/cb4335d1b03e933ed85cb59fffa60cf51f07567ed09831438c60f59afd166464.map */
\ No newline at end of file
diff --git a/src/static/flags/flags.css b/src/static/flags/flags.css
index b48e2b29..56a0f70b 100644
--- a/src/static/flags/flags.css
+++ b/src/static/flags/flags.css
@@ -4,6 +4,7 @@
display: inline-block;
text-align: center;
vertical-align: top;
+ margin-right: 7px;
}
.select2-container div.flag {
@@ -21,7 +22,8 @@
filter: drop-shadow(0px 0px 1px rgb(0 0 0 / 0.5)) opacity(80%);
background-image: url('../flags/4x3/xx.svg');
transform: scale(1.3);
- margin-right: 5px;
+ margin-left: 5px;
+ margin-right: 4px;
}
.flag:before {
diff --git a/src/static/js/accounts.js b/src/static/js/accounts.js
index 28da929f..a9a8584b 100644
--- a/src/static/js/accounts.js
+++ b/src/static/js/accounts.js
@@ -17,7 +17,7 @@ function init_account_buttons() {
$btn.parent().children().toggleClass('hidden')
$btn.toggleClass('hidden')
$btn.closest('tr').toggleClass('info')
- $.notify($btn.attr('data-message'), 'success')
+ notify($btn.attr('data-message'), 'success')
},
error: function(response) {
if (response.responseJSON && response.responseJSON.message == 'redirect') {
@@ -41,7 +41,7 @@ function init_clickable_has_coders() {
})
}
-function invert_linked_coder_accounts(e) {
+function invert_accounts(e, s) {
e.preventDefault()
- $('#accounts input[name="accounts"]').click()
+ $('#accounts input[name="' + $.escapeSelector(s) + '"]').click()
}
diff --git a/src/static/js/base.js b/src/static/js/base.js
index 482f9ad7..5da00be9 100644
--- a/src/static/js/base.js
+++ b/src/static/js/base.js
@@ -157,7 +157,7 @@ function inline_button() {
action: 'reset_contest_statistic_timing', cid: btn.attr('data-contest-id')
}).done(function(data) {
btn.attr('data-original-title', data.message).tooltip('show')
- $.notify(data.message, data.status)
+ notify(data.message, data.status)
}).fail(log_ajax_error_callback)
})
@@ -225,7 +225,7 @@ function log_ajax_error(response, element = null) {
element.text(message)
element.removeClass('hidden')
} else {
- $.notify(message, 'error')
+ notify(message, 'error')
}
$('.bootbox').effect('shake')
}
@@ -297,7 +297,7 @@ function copyElementToClipboard(event, element) {
copyTextToClipboard(text)
el.attr('title', 'copied')
el.tooltip('show')
- $.notify('Copied "' + text + '" to clipboard', 'success')
+ notify('Copied "' + text + '" to clipboard', 'success')
setTimeout(function() { el.attr('title', ''); el.tooltip('destroy'); }, 1000)
return false
}
@@ -888,3 +888,61 @@ function restarred() {
offset_height += el.height()
}).css('z-index', '')
}
+
+/*
+ * toastify notifications
+ */
+
+Toastify.defaults.style = {}
+Toastify.defaults.position = 'right'
+Toastify.defaults.gravity= 'bottom'
+Toastify.defaults.stopOnFocus = true
+Toastify.defaults.duration = 4000
+Toastify.defaults.escapeMarkup = true
+
+function notify(message, type = 'success', duration = Toastify.defaults.duration) {
+ var escapeHTML = Toastify.defaults.escapeMarkup
+ if (typeof type == 'object') {
+ var options = type
+ type = options.type ?? 'success'
+ duration = options.duration ?? duration
+ escapeHTML = options.escapeHTML ?? escapeHTML
+ }
+ type = {error: 'danger', warn: 'warning'}[type] || type
+ if (!['danger', 'warning', 'success', 'info'].includes(type)) {
+ type = 'undefined'
+ }
+
+ var toastify = Toastify({
+ text: message,
+ duration: duration,
+ escapeMarkup: escapeHTML,
+ className: `toastify-bootstrap alert alert-${type}`,
+ })
+ toastify.showToast()
+ const toastElement = $(toastify.toastElement)
+
+ const progressBar = $('
');
- }
- }
- value = name === blankFieldName ? '' : '=' + name;
- find(this.userContainer, "[data-notify-" + type + value + "]").html(d);
- }
- this.updateClasses();
- if (this.elem) {
- this.setElementPosition();
- } else {
- this.setGlobalPosition();
- }
- this.show(true);
- if (this.options.autoHide) {
- clearTimeout(this.autohideTimer);
- this.autohideTimer = setTimeout(this.show.bind(this, false), this.options.autoHideDelay);
- }
- };
-
- Notification.prototype.destroy = function() {
- return this.wrapper.remove();
- };
-
- $[pluginName] = function(elem, data, options) {
- if ((elem && elem.nodeName) || elem.jquery) {
- $(elem)[pluginName](data, options);
- } else {
- options = data;
- data = elem;
- new Notification(null, data, options);
- }
- return elem;
- };
-
- $.fn[pluginName] = function(data, options) {
- $(this).each(function() {
- var inst;
- inst = getAnchorElement($(this)).data(pluginClassName);
- if (inst) {
- return inst.run(data, options);
- } else {
- return new Notification($(this), data, options);
- }
- });
- return this;
- };
-
- $.extend($[pluginName], {
- defaults: defaults,
- addStyle: addStyle,
- pluginOptions: pluginOptions,
- getStyle: getStyle,
- insertCSS: insertCSS
- });
-
- //always include the default bootstrap style
- addStyle("bootstrap", {
- html: "
-
{% if params.to_list %}
coder{% if perms.ranking.link_account %} {% icon_to 'invert' %}{% endif %}
coder{% if perms.ranking.link_account %} {% icon_to 'invert' %}{% endif %}
-
{% endif %}
to list
list {% icon_to 'invert' %}
@@ -71,7 +71,7 @@
{% if custom_fields %}
{% for field in custom_fields.values %}
- {% if field not in skip_actions_columns %}
+ {% if field not in skip_actions_columns and fields_types|get_item:field != 'str' %}
{% endif %}
" }}
- {% with rating_time=account.info|get_item:"_rating_time" %}
- {% if rating_time and account.rating_prediction.time and rating_time < account.rating_prediction.time or not rating_time and account.rating_prediction.time %}
+ {% if account.rating_update_time and account.rating_prediction.time and account.rating_update_time < account.rating_prediction.time or not account.rating_update_time and account.rating_prediction.time %}
{% endif %}
{% if account.rating is not None %}
@@ -113,7 +112,6 @@
{% else %}
—
{% endif %}
- {% endwith %}
{% if account.resource_rank %}{{ account.resource_rank }}{% else %}—{% endif %}
{{ account.n_contests }}
diff --git a/src/templates/base.html b/src/templates/base.html
index 6a73e7c8..0ecaa324 100644
--- a/src/templates/base.html
+++ b/src/templates/base.html
@@ -43,6 +43,9 @@
+
+
+
{% if user.is_authenticated and user.coder.settings.theme %}
@@ -63,9 +66,6 @@
-
-
-
diff --git a/src/templates/check_timezone.html b/src/templates/check_timezone.html
index fded30a1..cd7b96c4 100644
--- a/src/templates/check_timezone.html
+++ b/src/templates/check_timezone.html
@@ -11,9 +11,9 @@
if (data == "reload") {
location.reload()
} else if (data == "accepted") {
- $.notify("Warning! Timezone is set incorrectly. Please reload page.", "warn")
+ notify("Warning! Timezone is set incorrectly. Please reload page.", "warn")
} else {
- $.notify(data, "error")
+ notify(data, "error")
}
}
});
diff --git a/src/templates/coder_list.html b/src/templates/coder_list.html
index 6158ba2e..b73aeab1 100644
--- a/src/templates/coder_list.html
+++ b/src/templates/coder_list.html
@@ -3,12 +3,24 @@
{% block ogtitle %}{% block title %}{{ coder_list.name }} - List{% endblock %}{% endblock %}
{% block end-head %}
+
+
+
+
{% endblock %}
{% block content %}
+{% if coder_list.with_names %}
+
+{% endif %}
+
{{ coder_list.name }}
@@ -49,9 +61,12 @@
#
VS
+ {% if coder_list.with_names %}
+ Name
+ {% endif %}
Coder/Accounts
- ({{ coder_values|length }} of {{ coder_list_n_values_limit }})
+ ({{ coder_list_groups|length }} of {{ coder_list_n_values_limit }})
{% for resource in params.resources %}
@@ -63,38 +78,54 @@
- {% for group_id, data in coder_values.items %}
+ {% for group in coder_list_groups %}
+ {% with list_values=group.values %}
+ {% with has_list_values=list_values.count %}
+ {% endwith %}
+ {% endwith %}
{% endfor %}
diff --git a/src/templates/field_to_input.html b/src/templates/field_to_input.html
index 317eb3d6..af5b8af5 100644
--- a/src/templates/field_to_input.html
+++ b/src/templates/field_to_input.html
@@ -1,6 +1,8 @@
+{% if default %}
{% with capitalized_field=field|capitalize_field %}
{% with value=request.GET|get_item:field %}
-{% with collapse=value|iffalse %}
+{% with force_collapse=force_collapse|default:False %}
+{% with collapse=value|iffalse|ifor:force_collapse %}
{% if collapse %}
{{ forloop.counter }}
-
+ {% if has_list_values %}{% endif %}
+ {% if has_list_values %}
{% if request.user.is_authenticated %}
-
+
{% else %}
{% endif %}
+ {% endif %}
+
+ {% if coder_list.with_names %}
+
+
+ {% endif %}
- {% for v in data.list_values %}
+ {% for v in list_values.all %}
{% if forloop.counter0 %}|{% endif %}
{% if v.coder %}
- {% include "coder.html" with coder=v.coder with_fixed_width=True %}
+ {% include "coder.html" with coder=v.coder with_fixed_width=False %}
{% elif v.account %}
- {% include "account_table_cell.html" with resource=v.account.resource account=v.account with_resource=True with_fixed_width=True without_inline_button=True %}
+ {% include "account_table_cell.html" with resource=v.account.resource account=v.account with_resource=True with_fixed_width=False without_inline_button=True %}
{% else %}
—
{% endif %}
+
{% endfor %}
- {% if can_modify %}
- {% with v=data.list_values.0 %}
- {% endwith %}
- {% endif %}
{% elif statistics.exists %}
{% if not groupby or groupby == 'none' %}
- {% if contest.parsed_time %}
-