Fix basic flake8 errors

This commit is contained in:
Quantum 2019-09-28 16:32:12 -04:00 committed by Guanzhong Chen
parent 4b07800b5d
commit 61daa227e2
72 changed files with 258 additions and 230 deletions

View File

@ -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

View File

@ -2,4 +2,4 @@
Django-ace originally from https://github.com/bradleyayers/django-ace.
"""
from .widgets import AceWidget
from .widgets import AceWidget

View File

@ -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'):

View File

@ -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

View File

@ -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))

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -24,4 +24,4 @@ class Handler(object):
@property
def socket(self):
return self._socket
return self._socket

View File

@ -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()

View File

@ -89,5 +89,6 @@ def main():
print('Done')
s1.close()
if __name__ == '__main__':
main()

View File

@ -49,5 +49,6 @@ def main():
server = TestServer(list(zip(args.host, args.port)), handler)
server.serve_forever()
if __name__ == '__main__':
main()

View File

@ -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'):

View File

@ -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:

View File

@ -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')

View File

@ -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))

View File

@ -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'):

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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']),

View File

@ -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']),

View File

@ -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']),

View File

@ -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']),

View File

@ -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')

View File

@ -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

View File

@ -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)))

View File

@ -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'],

View File

@ -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 = {

View File

@ -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')

View File

@ -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):

View File

@ -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()

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'),

View File

@ -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

View File

@ -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)

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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('-', '_'))

View File

@ -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)):

View File

@ -1,3 +1 @@
from django.test import TestCase
# Create your tests here.

View File

@ -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:

View File

@ -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"""

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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):

View File

@ -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

View File

@ -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):

View File

@ -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))

View File

@ -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']

View File

@ -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,

View File

@ -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

View File

@ -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,)))

View File

@ -1,6 +1,5 @@
import json
from functools import partial
from urllib.parse import urlencode
from uuid import UUID
from celery.result import AsyncResult

View File

@ -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)),
}
})

View File

@ -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))

View File

@ -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:

View File

@ -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
)

View File

@ -3,7 +3,7 @@ import os
import sys
try:
import MySQLdb
import MySQLdb # noqa: F401, imported for side effect
except ImportError:
import pymysql
pymysql.install_as_MySQLdb()