mirror of
https://github.com/DMOJ/online-judge.git
synced 2024-11-25 16:32:37 +08:00
Fix basic flake8 errors
This commit is contained in:
parent
4b07800b5d
commit
61daa227e2
9
.flake8
9
.flake8
@ -4,8 +4,15 @@ ignore =
|
||||
W504, # line break occurred after a binary operator
|
||||
per-file-ignores =
|
||||
# F401: unused imports, ignore in all __init__.py
|
||||
./*/__init__.py:F401
|
||||
# F403: import *
|
||||
./*/__init__.py:F401,F403
|
||||
# F405: name comes from import *
|
||||
./event_socket_server/__init__.py:F401,F403,F405
|
||||
./judge/management/commands/runmoss.py:F403,F405
|
||||
# E501: line too long, ignore in migrations
|
||||
./judge/migrations/*.py:E501
|
||||
# E303: too many blank lines
|
||||
# PyCharm likes to have double lines between class/def in an if statement.
|
||||
./judge/widgets/pagedown.py:E303
|
||||
exclude =
|
||||
./dmoj/local_settings.py, # belongs to the user
|
||||
|
@ -2,4 +2,4 @@
|
||||
Django-ace originally from https://github.com/bradleyayers/django-ace.
|
||||
"""
|
||||
|
||||
from .widgets import AceWidget
|
||||
from .widgets import AceWidget
|
||||
|
@ -10,7 +10,7 @@ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dmoj.settings')
|
||||
|
||||
app = Celery('dmoj')
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf import settings # noqa: E402, django must be imported here
|
||||
app.config_from_object(settings, namespace='CELERY')
|
||||
|
||||
if hasattr(settings, 'CELERY_BROKER_URL_SECRET'):
|
||||
|
@ -10,7 +10,6 @@ https://docs.djangoproject.com/en/1.11/ref/settings/
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
import os
|
||||
import re
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django_jinja.builtins import DEFAULT_EXTENSIONS
|
||||
|
22
dmoj/urls.py
22
dmoj/urls.py
@ -4,13 +4,16 @@ from django.contrib import admin
|
||||
from django.contrib.auth import views as auth_views
|
||||
from django.contrib.sitemaps.views import sitemap
|
||||
from django.http import Http404, HttpResponsePermanentRedirect
|
||||
from django.templatetags.static import static
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.functional import lazystr
|
||||
from django.views.generic import RedirectView
|
||||
|
||||
from judge.feed import CommentFeed, AtomCommentFeed, BlogFeed, AtomBlogFeed, ProblemFeed, AtomProblemFeed
|
||||
from judge.forms import CustomAuthenticationForm
|
||||
from judge.sitemap import ProblemSitemap, UserSitemap, HomePageSitemap, UrlSitemap, ContestSitemap, OrganizationSitemap, \
|
||||
BlogPostSitemap, SolutionSitemap
|
||||
from judge.sitemap import ProblemSitemap, UserSitemap, HomePageSitemap, UrlSitemap, ContestSitemap, \
|
||||
OrganizationSitemap, BlogPostSitemap, SolutionSitemap
|
||||
from judge.views import TitledTemplateView
|
||||
from judge.views import organization, language, status, blog, problem, mailgun, license, register, user, \
|
||||
submission, widgets, comment, contests, api, ranked_submission, stats, preview, ticket, totp, tasks, problem_manage
|
||||
@ -58,7 +61,7 @@ register_patterns = [
|
||||
url(r'^password/change/done/$', auth_views.PasswordChangeDoneView.as_view(
|
||||
template_name='registration/password_change_done.html',
|
||||
), name='password_change_done'),
|
||||
url(r'^password/reset/$',auth_views.PasswordResetView.as_view(
|
||||
url(r'^password/reset/$', auth_views.PasswordResetView.as_view(
|
||||
template_name='registration/password_reset.html',
|
||||
html_email_template_name='registration/password_reset_email.html',
|
||||
email_template_name='registration/password_reset_email.txt',
|
||||
@ -158,7 +161,7 @@ urlpatterns = [
|
||||
url(r'^users/', include([
|
||||
url(r'^$', user.users, name='user_list'),
|
||||
url(r'^(?P<page>\d+)$', lambda request, page:
|
||||
HttpResponsePermanentRedirect('%s?page=%s' % (reverse('user_list'), page))),
|
||||
HttpResponsePermanentRedirect('%s?page=%s' % (reverse('user_list'), page))),
|
||||
url(r'^find$', user.user_ranking_redirect, name='user_ranking_redirect'),
|
||||
])),
|
||||
|
||||
@ -171,7 +174,8 @@ urlpatterns = [
|
||||
url(r'/ajax$', user.UserPerformancePointsAjax.as_view(), name='user_pp_ajax'),
|
||||
])),
|
||||
url(r'^/submissions/', paged_list_view(submission.AllUserSubmissions, 'all_user_submissions_old')),
|
||||
url(r'^/submissions/', lambda _, user: HttpResponsePermanentRedirect(reverse('all_user_submissions', args=[user]))),
|
||||
url(r'^/submissions/', lambda _, user:
|
||||
HttpResponsePermanentRedirect(reverse('all_user_submissions', args=[user]))),
|
||||
|
||||
url(r'^/$', lambda _, user: HttpResponsePermanentRedirect(reverse('user_page', args=[user]))),
|
||||
])),
|
||||
@ -208,7 +212,8 @@ urlpatterns = [
|
||||
paged_list_view(submission.UserContestSubmissions, 'contest_user_submissions')),
|
||||
|
||||
url(r'^/participations$', contests.ContestParticipationList.as_view(), name='contest_participation_own'),
|
||||
url(r'^/participations/(?P<user>\w+)$', contests.ContestParticipationList.as_view(), name='contest_participation'),
|
||||
url(r'^/participations/(?P<user>\w+)$',
|
||||
contests.ContestParticipationList.as_view(), name='contest_participation'),
|
||||
|
||||
url(r'^/$', lambda _, contest: HttpResponsePermanentRedirect(reverse('contest_view', args=[contest]))),
|
||||
])),
|
||||
@ -359,11 +364,6 @@ favicon_paths = ['apple-touch-icon-180x180.png', 'apple-touch-icon-114x114.png',
|
||||
'mstile-310x150.png', 'apple-touch-icon-144x144.png', 'browserconfig.xml', 'manifest.json',
|
||||
'apple-touch-icon-120x120.png', 'mstile-310x310.png']
|
||||
|
||||
|
||||
from django.templatetags.static import static
|
||||
from django.utils.functional import lazystr
|
||||
from django.views.generic import RedirectView
|
||||
|
||||
for favicon in favicon_paths:
|
||||
urlpatterns.append(url(r'^%s$' % favicon, RedirectView.as_view(
|
||||
url=lazystr(lambda: static('icons/' + favicon))
|
||||
|
@ -2,10 +2,11 @@ import os
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dmoj.settings')
|
||||
|
||||
try:
|
||||
import MySQLdb
|
||||
import MySQLdb # noqa: F401, imported for side effect
|
||||
except ImportError:
|
||||
import pymysql
|
||||
|
||||
pymysql.install_as_MySQLdb()
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
from django.core.wsgi import get_wsgi_application # noqa: E402, django must be imported here
|
||||
application = get_wsgi_application()
|
||||
|
@ -1,11 +1,12 @@
|
||||
import os
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dmoj.settings')
|
||||
|
||||
import gevent.monkey
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dmoj.settings')
|
||||
gevent.monkey.patch_all()
|
||||
|
||||
try:
|
||||
import MySQLdb
|
||||
import MySQLdb # noqa: F401, imported for side effect
|
||||
except ImportError:
|
||||
import pymysql
|
||||
pymysql.install_as_MySQLdb()
|
||||
@ -20,5 +21,5 @@ else:
|
||||
partial(MySQLdb.connect, waiter=gevent_waiter)
|
||||
)
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
from django.core.wsgi import get_wsgi_application # noqa: E402, django must be imported here
|
||||
application = get_wsgi_application()
|
||||
|
@ -1,8 +1,8 @@
|
||||
try:
|
||||
import MySQLdb
|
||||
import MySQLdb # noqa: F401, imported for side effect
|
||||
except ImportError:
|
||||
import pymysql
|
||||
pymysql.install_as_MySQLdb()
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from dmoj.celery import app
|
||||
from dmoj.celery import app # noqa: F401, imported for side effect
|
||||
|
@ -3,7 +3,7 @@ import select
|
||||
__author__ = 'Quantum'
|
||||
engines = {}
|
||||
|
||||
from .select_server import SelectServer
|
||||
from .select_server import SelectServer # noqa: E402, import not at top for consistency
|
||||
engines['select'] = SelectServer
|
||||
|
||||
if hasattr(select, 'poll'):
|
||||
@ -14,4 +14,4 @@ if hasattr(select, 'epoll'):
|
||||
from .epoll_server import EpollServer
|
||||
engines['epoll'] = EpollServer
|
||||
|
||||
del select
|
||||
del select
|
||||
|
@ -3,7 +3,8 @@ __author__ = 'Quantum'
|
||||
|
||||
if not hasattr(select, 'epoll'):
|
||||
raise ImportError('System does not support epoll')
|
||||
from .poll_server import PollServer
|
||||
|
||||
from .poll_server import PollServer # noqa: E402, must be imported here
|
||||
|
||||
|
||||
class EpollServer(PollServer):
|
||||
|
@ -24,4 +24,4 @@ class Handler(object):
|
||||
|
||||
@property
|
||||
def socket(self):
|
||||
return self._socket
|
||||
return self._socket
|
||||
|
@ -106,7 +106,7 @@ class ProxyProtocolMixin(object):
|
||||
return self.close()
|
||||
|
||||
self.__type = self.__DATA
|
||||
super(ProxyProtocolMixin, self)._recv_data(data[index+2:])
|
||||
super(ProxyProtocolMixin, self)._recv_data(data[index + 2:])
|
||||
elif len(self.__buffer) > 107 or index > 105:
|
||||
self.close()
|
||||
|
||||
|
@ -89,5 +89,6 @@ def main():
|
||||
print('Done')
|
||||
s1.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -49,5 +49,6 @@ def main():
|
||||
server = TestServer(list(zip(args.host, args.port)), handler)
|
||||
server.serve_forever()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -95,7 +95,7 @@ class ContestForm(ModelForm):
|
||||
class Meta:
|
||||
widgets = {
|
||||
'organizers': HeavySelect2MultipleWidget(data_view='profile_select2'),
|
||||
'private_contestants': HeavySelect2MultipleWidget(data_view='profile_select2',
|
||||
'private_contestants': HeavySelect2MultipleWidget(data_view='profile_select2',
|
||||
attrs={'style': 'width: 100%'}),
|
||||
'organizations': HeavySelect2MultipleWidget(data_view='organization_select2'),
|
||||
'tags': Select2MultipleWidget,
|
||||
@ -108,7 +108,7 @@ class ContestForm(ModelForm):
|
||||
|
||||
class ContestAdmin(VersionAdmin):
|
||||
fieldsets = (
|
||||
(None, {'fields': ('key', 'name', 'organizers') }),
|
||||
(None, {'fields': ('key', 'name', 'organizers')}),
|
||||
(_('Settings'), {'fields': ('is_visible', 'use_clarifications', 'hide_problem_tags', 'hide_scoreboard',
|
||||
'run_pretests_only')}),
|
||||
(_('Scheduling'), {'fields': ('start_time', 'end_time', 'time_limit')}),
|
||||
@ -116,7 +116,7 @@ class ContestAdmin(VersionAdmin):
|
||||
(_('Format'), {'fields': ('format_name', 'format_config')}),
|
||||
(_('Rating'), {'fields': ('is_rated', 'rate_all', 'rating_floor', 'rating_ceiling', 'rate_exclude')}),
|
||||
(_('Access'), {'fields': ('access_code', 'is_private', 'private_contestants', 'is_organization_private',
|
||||
'organizations')}),
|
||||
'organizations')}),
|
||||
(_('Justice'), {'fields': ('banned_users',)}),
|
||||
)
|
||||
list_display = ('key', 'name', 'is_visible', 'is_rated', 'start_time', 'end_time', 'time_limit', 'user_count')
|
||||
@ -168,9 +168,11 @@ class ContestAdmin(VersionAdmin):
|
||||
make_hidden.short_description = _('Mark contests as hidden')
|
||||
|
||||
def get_urls(self):
|
||||
return [url(r'^rate/all/$', self.rate_all_view, name='judge_contest_rate_all'),
|
||||
url(r'^(\d+)/rate/$', self.rate_view, name='judge_contest_rate'),
|
||||
url(r'^(\d+)/judge/(\d+)/$', self.rejudge_view, name='judge_contest_rejudge')] + super(ContestAdmin, self).get_urls()
|
||||
return [
|
||||
url(r'^rate/all/$', self.rate_all_view, name='judge_contest_rate_all'),
|
||||
url(r'^(\d+)/rate/$', self.rate_view, name='judge_contest_rate'),
|
||||
url(r'^(\d+)/judge/(\d+)/$', self.rejudge_view, name='judge_contest_rejudge')
|
||||
] + super(ContestAdmin, self).get_urls()
|
||||
|
||||
def rejudge_view(self, request, contest_id, problem_id):
|
||||
if not request.user.has_perm('judge.rejudge_submission'):
|
||||
|
@ -35,7 +35,8 @@ class ProblemForm(ModelForm):
|
||||
'curators': HeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
|
||||
'testers': HeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
|
||||
'banned_users': HeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
|
||||
'organizations': HeavySelect2MultipleWidget(data_view='organization_select2', attrs={'style': 'width: 100%'}),
|
||||
'organizations': HeavySelect2MultipleWidget(data_view='organization_select2',
|
||||
attrs={'style': 'width: 100%'}),
|
||||
'types': Select2MultipleWidget,
|
||||
'group': Select2Widget,
|
||||
}
|
||||
@ -47,8 +48,8 @@ class ProblemCreatorListFilter(admin.SimpleListFilter):
|
||||
title = parameter_name = 'creator'
|
||||
|
||||
def lookups(self, request, model_admin):
|
||||
return [(name, name) for name in Profile.objects.exclude(authored_problems=None)
|
||||
.values_list('user__username', flat=True)]
|
||||
queryset = Profile.objects.exclude(authored_problems=None).values_list('user__username', flat=True)
|
||||
return [(name, name) for name in queryset]
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
if self.value() is None:
|
||||
|
@ -43,7 +43,8 @@ class TimezoneFilter(admin.SimpleListFilter):
|
||||
|
||||
class ProfileAdmin(VersionAdmin):
|
||||
fields = ('user', 'display_rank', 'about', 'organizations', 'timezone', 'language', 'ace_theme',
|
||||
'math_engine', 'last_access', 'ip', 'mute', 'is_unlisted', 'notes', 'is_totp_enabled', 'user_script', 'current_contest')
|
||||
'math_engine', 'last_access', 'ip', 'mute', 'is_unlisted', 'notes', 'is_totp_enabled', 'user_script',
|
||||
'current_contest')
|
||||
readonly_fields = ('user',)
|
||||
list_display = ('admin_user_admin', 'email', 'is_totp_enabled', 'timezone_full',
|
||||
'date_joined', 'last_access', 'ip', 'show_public')
|
||||
|
@ -53,19 +53,17 @@ class GenerateKeyTextInput(TextInput):
|
||||
'''\
|
||||
<a href="#" onclick="return false;" class="button" id="id_{0}_regen">Regenerate</a>
|
||||
<script type="text/javascript">
|
||||
(function ($) {{
|
||||
$(document).ready(function () {{
|
||||
$('#id_{0}_regen').click(function () {{
|
||||
var length = 100,
|
||||
charset = "abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()_+-=|[]{{}};:,<>./?",
|
||||
key = "";
|
||||
for (var i = 0, n = charset.length; i < length; ++i) {{
|
||||
key += charset.charAt(Math.floor(Math.random() * n));
|
||||
}}
|
||||
$('#id_{0}').val(key);
|
||||
}});
|
||||
django.jQuery(document).ready(function ($) {{
|
||||
$('#id_{0}_regen').click(function () {{
|
||||
var length = 100,
|
||||
charset = "abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()_+-=|[]{{}};:,<>./?",
|
||||
key = "";
|
||||
for (var i = 0, n = charset.length; i < length; ++i) {{
|
||||
key += charset.charAt(Math.floor(Math.random() * n));
|
||||
}}
|
||||
$('#id_{0}').val(key);
|
||||
}});
|
||||
}})(django.jQuery);
|
||||
}});
|
||||
</script>
|
||||
''', name))
|
||||
|
||||
|
@ -7,8 +7,6 @@ from django.contrib import admin, messages
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db.models import Q
|
||||
from django.forms import ModelForm
|
||||
from django.forms.models import modelformset_factory
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.html import format_html
|
||||
@ -80,13 +78,17 @@ class ContestSubmissionInline(admin.StackedInline):
|
||||
kwargs['queryset'] = ContestParticipation.objects.filter(user=submission.user,
|
||||
contest__problems=submission.problem) \
|
||||
.only('id', 'contest__name')
|
||||
label = lambda obj: obj.contest.name
|
||||
|
||||
def label(obj):
|
||||
return obj.contest.name
|
||||
elif db_field.name == 'problem':
|
||||
kwargs['queryset'] = ContestProblem.objects.filter(problem=submission.problem) \
|
||||
.only('id', 'problem__name', 'contest__name')
|
||||
label = lambda obj: pgettext('contest problem', '%(problem)s in %(contest)s') % {
|
||||
'problem': obj.problem.name, 'contest': obj.contest.name
|
||||
}
|
||||
|
||||
def label(obj):
|
||||
return pgettext('contest problem', '%(problem)s in %(contest)s') % {
|
||||
'problem': obj.problem.name, 'contest': obj.contest.name
|
||||
}
|
||||
field = super(ContestSubmissionInline, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
if label is not None:
|
||||
field.label_from_instance = label
|
||||
@ -234,8 +236,9 @@ class SubmissionAdmin(admin.ModelAdmin):
|
||||
judge_column.short_description = ''
|
||||
|
||||
def get_urls(self):
|
||||
return [url(r'^(\d+)/judge/$', self.judge_view, name='judge_submission_rejudge')] + \
|
||||
super(SubmissionAdmin, self).get_urls()
|
||||
return [
|
||||
url(r'^(\d+)/judge/$', self.judge_view, name='judge_submission_rejudge')
|
||||
] + super(SubmissionAdmin, self).get_urls()
|
||||
|
||||
def judge_view(self, request, id):
|
||||
if not request.user.has_perm('judge.rejudge_submission') or not request.user.has_perm('judge.edit_own_problem'):
|
||||
|
@ -12,7 +12,7 @@ class JudgeAppConfig(AppConfig):
|
||||
# OPERATIONS MAY HAVE SIDE EFFECTS.
|
||||
# DO NOT REMOVE THINKING THE IMPORT IS UNUSED.
|
||||
# noinspection PyUnresolvedReferences
|
||||
from . import signals, jinja2
|
||||
from . import signals, jinja2 # noqa: F401, imported for side effects
|
||||
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
from django.contrib.flatpages.admin import FlatPageAdmin
|
||||
|
@ -18,7 +18,7 @@ class DjangoHandler(ZlibPacketHandler):
|
||||
'disconnect-judge': self.on_disconnect,
|
||||
}
|
||||
self._to_kill = True
|
||||
#self.server.schedule(5, self._kill_if_no_request)
|
||||
# self.server.schedule(5, self._kill_if_no_request)
|
||||
|
||||
def _kill_if_no_request(self):
|
||||
if self._to_kill:
|
||||
@ -33,7 +33,7 @@ class DjangoHandler(ZlibPacketHandler):
|
||||
packet = json.loads(packet)
|
||||
try:
|
||||
result = self.handlers.get(packet.get('name', None), self.on_malformed)(packet)
|
||||
except:
|
||||
except Exception:
|
||||
logger.exception('Error in packet handling (Django-facing)')
|
||||
result = {'name': 'bad-request'}
|
||||
self.send(result, self._schedule_close)
|
||||
|
@ -194,7 +194,7 @@ class JudgeHandler(ProxyProtocolMixin, ZlibPacketHandler):
|
||||
else:
|
||||
handler = self.handlers.get(data['name'], self.on_malformed)
|
||||
handler(data)
|
||||
except:
|
||||
except Exception:
|
||||
logger.exception('Error in packet handling (Judge-side): %s', self.name)
|
||||
self._packet_exception()
|
||||
# You can't crash here because you aren't so sure about the judges
|
||||
|
@ -33,7 +33,7 @@ class JudgeServer(get_preferred_engine()):
|
||||
for judge in self.judges:
|
||||
judge.ping()
|
||||
time.sleep(10)
|
||||
except:
|
||||
except Exception:
|
||||
logger.exception('Ping error')
|
||||
raise
|
||||
|
||||
|
@ -52,16 +52,16 @@ class AtCoderContestFormat(DefaultContestFormat):
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute('''
|
||||
SELECT MAX(cs.points) as `score`, (
|
||||
SELECT MIN(csub.date)
|
||||
FROM judge_contestsubmission ccs LEFT OUTER JOIN
|
||||
judge_submission csub ON (csub.id = ccs.submission_id)
|
||||
WHERE ccs.problem_id = cp.id AND ccs.participation_id = %s AND ccs.points = MAX(cs.points)
|
||||
) AS `time`, cp.id AS `prob`
|
||||
FROM judge_contestproblem cp INNER JOIN
|
||||
judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN
|
||||
judge_submission sub ON (sub.id = cs.submission_id)
|
||||
GROUP BY cp.id
|
||||
SELECT MAX(cs.points) as `score`, (
|
||||
SELECT MIN(csub.date)
|
||||
FROM judge_contestsubmission ccs LEFT OUTER JOIN
|
||||
judge_submission csub ON (csub.id = ccs.submission_id)
|
||||
WHERE ccs.problem_id = cp.id AND ccs.participation_id = %s AND ccs.points = MAX(cs.points)
|
||||
) AS `time`, cp.id AS `prob`
|
||||
FROM judge_contestproblem cp INNER JOIN
|
||||
judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN
|
||||
judge_submission sub ON (sub.id = cs.submission_id)
|
||||
GROUP BY cp.id
|
||||
''', (participation.id, participation.id))
|
||||
|
||||
for score, time, prob in cursor.fetchall():
|
||||
@ -99,8 +99,8 @@ class AtCoderContestFormat(DefaultContestFormat):
|
||||
penalty=floatformat(format_data['penalty'])) if format_data['penalty'] else ''
|
||||
return format_html(
|
||||
'<td class="{state}"><a href="{url}">{points}{penalty}<div class="solving-time">{time}</div></a></td>',
|
||||
state=('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') +
|
||||
self.best_solution_state(format_data['points'], contest_problem.points),
|
||||
state=(('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') +
|
||||
self.best_solution_state(format_data['points'], contest_problem.points)),
|
||||
url=reverse('contest_user_submissions',
|
||||
args=[self.contest.key, participation.user.user.username, contest_problem.problem.code]),
|
||||
points=floatformat(format_data['points']),
|
||||
|
@ -3,7 +3,6 @@ from django.core.exceptions import ValidationError
|
||||
from django.db.models import Max
|
||||
from django.template.defaultfilters import floatformat
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy
|
||||
@ -49,8 +48,8 @@ class DefaultContestFormat(BaseContestFormat):
|
||||
if format_data:
|
||||
return format_html(
|
||||
u'<td class="{state}"><a href="{url}">{points}<div class="solving-time">{time}</div></a></td>',
|
||||
state=('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') +
|
||||
self.best_solution_state(format_data['points'], contest_problem.points),
|
||||
state=(('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') +
|
||||
self.best_solution_state(format_data['points'], contest_problem.points)),
|
||||
url=reverse('contest_user_submissions',
|
||||
args=[self.contest.key, participation.user.user.username, contest_problem.problem.code]),
|
||||
points=floatformat(format_data['points']),
|
||||
|
@ -102,8 +102,8 @@ class ECOOContestFormat(DefaultContestFormat):
|
||||
|
||||
return format_html(
|
||||
'<td class="{state}"><a href="{url}">{points}{bonus}<div class="solving-time">{time}</div></a></td>',
|
||||
state=('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') +
|
||||
self.best_solution_state(format_data['points'], contest_problem.points),
|
||||
state=(('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') +
|
||||
self.best_solution_state(format_data['points'], contest_problem.points)),
|
||||
url=reverse('contest_user_submissions',
|
||||
args=[self.contest.key, participation.user.user.username, contest_problem.problem.code]),
|
||||
points=floatformat(format_data['points']),
|
||||
|
@ -81,8 +81,8 @@ class IOIContestFormat(DefaultContestFormat):
|
||||
if format_data:
|
||||
return format_html(
|
||||
'<td class="{state}"><a href="{url}">{points}<div class="solving-time">{time}</div></a></td>',
|
||||
state=('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') +
|
||||
self.best_solution_state(format_data['points'], contest_problem.points),
|
||||
state=(('pretest-' if self.contest.run_pretests_only and contest_problem.is_pretested else '') +
|
||||
self.best_solution_state(format_data['points'], contest_problem.points)),
|
||||
url=reverse('contest_user_submissions',
|
||||
args=[self.contest.key, participation.user.user.username, contest_problem.problem.code]),
|
||||
points=floatformat(format_data['points']),
|
||||
|
@ -12,7 +12,9 @@ from judge.models import Comment, BlogPost, Problem
|
||||
class ProblemFeed(Feed):
|
||||
title = 'Recently Added %s Problems' % getattr(settings, 'SITE_NAME', 'DMOJ')
|
||||
link = '/'
|
||||
description = 'The latest problems added on the %s website' % getattr(settings, 'SITE_LONG_NAME', getattr(settings, 'SITE_NAME', 'DMOJ'))
|
||||
description = 'The latest problems added on the %s website' % (
|
||||
getattr(settings, 'SITE_LONG_NAME', getattr(settings, 'SITE_NAME', 'DMOJ'))
|
||||
)
|
||||
|
||||
def items(self):
|
||||
return Problem.objects.filter(is_public=True, is_organization_private=False).order_by('-date', '-id')[:25]
|
||||
@ -42,7 +44,9 @@ class AtomProblemFeed(ProblemFeed):
|
||||
class CommentFeed(Feed):
|
||||
title = 'Latest %s Comments' % getattr(settings, 'SITE_NAME', 'DMOJ')
|
||||
link = '/'
|
||||
description = 'The latest comments on the %s website' % getattr(settings, 'SITE_LONG_NAME', getattr(settings, 'SITE_NAME', 'DMOJ'))
|
||||
description = 'The latest comments on the %s website' % (
|
||||
getattr(settings, 'SITE_LONG_NAME', getattr(settings, 'SITE_NAME', 'DMOJ'))
|
||||
)
|
||||
|
||||
def items(self):
|
||||
return Comment.most_recent(AnonymousUser(), 25)
|
||||
@ -72,7 +76,9 @@ class AtomCommentFeed(CommentFeed):
|
||||
class BlogFeed(Feed):
|
||||
title = 'Latest %s Blog Posts' % getattr(settings, 'SITE_NAME', 'DMOJ')
|
||||
link = '/'
|
||||
description = 'The latest blog posts from the %s' % getattr(settings, 'SITE_LONG_NAME', getattr(settings, 'SITE_NAME', 'DMOJ'))
|
||||
description = 'The latest blog posts from the %s' % (
|
||||
getattr(settings, 'SITE_LONG_NAME', getattr(settings, 'SITE_NAME', 'DMOJ'))
|
||||
)
|
||||
|
||||
def items(self):
|
||||
return BlogPost.objects.filter(visible=True, publish_on__lte=timezone.now()).order_by('-sticky', '-publish_on')
|
||||
|
@ -53,7 +53,8 @@ class ProfileForm(ModelForm):
|
||||
max_orgs = getattr(settings, 'DMOJ_USER_MAX_ORGANIZATION_COUNT', 3)
|
||||
|
||||
if sum(org.is_open for org in organizations) > max_orgs:
|
||||
raise ValidationError(_('You may not be part of more than {count} public organizations.').format(count=max_orgs))
|
||||
raise ValidationError(
|
||||
_('You may not be part of more than {count} public organizations.').format(count=max_orgs))
|
||||
|
||||
return self.cleaned_data
|
||||
|
||||
|
@ -13,6 +13,7 @@ def _wrap_code(inner):
|
||||
yield tup
|
||||
yield 0, "</code>"
|
||||
|
||||
|
||||
try:
|
||||
import pygments
|
||||
import pygments.lexers
|
||||
@ -32,5 +33,5 @@ else:
|
||||
except pygments.util.ClassNotFound:
|
||||
return _make_pre_code(code)
|
||||
|
||||
#return mark_safe(pygments.highlight(code, lexer, HtmlCodeFormatter(cssclass=cssclass, linenos='table')))
|
||||
# return mark_safe(pygments.highlight(code, lexer, HtmlCodeFormatter(cssclass=cssclass, linenos='table')))
|
||||
return mark_safe(pygments.highlight(code, lexer, HtmlCodeFormatter(cssclass=cssclass)))
|
||||
|
@ -85,10 +85,10 @@ class AwesomeRenderer(MathRenderer, mistune.Renderer):
|
||||
elif 'error' not in result:
|
||||
img = ('''<img src="%(svg)s" onerror="this.src='%(png)s';this.onerror=null"'''
|
||||
'width="%(width)s" height="%(height)s"%(tail)s>') % {
|
||||
'svg': result['svg'], 'png': result['png'],
|
||||
'width': result['meta']['width'], 'height': result['meta']['height'],
|
||||
'tail': ' /' if self.options.get('use_xhtml') else ''
|
||||
}
|
||||
'svg': result['svg'], 'png': result['png'],
|
||||
'width': result['meta']['width'], 'height': result['meta']['height'],
|
||||
'tail': ' /' if self.options.get('use_xhtml') else ''
|
||||
}
|
||||
style = ['max-width: 100%',
|
||||
'height: %s' % result['meta']['height'],
|
||||
'max-height: %s' % result['meta']['height'],
|
||||
|
@ -51,7 +51,7 @@ def get_user_rating(username, data):
|
||||
def get_user_info(usernames):
|
||||
return {name: (rank, rating) for name, rank, rating in
|
||||
Profile.objects.filter(user__username__in=usernames)
|
||||
.values_list('user__username', 'display_rank', 'rating')}
|
||||
.values_list('user__username', 'display_rank', 'rating')}
|
||||
|
||||
|
||||
reference_map = {
|
||||
|
@ -88,9 +88,7 @@ def judge_submission(submission, rejudge, batch_rejudge=False):
|
||||
'problem-id': submission.problem.code,
|
||||
'language': submission.language.key,
|
||||
'source': submission.source.source,
|
||||
'priority': BATCH_REJUDGE_PRIORITY
|
||||
if batch_rejudge
|
||||
else REJUDGE_PRIORITY if rejudge else priority,
|
||||
'priority': BATCH_REJUDGE_PRIORITY if batch_rejudge else REJUDGE_PRIORITY if rejudge else priority,
|
||||
})
|
||||
except BaseException:
|
||||
logger.exception('Failed to send request to judge')
|
||||
|
@ -1,7 +1,7 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from judge.models import *
|
||||
from judge.models import Profile, Language
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
@ -1,18 +0,0 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import NoArgsCommand
|
||||
from django.utils import timezone
|
||||
from registration.models import RegistrationProfile
|
||||
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = 'Delete expired user registrations from the database'
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
for profile in RegistrationProfile.objects.exclude(activation_key=RegistrationProfile.ACTIVATED)\
|
||||
.filter(user__date_joined__lt=timezone.now() - timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS))\
|
||||
.filter(user__is_active=False):
|
||||
if not profile.user.profile.submission_set.exists():
|
||||
profile.user.delete()
|
||||
profile.delete()
|
@ -12,7 +12,7 @@ class Command(BaseCommand):
|
||||
judge_handler = DjangoJudgeHandler
|
||||
|
||||
try:
|
||||
import netaddr
|
||||
import netaddr # noqa: F401, imported to see if it exists
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
|
@ -2,7 +2,6 @@
|
||||
# Generated by Django 1.11.20 on 2019-09-02 15:58
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
@ -16,6 +16,7 @@ def make_timezones():
|
||||
data[area].append((tz, loc))
|
||||
return sorted(data.items(), key=itemgetter(0))
|
||||
|
||||
|
||||
TIMEZONE = make_timezones()
|
||||
del make_timezones
|
||||
|
||||
|
@ -21,8 +21,8 @@ from judge.utils.cachedict import CacheDict
|
||||
|
||||
__all__ = ['Comment', 'CommentLock', 'CommentVote']
|
||||
|
||||
comment_validator = RegexValidator('^[pcs]:[a-z0-9]+$|^b:\d+$',
|
||||
_('Page code must be ^[pcs]:[a-z0-9]+$|^b:\d+$'))
|
||||
comment_validator = RegexValidator(r'^[pcs]:[a-z0-9]+$|^b:\d+$',
|
||||
_(r'Page code must be ^[pcs]:[a-z0-9]+$|^b:\d+$'))
|
||||
|
||||
|
||||
class VersionRelation(GenericRelation):
|
||||
@ -112,7 +112,7 @@ class Comment(MPTTModel):
|
||||
link = reverse('blog_post', args=(self.page[2:], slug))
|
||||
elif self.page.startswith('s:'):
|
||||
link = reverse('problem_editorial', args=(self.page[2:],))
|
||||
except:
|
||||
except Exception:
|
||||
link = 'invalid'
|
||||
return link
|
||||
|
||||
|
@ -57,9 +57,9 @@ class Contest(models.Model):
|
||||
end_time = models.DateTimeField(verbose_name=_('end time'), db_index=True)
|
||||
time_limit = models.DurationField(verbose_name=_('time limit'), blank=True, null=True)
|
||||
is_visible = models.BooleanField(verbose_name=_('publicly visible'), default=False,
|
||||
help_text=_('Should be set even for organization-private contests, where it '
|
||||
'determines whether the contest is visible to members of the '
|
||||
'specified organizations.'))
|
||||
help_text=_('Should be set even for organization-private contests, where it '
|
||||
'determines whether the contest is visible to members of the '
|
||||
'specified organizations.'))
|
||||
is_rated = models.BooleanField(verbose_name=_('contest rated'), help_text=_('Whether this contest can be rated.'),
|
||||
default=False)
|
||||
hide_scoreboard = models.BooleanField(verbose_name=_('hide scoreboard'),
|
||||
@ -92,8 +92,10 @@ class Contest(models.Model):
|
||||
organizations = models.ManyToManyField(Organization, blank=True, verbose_name=_('organizations'),
|
||||
help_text=_('If private, only these organizations may see the contest'))
|
||||
og_image = models.CharField(verbose_name=_('OpenGraph image'), default='', max_length=150, blank=True)
|
||||
logo_override_image = models.CharField(verbose_name=_('Logo override image'), default='', max_length=150, blank=True,
|
||||
help_text=_('This image will replace the default site logo for users inside the contest.'))
|
||||
logo_override_image = models.CharField(verbose_name=_('Logo override image'), default='', max_length=150,
|
||||
blank=True,
|
||||
help_text=_('This image will replace the default site logo for users '
|
||||
'inside the contest.'))
|
||||
tags = models.ManyToManyField(ContestTag, verbose_name=_('contest tags'), blank=True, related_name='contests')
|
||||
user_count = models.IntegerField(verbose_name=_('the amount of live participants'), default=0)
|
||||
summary = models.TextField(blank=True, verbose_name=_('contest summary'),
|
||||
|
@ -102,8 +102,8 @@ class Problem(models.Model):
|
||||
'as shown in the problem list.'))
|
||||
description = models.TextField(verbose_name=_('problem body'))
|
||||
authors = models.ManyToManyField(Profile, verbose_name=_('creators'), blank=True, related_name='authored_problems',
|
||||
help_text=_('These users will be able to edit the problem, '
|
||||
'and be listed as authors.'))
|
||||
help_text=_('These users will be able to edit the problem, '
|
||||
'and be listed as authors.'))
|
||||
curators = models.ManyToManyField(Profile, verbose_name=_('curators'), blank=True, related_name='curated_problems',
|
||||
help_text=_('These users will be able to edit the problem, '
|
||||
'but not be listed as authors.'))
|
||||
@ -111,11 +111,10 @@ class Problem(models.Model):
|
||||
help_text=_(
|
||||
'These users will be able to view the private problem, but not edit it.'))
|
||||
types = models.ManyToManyField(ProblemType, verbose_name=_('problem types'),
|
||||
help_text=_('The type of problem, '
|
||||
"as shown on the problem's page."))
|
||||
help_text=_('The type of problem, '
|
||||
"as shown on the problem's page."))
|
||||
group = models.ForeignKey(ProblemGroup, verbose_name=_('problem group'), on_delete=CASCADE,
|
||||
help_text=_('The group of problem, '
|
||||
'shown under Category in the problem list.'))
|
||||
help_text=_('The group of problem, shown under Category in the problem list.'))
|
||||
time_limit = models.FloatField(verbose_name=_('time limit'),
|
||||
help_text=_('The time limit for this problem, in seconds. '
|
||||
'Fractional seconds (e.g. 1.5) are supported.'),
|
||||
@ -125,11 +124,11 @@ class Problem(models.Model):
|
||||
'(e.g. 64mb = 65536 kilobytes).'))
|
||||
short_circuit = models.BooleanField(default=False)
|
||||
points = models.FloatField(verbose_name=_('points'),
|
||||
help_text=_('Points awarded for problem completion. '
|
||||
"Points are displayed with a 'p' suffix if partial."))
|
||||
help_text=_('Points awarded for problem completion. '
|
||||
"Points are displayed with a 'p' suffix if partial."))
|
||||
partial = models.BooleanField(verbose_name=_('allows partial points'), default=False)
|
||||
allowed_languages = models.ManyToManyField(Language, verbose_name=_('allowed languages'),
|
||||
help_text=_('List of allowed submission languages.'))
|
||||
help_text=_('List of allowed submission languages.'))
|
||||
is_public = models.BooleanField(verbose_name=_('publicly visible'), db_index=True, default=False)
|
||||
is_manually_managed = models.BooleanField(verbose_name=_('manually managed'), db_index=True, default=False,
|
||||
help_text=_('Whether judges should be allowed to manage data or not.'))
|
||||
@ -272,8 +271,11 @@ class Problem(models.Model):
|
||||
self.user_count = self.submission_set.filter(points__gte=self.points, result='AC',
|
||||
user__is_unlisted=False).values('user').distinct().count()
|
||||
submissions = self.submission_set.count()
|
||||
self.ac_rate = 100.0 * self.submission_set.filter(points__gte=self.points, result='AC',
|
||||
user__is_unlisted=False).count() / submissions if submissions else 0
|
||||
if submissions:
|
||||
self.ac_rate = 100.0 * self.submission_set.filter(points__gte=self.points, result='AC',
|
||||
user__is_unlisted=False).count() / submissions
|
||||
else:
|
||||
self.ac_rate = 0
|
||||
self.save()
|
||||
|
||||
update_stats.alters_data = True
|
||||
|
@ -106,8 +106,8 @@ class Profile(models.Model):
|
||||
help_text=_('32 character base32-encoded key for TOTP'),
|
||||
validators=[RegexValidator('^$|^[A-Z2-7]{32}$',
|
||||
_('TOTP key must be empty or base32'))])
|
||||
notes = models.TextField(verbose_name=_('internal notes'), help_text=_('Notes for administrators regarding this user.'),
|
||||
null=True, blank=True)
|
||||
notes = models.TextField(verbose_name=_('internal notes'), null=True, blank=True,
|
||||
help_text=_('Notes for administrators regarding this user.'))
|
||||
|
||||
@cached_property
|
||||
def organization(self):
|
||||
@ -119,15 +119,17 @@ class Profile(models.Model):
|
||||
def username(self):
|
||||
return self.user.username
|
||||
|
||||
_pp_table = [pow(getattr(settings, 'DMOJ_PP_STEP', 0.95), i) for i in range(getattr(settings, 'DMOJ_PP_ENTRIES', 100))]
|
||||
_pp_table = [pow(getattr(settings, 'DMOJ_PP_STEP', 0.95), i)
|
||||
for i in range(getattr(settings, 'DMOJ_PP_ENTRIES', 100))]
|
||||
|
||||
def calculate_points(self, table=_pp_table):
|
||||
from judge.models import Problem
|
||||
data = (Problem.objects.filter(submission__user=self, submission__points__isnull=False, is_public=True,
|
||||
is_organization_private=False)
|
||||
.annotate(max_points=Max('submission__points')).order_by('-max_points')
|
||||
.values_list('max_points', flat=True).filter(max_points__gt=0))
|
||||
.annotate(max_points=Max('submission__points')).order_by('-max_points')
|
||||
.values_list('max_points', flat=True).filter(max_points__gt=0))
|
||||
extradata = Problem.objects.filter(submission__user=self, submission__result='AC', is_public=True) \
|
||||
.values('id').distinct().count()
|
||||
.values('id').distinct().count()
|
||||
bonus_function = getattr(settings, 'DMOJ_PP_BONUS_FUNCTION', lambda n: 300 * (1 - 0.997 ** n))
|
||||
points = sum(data)
|
||||
problems = len(data)
|
||||
|
@ -162,8 +162,8 @@ class Submission(models.Model):
|
||||
|
||||
@classmethod
|
||||
def get_id_secret(cls, sub_id):
|
||||
return (hmac.new(utf8bytes(settings.EVENT_DAEMON_SUBMISSION_KEY), b'%d' % sub_id, hashlib.sha512).hexdigest()[:16] +
|
||||
'%08x' % sub_id)
|
||||
return (hmac.new(utf8bytes(settings.EVENT_DAEMON_SUBMISSION_KEY), b'%d' % sub_id, hashlib.sha512)
|
||||
.hexdigest()[:16] + '%08x' % sub_id)
|
||||
|
||||
@cached_property
|
||||
def id_secret(self):
|
||||
|
@ -186,8 +186,7 @@ try {
|
||||
'zoom': getattr(settings, 'SLIMERJS_PDF_ZOOM', 0.75),
|
||||
'input': 'input.html', 'output': 'output.pdf',
|
||||
'paper': getattr(settings, 'SLIMERJS_PAPER_SIZE', 'Letter'),
|
||||
'footer': gettext('Page [page] of [topage]').replace('[page]', '&P')
|
||||
.replace('[topage]', '&L'),
|
||||
'footer': gettext('Page [page] of [topage]').replace('[page]', '&P').replace('[topage]', '&L'),
|
||||
}))
|
||||
|
||||
def _make(self, debug):
|
||||
|
@ -74,7 +74,8 @@ def recalculate_ratings(old_rating, old_volatility, actual_rank, times_rated):
|
||||
if times_rated[i] == 0:
|
||||
new_volatility[i] = 385
|
||||
else:
|
||||
new_volatility[i] = math.sqrt(((new_rating[i] - old_rating[i]) ** 2) / Weight + (old_volatility[i] ** 2) / (Weight + 1))
|
||||
new_volatility[i] = math.sqrt(((new_rating[i] - old_rating[i]) ** 2) / Weight +
|
||||
(old_volatility[i] ** 2) / (Weight + 1))
|
||||
if abs(old_rating[i] - new_rating[i]) > Cap:
|
||||
if old_rating[i] < new_rating[i]:
|
||||
new_rating[i] = old_rating[i] + Cap
|
||||
|
@ -5,7 +5,6 @@ from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.cache import cache
|
||||
from django.core.cache.utils import make_template_fragment_key
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.dispatch import receiver
|
||||
|
||||
|
@ -44,7 +44,7 @@ class GitHubSecureEmailOAuth2(GithubOAuth2):
|
||||
return data
|
||||
|
||||
|
||||
def slugify_username(username, renotword=re.compile('[^\w]')):
|
||||
def slugify_username(username, renotword=re.compile(r'[^\w]')):
|
||||
return renotword.sub('', username.replace('-', '_'))
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@ register = template.Library()
|
||||
|
||||
|
||||
@register.filter(name='list_attr')
|
||||
def list_getattr(iterable, prop):
|
||||
def list_attr(iterable, prop):
|
||||
result = []
|
||||
for item in iterable:
|
||||
if hasattr(item, str(prop)):
|
||||
|
@ -1,3 +1 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
|
@ -7,14 +7,12 @@ if settings.USE_I18N:
|
||||
|
||||
_translations = {}
|
||||
|
||||
|
||||
def translation(language):
|
||||
global _translations
|
||||
if language not in _translations:
|
||||
_translations[language] = DjangoTranslation(language, domain='dmoj-user')
|
||||
return _translations[language]
|
||||
|
||||
|
||||
def do_translate(message, translation_function):
|
||||
"""Copied from django.utils.translation.trans_real"""
|
||||
# str() is allowing a bytestring message to remain bytestring on Python 2
|
||||
@ -35,7 +33,6 @@ if settings.USE_I18N:
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def gettext(message):
|
||||
return do_translate(message, 'gettext')
|
||||
else:
|
||||
|
@ -2,8 +2,10 @@ import hmac
|
||||
from hashlib import sha1
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from judge.utils.unicode import utf8bytes
|
||||
|
||||
|
||||
class CamoClient(object):
|
||||
"""Based on https://github.com/sionide21/camo-client"""
|
||||
|
||||
|
@ -200,7 +200,7 @@ class DiggPaginator(ExPaginator):
|
||||
"""
|
||||
|
||||
page = super(DiggPaginator, self).page(number, *args, **kwargs)
|
||||
number = int(number) # we know this will work
|
||||
number = int(number) # we know this will work
|
||||
|
||||
# easier access
|
||||
num_pages, body, tail, padding, margin = \
|
||||
@ -208,7 +208,7 @@ class DiggPaginator(ExPaginator):
|
||||
|
||||
# put active page in middle of main range
|
||||
main_range = list(map(int, [
|
||||
math.floor(number - body / 2.0) + 1, # +1 = shift odd body to right
|
||||
math.floor(number - body / 2.0) + 1, # +1 = shift odd body to right
|
||||
math.floor(number + body / 2.0)]))
|
||||
# adjust bounds
|
||||
if main_range[0] < 1:
|
||||
|
@ -63,7 +63,7 @@ class MathoidMathParser(object):
|
||||
try:
|
||||
response = requests.post(self.mathoid_url, data={
|
||||
'q': reescape.sub(lambda m: '\\' + m.group(0), formula).encode('utf-8'),
|
||||
'type': 'tex' if formula.startswith('\displaystyle') else 'inline-tex'
|
||||
'type': 'tex' if formula.startswith(r'\displaystyle') else 'inline-tex'
|
||||
})
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
@ -132,7 +132,7 @@ class MathoidMathParser(object):
|
||||
return None
|
||||
|
||||
result['tex'] = formula
|
||||
result['display'] = formula.startswith('\displaystyle')
|
||||
result['display'] = formula.startswith(r'\displaystyle')
|
||||
return {
|
||||
'mml': self.output_mml,
|
||||
'msp': self.output_msp,
|
||||
@ -178,7 +178,7 @@ class MathoidMathParser(object):
|
||||
|
||||
def display_math(self, math):
|
||||
math = format_math(math)
|
||||
return self.get_result('\displaystyle ' + math) or r'\[%s\]' % escape(math)
|
||||
return self.get_result(r'\displaystyle ' + math) or r'\[%s\]' % escape(math)
|
||||
|
||||
def inline_math(self, math):
|
||||
math = format_math(math)
|
||||
|
@ -18,8 +18,8 @@ def user_authored_ids(profile):
|
||||
|
||||
|
||||
def user_editable_ids(profile):
|
||||
result = set((Problem.objects.filter(authors=profile) | Problem.objects.filter(curators=profile)).values_list('id',
|
||||
flat=True))
|
||||
result = set((Problem.objects.filter(authors=profile) | Problem.objects.filter(curators=profile))
|
||||
.values_list('id', flat=True))
|
||||
return result
|
||||
|
||||
|
||||
@ -110,7 +110,8 @@ def hot_problems(duration, limit):
|
||||
cache_key = 'hot_problems:%d:%d' % (duration.total_seconds(), limit)
|
||||
qs = cache.get(cache_key)
|
||||
if qs is None:
|
||||
qs = Problem.objects.filter(is_public=True, is_organization_private=False, submission__date__gt=timezone.now() - duration, points__gt=3, points__lt=25)
|
||||
qs = Problem.objects.filter(is_public=True, is_organization_private=False,
|
||||
submission__date__gt=timezone.now() - duration, points__gt=3, points__lt=25)
|
||||
qs0 = qs.annotate(k=Count('submission__user', distinct=True)).order_by('-k').values_list('k', flat=True)
|
||||
|
||||
if not qs0:
|
||||
@ -121,21 +122,24 @@ def hot_problems(duration, limit):
|
||||
qs = qs.annotate(unique_user_count=Count('submission__user', distinct=True))
|
||||
# fix braindamage in excluding CE
|
||||
qs = qs.annotate(submission_volume=Count(Case(
|
||||
When(submission__result='AC', then=1),
|
||||
When(submission__result='WA', then=1),
|
||||
When(submission__result='IR', then=1),
|
||||
When(submission__result='RTE', then=1),
|
||||
When(submission__result='TLE', then=1),
|
||||
When(submission__result='OLE', then=1),
|
||||
output_field=FloatField(),
|
||||
)))
|
||||
When(submission__result='AC', then=1),
|
||||
When(submission__result='WA', then=1),
|
||||
When(submission__result='IR', then=1),
|
||||
When(submission__result='RTE', then=1),
|
||||
When(submission__result='TLE', then=1),
|
||||
When(submission__result='OLE', then=1),
|
||||
output_field=FloatField(),
|
||||
)))
|
||||
qs = qs.annotate(ac_volume=Count(Case(
|
||||
When(submission__result='AC', then=1),
|
||||
output_field=FloatField(),
|
||||
)))
|
||||
When(submission__result='AC', then=1),
|
||||
output_field=FloatField(),
|
||||
)))
|
||||
qs = qs.filter(unique_user_count__gt=max(mx / 3.0, 1))
|
||||
|
||||
qs = qs.annotate(ordering=ExpressionWrapper(0.5 * F('points') * (0.4 * F('ac_volume') / F('submission_volume') + 0.6 * F('ac_rate')) + 100 * e ** (F('unique_user_count') / mx), output_field=FloatField())).order_by('-ordering').defer('description')[:limit]
|
||||
qs = qs.annotate(ordering=ExpressionWrapper(
|
||||
0.5 * F('points') * (0.4 * F('ac_volume') / F('submission_volume') + 0.6 * F('ac_rate')) +
|
||||
100 * e ** (F('unique_user_count') / mx), output_field=FloatField()
|
||||
)).order_by('-ordering').defer('description')[:limit]
|
||||
|
||||
cache.set(cache_key, qs, 900)
|
||||
return qs
|
||||
|
@ -16,7 +16,7 @@ def sane_time_repr(delta):
|
||||
|
||||
|
||||
def api_v1_contest_list(request):
|
||||
queryset = Contest.objects.filter(is_visible=True, is_private=False,
|
||||
queryset = Contest.objects.filter(is_visible=True, is_private=False,
|
||||
is_organization_private=False).prefetch_related(
|
||||
Prefetch('tags', queryset=ContestTag.objects.only('name'), to_attr='tag_list')).defer('description')
|
||||
|
||||
@ -44,8 +44,8 @@ def api_v1_contest_detail(request, contest):
|
||||
.annotate(username=F('user__user__username'))
|
||||
.order_by('-score', 'cumtime') if can_see_rankings else [])
|
||||
|
||||
if not (in_contest or contest.ended or request.user.is_superuser
|
||||
or (request.user.is_authenticated and contest.organizers.filter(id=request.profile.id).exists())):
|
||||
if not (in_contest or contest.ended or request.user.is_superuser or
|
||||
(request.user.is_authenticated and contest.organizers.filter(id=request.profile.id).exists())):
|
||||
problems = []
|
||||
|
||||
return JsonResponse({
|
||||
@ -125,7 +125,8 @@ def api_v1_user_list(request):
|
||||
|
||||
def api_v1_user_info(request, user):
|
||||
profile = get_object_or_404(Profile, user__username=user)
|
||||
submissions = list(Submission.objects.filter(case_points=F('case_total'), user=profile, problem__is_public=True, problem__is_organization_private=False)
|
||||
submissions = list(Submission.objects.filter(case_points=F('case_total'), user=profile, problem__is_public=True,
|
||||
problem__is_organization_private=False)
|
||||
.values('problem').distinct().values_list('problem__code', flat=True))
|
||||
resp = {
|
||||
'points': profile.points,
|
||||
|
@ -67,13 +67,14 @@ def api_v2_user_info(request):
|
||||
|
||||
contest_history = []
|
||||
for participation in (ContestParticipation.objects.filter(user=profile, virtual=0, contest__is_visible=True)
|
||||
.order_by('-contest__end_time')):
|
||||
.order_by('-contest__end_time')):
|
||||
contest = participation.contest
|
||||
|
||||
problems = list(contest.contest_problems.select_related('problem').defer('problem__description')
|
||||
.order_by('order'))
|
||||
rank, result = next(filter(lambda data: data[1].user == profile.user,
|
||||
ranker(contest_ranking_list(contest,problems), key=attrgetter('points', 'cumtime'))))
|
||||
ranker(contest_ranking_list(contest, problems),
|
||||
key=attrgetter('points', 'cumtime'))))
|
||||
|
||||
contest_history.append({
|
||||
'contest': {
|
||||
@ -117,7 +118,7 @@ def api_v2_user_info(request):
|
||||
'solved': solved_problems,
|
||||
'attempted': attempted_problems,
|
||||
'authored': list(Problem.objects.filter(is_public=True, is_organization_private=False, authors=profile)
|
||||
.values_list('code', flat=True))
|
||||
.values_list('code', flat=True))
|
||||
}
|
||||
|
||||
return JsonResponse(resp)
|
||||
|
@ -58,8 +58,8 @@ class PostList(ListView):
|
||||
context['post_comment_counts'] = {
|
||||
int(page[2:]): count for page, count in
|
||||
Comment.objects
|
||||
.filter(page__in=['b:%d' % post.id for post in context['posts']], hidden=False)
|
||||
.values_list('page').annotate(count=Count('page')).order_by()
|
||||
.filter(page__in=['b:%d' % post.id for post in context['posts']], hidden=False)
|
||||
.values_list('page').annotate(count=Count('page')).order_by()
|
||||
}
|
||||
|
||||
now = timezone.now()
|
||||
|
@ -6,7 +6,6 @@ from itertools import chain
|
||||
from operator import attrgetter
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
|
||||
@ -181,7 +180,8 @@ class ContestMixin(object):
|
||||
raise Http404()
|
||||
|
||||
if contest.is_private or contest.is_organization_private:
|
||||
private_contest_error = PrivateContestError(contest.name, contest.private_contestants.all(), contest.organizations.all())
|
||||
private_contest_error = PrivateContestError(contest.name, contest.private_contestants.all(),
|
||||
contest.organizations.all())
|
||||
if profile is None:
|
||||
raise private_contest_error
|
||||
if user.has_perm('judge.edit_all_contest'):
|
||||
@ -272,8 +272,8 @@ class ContestJoin(LoginRequiredMixin, ContestMixin, BaseDetailView):
|
||||
_('You have been declared persona non grata for this contest. '
|
||||
'You are permanently barred from joining this contest.'))
|
||||
|
||||
requires_access_code = not (request.user.is_superuser or self.is_organizer) \
|
||||
and contest.access_code and access_code != contest.access_code
|
||||
requires_access_code = (not (request.user.is_superuser or self.is_organizer) and
|
||||
contest.access_code and access_code != contest.access_code)
|
||||
if contest.ended:
|
||||
if requires_access_code:
|
||||
raise ContestAccessDenied()
|
||||
|
@ -1,5 +1,3 @@
|
||||
from itertools import chain
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
@ -8,7 +6,7 @@ from django.core.cache import cache
|
||||
from django.core.cache.utils import make_template_fragment_key
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, Max, Q
|
||||
from django.db.models import Count, Q
|
||||
from django.forms import Form, modelformset_factory
|
||||
from django.http import Http404, HttpResponseRedirect, HttpResponsePermanentRedirect
|
||||
from django.urls import reverse
|
||||
@ -120,7 +118,10 @@ class JoinOrganization(OrganizationMembershipChange):
|
||||
|
||||
max_orgs = getattr(settings, 'DMOJ_USER_MAX_ORGANIZATION_COUNT', 3)
|
||||
if profile.organizations.filter(is_open=True).count() >= max_orgs:
|
||||
return generic_message(request, _('Joining organization'), _('You may not be part of more than {count} public organizations.').format(count=max_orgs))
|
||||
return generic_message(
|
||||
request, _('Joining organization'),
|
||||
_('You may not be part of more than {count} public organizations.').format(count=max_orgs)
|
||||
)
|
||||
|
||||
profile.organizations.add(org)
|
||||
profile.save()
|
||||
@ -281,7 +282,8 @@ class EditOrganization(LoginRequiredMixin, TitleMixin, OrganizationMixin, Update
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super(EditOrganization, self).get_form(form_class)
|
||||
form.fields['admins'].queryset = Profile.objects.filter(Q(organizations=self.object) | Q(admin_of=self.object)).distinct()
|
||||
form.fields['admins'].queryset = \
|
||||
Profile.objects.filter(Q(organizations=self.object) | Q(admin_of=self.object)).distinct()
|
||||
return form
|
||||
|
||||
def form_valid(self, form):
|
||||
|
@ -9,7 +9,7 @@ from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||
from django.db import IntegrityError, transaction
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, Q, F, Prefetch
|
||||
from django.db.utils import ProgrammingError
|
||||
from django.http import Http404, HttpResponseRedirect, HttpResponse, HttpResponseForbidden
|
||||
@ -21,7 +21,6 @@ from django.utils.functional import cached_property
|
||||
from django.utils.html import format_html, escape
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext as _, gettext_lazy
|
||||
from django.views.decorators.http import require_POST
|
||||
from django.views.generic import ListView, View
|
||||
from django.views.generic.base import TemplateResponseMixin
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
@ -29,8 +28,9 @@ from django.views.generic.detail import SingleObjectMixin
|
||||
from django_ace.widgets import ACE_URL
|
||||
from judge.comments import CommentedDetailView
|
||||
from judge.forms import ProblemCloneForm, ProblemSubmitForm
|
||||
from judge.models import ContestSubmission, ContestProblem, Judge, Language, Problem, ProblemGroup, ProblemTranslation, \
|
||||
ProblemType, RuntimeVersion, Solution, Submission, SubmissionSource, TranslatedProblemForeignKeyQuerySet
|
||||
from judge.models import ContestSubmission, ContestProblem, Judge, Language, Problem, ProblemGroup, \
|
||||
ProblemTranslation, ProblemType, RuntimeVersion, Solution, Submission, SubmissionSource, \
|
||||
TranslatedProblemForeignKeyQuerySet
|
||||
from judge.pdf_problems import HAS_PDF, DefaultPdfMaker
|
||||
from judge.utils.diggpaginator import DiggPaginator
|
||||
from judge.utils.opengraph import generate_opengraph
|
||||
@ -49,7 +49,8 @@ def get_contest_problem(problem, profile):
|
||||
|
||||
|
||||
def get_contest_submission_count(problem, profile):
|
||||
return profile.current_contest.submissions.exclude(submission__status__in=['IE']).filter(problem__problem__code=problem).count()
|
||||
return profile.current_contest.submissions.exclude(submission__status__in=['IE'])\
|
||||
.filter(problem__problem__code=problem).count()
|
||||
|
||||
|
||||
class ProblemMixin(object):
|
||||
@ -273,7 +274,8 @@ class ProblemPdfView(ProblemMixin, SingleObjectMixin, View):
|
||||
shutil.move(maker.pdffile, cache)
|
||||
|
||||
response = HttpResponse()
|
||||
if hasattr(settings, 'DMOJ_PDF_PROBLEM_INTERNAL') and request.META.get('SERVER_SOFTWARE', '').startswith('nginx/'):
|
||||
if hasattr(settings, 'DMOJ_PDF_PROBLEM_INTERNAL') and \
|
||||
request.META.get('SERVER_SOFTWARE', '').startswith('nginx/'):
|
||||
response['X-Accel-Redirect'] = '%s/%s.%s.pdf' % (settings.DMOJ_PDF_PROBLEM_INTERNAL, problem.code, language)
|
||||
else:
|
||||
with open(cache, 'rb') as f:
|
||||
@ -527,7 +529,7 @@ user_logger = logging.getLogger('judge.user')
|
||||
@login_required
|
||||
def problem_submit(request, problem=None, submission=None):
|
||||
if submission is not None and not request.user.has_perm('judge.resubmit_other') and \
|
||||
get_object_or_404(Submission, id=int(submission)).user.user != request.user:
|
||||
get_object_or_404(Submission, id=int(submission)).user.user != request.user:
|
||||
raise PermissionDenied()
|
||||
|
||||
profile = request.profile
|
||||
@ -535,8 +537,8 @@ def problem_submit(request, problem=None, submission=None):
|
||||
form = ProblemSubmitForm(request.POST, instance=Submission(user=profile))
|
||||
if form.is_valid():
|
||||
if (not request.user.has_perm('judge.spam_submission') and
|
||||
Submission.objects.filter(user=profile, was_rejudged=False).exclude(
|
||||
status__in=['D', 'IE', 'CE', 'AB']).count() > 2):
|
||||
Submission.objects.filter(user=profile, was_rejudged=False)
|
||||
.exclude(status__in=['D', 'IE', 'CE', 'AB']).count() > 2):
|
||||
return HttpResponse('<h1>You submitted too many submissions.</h1>', status=429)
|
||||
if not form.cleaned_data['problem'].allowed_languages.filter(
|
||||
id=form.cleaned_data['language'].id).exists():
|
||||
@ -603,8 +605,10 @@ def problem_submit(request, problem=None, submission=None):
|
||||
form = ProblemSubmitForm(initial=initial)
|
||||
form_data = initial
|
||||
if 'problem' in form_data:
|
||||
form.fields['language'].queryset = (form_data['problem'].usable_languages.order_by('name', 'key')
|
||||
.prefetch_related(Prefetch('runtimeversion_set', RuntimeVersion.objects.order_by('priority'))))
|
||||
form.fields['language'].queryset = (
|
||||
form_data['problem'].usable_languages.order_by('name', 'key')
|
||||
.prefetch_related(Prefetch('runtimeversion_set', RuntimeVersion.objects.order_by('priority')))
|
||||
)
|
||||
problem_object = form_data['problem']
|
||||
if 'language' in form_data:
|
||||
form.fields['source'].widget.mode = form_data['language'].ace
|
||||
|
@ -73,7 +73,8 @@ class ProblemCaseForm(ModelForm):
|
||||
}
|
||||
|
||||
|
||||
class ProblemCaseFormSet(formset_factory(ProblemCaseForm, formset=BaseModelFormSet, extra=1, max_num=1, can_delete=True)):
|
||||
class ProblemCaseFormSet(formset_factory(ProblemCaseForm, formset=BaseModelFormSet, extra=1, max_num=1,
|
||||
can_delete=True)):
|
||||
model = ProblemTestCase
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -68,19 +68,22 @@ class RankedSubmissions(ProblemSubmissions):
|
||||
class ContestRankedSubmission(ForceContestMixin, RankedSubmissions):
|
||||
def get_title(self):
|
||||
if self.problem.is_accessible_by(self.request.user):
|
||||
return _('Best solutions for %(problem)s in %(contest)s') % {'problem': self.problem_name,
|
||||
'contest': self.contest.name}
|
||||
return _('Best solutions for problem %(number)s in %(contest)s') % {'number': self.get_problem_number(self.problem),
|
||||
'contest': self.contest.name}
|
||||
return _('Best solutions for %(problem)s in %(contest)s') % {
|
||||
'problem': self.problem_name, 'contest': self.contest.name
|
||||
}
|
||||
return _('Best solutions for problem %(number)s in %(contest)s') % {
|
||||
'number': self.get_problem_number(self.problem), 'contest': self.contest.name
|
||||
}
|
||||
|
||||
def get_content_title(self):
|
||||
if self.problem.is_accessible_by(self.request.user):
|
||||
return format_html(_('Best solutions for <a href="{1}">{0}</a> in <a href="{3}">{2}</a>'),
|
||||
self.problem_name, reverse('problem_detail', args=[self.problem.code]),
|
||||
self.contest.name, reverse('contest_view', args=[self.contest.key]))
|
||||
self.problem_name, reverse('problem_detail', args=[self.problem.code]),
|
||||
self.contest.name, reverse('contest_view', args=[self.contest.key]))
|
||||
return format_html(_('Best solutions for problem {0} in <a href="{2}">{1}</a>'),
|
||||
self.get_problem_number(self.problem), self.contest.name, reverse('contest_view', args=[self.contest.key]))
|
||||
self.get_problem_number(self.problem), self.contest.name,
|
||||
reverse('contest_view', args=[self.contest.key]))
|
||||
|
||||
def _get_result_data(self):
|
||||
return get_result_data(Submission.objects.filter(
|
||||
problem_id=self.problem.id, contest__participation__contest_id=self.contest.id))
|
||||
problem_id=self.problem.id, contest__participation__contest_id=self.contest.id))
|
||||
|
@ -46,8 +46,8 @@ class CustomRegistrationForm(RegistrationForm):
|
||||
'is allowed per address.') % self.cleaned_data['email'])
|
||||
if '@' in self.cleaned_data['email']:
|
||||
domain = self.cleaned_data['email'].split('@')[-1].lower()
|
||||
if (domain in getattr(settings, 'BAD_MAIL_PROVIDERS', ())
|
||||
or any(regex.match(domain) for regex in bad_mail_regex)):
|
||||
if (domain in getattr(settings, 'BAD_MAIL_PROVIDERS', ()) or
|
||||
any(regex.match(domain) for regex in bad_mail_regex)):
|
||||
raise forms.ValidationError(gettext('Your email provider is not allowed due to history of abuse. '
|
||||
'Please use a reputable email provider.'))
|
||||
return self.cleaned_data['email']
|
||||
|
@ -116,7 +116,8 @@ class UserSearchSelect2View(BaseListView):
|
||||
class ContestUserSearchSelect2View(UserSearchSelect2View):
|
||||
def get_queryset(self):
|
||||
contest = get_object_or_404(Contest, key=self.kwargs['contest'])
|
||||
if not contest.can_see_scoreboard(self.request.user) or contest.hide_scoreboard and contest.is_in_contest(self.request.user):
|
||||
if not contest.can_see_scoreboard(self.request.user) or \
|
||||
contest.hide_scoreboard and contest.is_in_contest(self.request.user):
|
||||
raise Http404()
|
||||
|
||||
return Profile.objects.filter(contest_history__contest=contest,
|
||||
|
@ -2,7 +2,7 @@ from itertools import repeat, chain
|
||||
from operator import itemgetter
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Count, Sum, Case, When, IntegerField, Value, FloatField
|
||||
from django.db.models import Count, Case, When, IntegerField, Value, FloatField
|
||||
from django.db.models.expressions import CombinedExpression
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import render
|
||||
|
@ -147,8 +147,8 @@ class SubmissionSourceRaw(SubmissionSource):
|
||||
@require_POST
|
||||
def abort_submission(request, submission):
|
||||
submission = get_object_or_404(Submission, id=int(submission))
|
||||
if (not request.user.is_authenticated or (submission.was_rejudged or
|
||||
(request.profile != submission.user)) and not request.user.has_perm('abort_any_submission')):
|
||||
if (not request.user.is_authenticated or (submission.was_rejudged or (request.profile != submission.user)) and
|
||||
not request.user.has_perm('abort_any_submission')):
|
||||
raise PermissionDenied()
|
||||
submission.abort()
|
||||
return HttpResponseRedirect(reverse('submission_status', args=(submission.id,)))
|
||||
|
@ -1,6 +1,5 @@
|
||||
import json
|
||||
from functools import partial
|
||||
from urllib.parse import urlencode
|
||||
from uuid import UUID
|
||||
|
||||
from celery.result import AsyncResult
|
||||
|
@ -17,7 +17,7 @@ from django.utils.html import escape, format_html, linebreaks
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy, gettext as _
|
||||
from django.views import View
|
||||
from django.views.generic import FormView, ListView
|
||||
from django.views.generic import ListView
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
@ -302,8 +302,8 @@ class TicketListDataAjax(TicketMixin, SingleObjectMixin, View):
|
||||
'notification': {
|
||||
'title': _('New Ticket: %s') % ticket.title,
|
||||
'body': '%s\n%s' % (_('#%(id)d, assigned to: %(users)s') % {
|
||||
'id': ticket.id, 'users': (_(', ').join(ticket.assignees.values_list('user__username', flat=True))
|
||||
or _('no one')),
|
||||
'id': ticket.id,
|
||||
'users': (_(', ').join(ticket.assignees.values_list('user__username', flat=True)) or _('no one')),
|
||||
}, truncatechars(message.body, 200)),
|
||||
}
|
||||
})
|
||||
|
@ -93,14 +93,19 @@ class UserPage(TitleMixin, UserMixin, DetailView):
|
||||
context = super(UserPage, self).get_context_data(**kwargs)
|
||||
|
||||
context['hide_solved'] = int(self.hide_solved)
|
||||
context['authored'] = self.object.authored_problems.filter(is_public=True, is_organization_private=False).order_by('code')
|
||||
context['authored'] = self.object.authored_problems.filter(is_public=True, is_organization_private=False) \
|
||||
.order_by('code')
|
||||
rating = self.object.ratings.order_by('-contest__end_time')[:1]
|
||||
context['rating'] = rating[0] if rating else None
|
||||
|
||||
context['rank'] = Profile.objects.filter(is_unlisted=False, performance_points__gt=self.object.performance_points).count() + 1
|
||||
context['rank'] = Profile.objects.filter(
|
||||
is_unlisted=False, performance_points__gt=self.object.performance_points
|
||||
).count() + 1
|
||||
|
||||
if rating:
|
||||
context['rating_rank'] = Profile.objects.filter(is_unlisted=False, rating__gt=self.object.rating).count() + 1
|
||||
context['rating_rank'] = Profile.objects.filter(
|
||||
is_unlisted=False, rating__gt=self.object.rating
|
||||
).count() + 1
|
||||
context['rated_users'] = Profile.objects.filter(is_unlisted=False, rating__isnull=False).count()
|
||||
context.update(self.object.ratings.aggregate(min_rating=Min('rating'), max_rating=Max('rating'),
|
||||
contests=Count('contest')))
|
||||
@ -281,7 +286,7 @@ user_list_view = UserList.as_view()
|
||||
|
||||
class FixedContestRanking(ContestRanking):
|
||||
contest = None
|
||||
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return self.contest
|
||||
|
||||
@ -302,7 +307,9 @@ def user_ranking_redirect(request):
|
||||
raise Http404()
|
||||
user = get_object_or_404(Profile, user__username=username)
|
||||
rank = Profile.objects.filter(is_unlisted=False, performance_points__gt=user.performance_points).count()
|
||||
rank += Profile.objects.filter(is_unlisted=False, performance_points__exact=user.performance_points, id__lt=user.id).count()
|
||||
rank += Profile.objects.filter(
|
||||
is_unlisted=False, performance_points__exact=user.performance_points, id__lt=user.id
|
||||
).count()
|
||||
page = rank // UserList.paginate_by
|
||||
return HttpResponseRedirect('%s%s#!%s' % (reverse('user_list'), '?page=%d' % (page + 1) if page else '', username))
|
||||
|
||||
|
@ -51,7 +51,7 @@ class DetectTimezone(View):
|
||||
if not hasattr(settings, 'GEONAMES_USERNAME'):
|
||||
raise ImproperlyConfigured()
|
||||
data = requests.get('http://api.geonames.org/timezoneJSON?lat=%f&lng=%f&username=%s' %
|
||||
(lat, long, settings.GEONAMES_USERNAME)).json()
|
||||
(lat, long, settings.GEONAMES_USERNAME)).json()
|
||||
try:
|
||||
return HttpResponse(data['timezoneId'], content_type='text/plain')
|
||||
except KeyError:
|
||||
|
@ -42,6 +42,6 @@ class CompressorWidgetMixin(object):
|
||||
result = html.fromstring(template.render(Context({'media': media})))
|
||||
|
||||
return forms.Media(
|
||||
css={'all': [result.find('.//link').get('href')]} if self.compress_css else media._css,
|
||||
js=[result.find('.//script').get('src')] if self.compress_js else media._js
|
||||
css={'all': [result.find('.//link').get('href')]} if self.compress_css else media._css,
|
||||
js=[result.find('.//script').get('src')] if self.compress_js else media._js
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user