Reformat using black

This commit is contained in:
cuom1999 2022-05-14 12:57:27 -05:00
parent efee4ad081
commit a87fb49918
221 changed files with 19127 additions and 7310 deletions

View file

@ -3,7 +3,12 @@ from django.contrib.admin.models import LogEntry
from judge.admin.comments import CommentAdmin
from judge.admin.contest import ContestAdmin, ContestParticipationAdmin, ContestTagAdmin
from judge.admin.interface import BlogPostAdmin, LicenseAdmin, LogEntryAdmin, NavigationBarAdmin
from judge.admin.interface import (
BlogPostAdmin,
LicenseAdmin,
LogEntryAdmin,
NavigationBarAdmin,
)
from judge.admin.organization import OrganizationAdmin, OrganizationRequestAdmin
from judge.admin.problem import ProblemAdmin, ProblemPointsVoteAdmin
from judge.admin.profile import ProfileAdmin
@ -12,10 +17,29 @@ from judge.admin.submission import SubmissionAdmin
from judge.admin.taxon import ProblemGroupAdmin, ProblemTypeAdmin
from judge.admin.ticket import TicketAdmin
from judge.admin.volunteer import VolunteerProblemVoteAdmin
from judge.models import BlogPost, Comment, CommentLock, Contest, ContestParticipation, \
ContestTag, Judge, Language, License, MiscConfig, NavigationBar, Organization, \
OrganizationRequest, Problem, ProblemGroup, ProblemPointsVote, ProblemType, Profile, Submission, Ticket, \
VolunteerProblemVote
from judge.models import (
BlogPost,
Comment,
CommentLock,
Contest,
ContestParticipation,
ContestTag,
Judge,
Language,
License,
MiscConfig,
NavigationBar,
Organization,
OrganizationRequest,
Problem,
ProblemGroup,
ProblemPointsVote,
ProblemType,
Profile,
Submission,
Ticket,
VolunteerProblemVote,
)
admin.site.register(BlogPost, BlogPostAdmin)
@ -39,4 +63,4 @@ admin.site.register(ProblemType, ProblemTypeAdmin)
admin.site.register(Profile, ProfileAdmin)
admin.site.register(Submission, SubmissionAdmin)
admin.site.register(Ticket, TicketAdmin)
admin.site.register(VolunteerProblemVote, VolunteerProblemVoteAdmin)
admin.site.register(VolunteerProblemVote, VolunteerProblemVoteAdmin)

View file

@ -11,53 +11,70 @@ from judge.widgets import AdminHeavySelect2Widget, HeavyPreviewAdminPageDownWidg
class CommentForm(ModelForm):
class Meta:
widgets = {
'author': AdminHeavySelect2Widget(data_view='profile_select2'),
'parent': AdminHeavySelect2Widget(data_view='comment_select2'),
"author": AdminHeavySelect2Widget(data_view="profile_select2"),
"parent": AdminHeavySelect2Widget(data_view="comment_select2"),
}
if HeavyPreviewAdminPageDownWidget is not None:
widgets['body'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('comment_preview'))
widgets["body"] = HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("comment_preview")
)
class CommentAdmin(VersionAdmin):
fieldsets = (
(None, {'fields': ('author', 'page', 'parent', 'score', 'hidden')}),
('Content', {'fields': ('body',)}),
(None, {"fields": ("author", "page", "parent", "score", "hidden")}),
("Content", {"fields": ("body",)}),
)
list_display = ['author', 'linked_page', 'time']
search_fields = ['author__user__username', 'page', 'body']
readonly_fields = ['score']
actions = ['hide_comment', 'unhide_comment']
list_filter = ['hidden']
list_display = ["author", "linked_page", "time"]
search_fields = ["author__user__username", "page", "body"]
readonly_fields = ["score"]
actions = ["hide_comment", "unhide_comment"]
list_filter = ["hidden"]
actions_on_top = True
actions_on_bottom = True
form = CommentForm
date_hierarchy = 'time'
date_hierarchy = "time"
def get_queryset(self, request):
return Comment.objects.order_by('-time')
return Comment.objects.order_by("-time")
def hide_comment(self, request, queryset):
count = queryset.update(hidden=True)
self.message_user(request, ungettext('%d comment successfully hidden.',
'%d comments successfully hidden.',
count) % count)
hide_comment.short_description = _('Hide comments')
self.message_user(
request,
ungettext(
"%d comment successfully hidden.",
"%d comments successfully hidden.",
count,
)
% count,
)
hide_comment.short_description = _("Hide comments")
def unhide_comment(self, request, queryset):
count = queryset.update(hidden=False)
self.message_user(request, ungettext('%d comment successfully unhidden.',
'%d comments successfully unhidden.',
count) % count)
unhide_comment.short_description = _('Unhide comments')
self.message_user(
request,
ungettext(
"%d comment successfully unhidden.",
"%d comments successfully unhidden.",
count,
)
% count,
)
unhide_comment.short_description = _("Unhide comments")
def linked_page(self, obj):
link = obj.link
if link is not None:
return format_html('<a href="{0}">{1}</a>', link, obj.page)
else:
return format_html('{0}', obj.page)
linked_page.short_description = _('Associated page')
linked_page.admin_order_field = 'page'
return format_html("{0}", obj.page)
linked_page.short_description = _("Associated page")
linked_page.admin_order_field = "page"
def save_model(self, request, obj, form, change):
super(CommentAdmin, self).save_model(request, obj, form, change)

View file

@ -16,8 +16,14 @@ from reversion_compare.admin import CompareVersionAdmin
from django_ace import AceWidget
from judge.models import Contest, ContestProblem, ContestSubmission, Profile, Rating
from judge.ratings import rate_contest
from judge.widgets import AdminHeavySelect2MultipleWidget, AdminHeavySelect2Widget, AdminPagedownWidget, \
AdminSelect2MultipleWidget, AdminSelect2Widget, HeavyPreviewAdminPageDownWidget
from judge.widgets import (
AdminHeavySelect2MultipleWidget,
AdminHeavySelect2Widget,
AdminPagedownWidget,
AdminSelect2MultipleWidget,
AdminSelect2Widget,
HeavyPreviewAdminPageDownWidget,
)
class AdminHeavySelect2Widget(AdminHeavySelect2Widget):
@ -28,159 +34,252 @@ class AdminHeavySelect2Widget(AdminHeavySelect2Widget):
class ContestTagForm(ModelForm):
contests = ModelMultipleChoiceField(
label=_('Included contests'),
label=_("Included contests"),
queryset=Contest.objects.all(),
required=False,
widget=AdminHeavySelect2MultipleWidget(data_view='contest_select2'))
widget=AdminHeavySelect2MultipleWidget(data_view="contest_select2"),
)
class ContestTagAdmin(admin.ModelAdmin):
fields = ('name', 'color', 'description', 'contests')
list_display = ('name', 'color')
fields = ("name", "color", "description", "contests")
list_display = ("name", "color")
actions_on_top = True
actions_on_bottom = True
form = ContestTagForm
if AdminPagedownWidget is not None:
formfield_overrides = {
TextField: {'widget': AdminPagedownWidget},
TextField: {"widget": AdminPagedownWidget},
}
def save_model(self, request, obj, form, change):
super(ContestTagAdmin, self).save_model(request, obj, form, change)
obj.contests.set(form.cleaned_data['contests'])
obj.contests.set(form.cleaned_data["contests"])
def get_form(self, request, obj=None, **kwargs):
form = super(ContestTagAdmin, self).get_form(request, obj, **kwargs)
if obj is not None:
form.base_fields['contests'].initial = obj.contests.all()
form.base_fields["contests"].initial = obj.contests.all()
return form
class ContestProblemInlineForm(ModelForm):
class Meta:
widgets = {'problem': AdminHeavySelect2Widget(data_view='problem_select2')}
widgets = {"problem": AdminHeavySelect2Widget(data_view="problem_select2")}
class ContestProblemInline(admin.TabularInline):
model = ContestProblem
verbose_name = _('Problem')
verbose_name_plural = 'Problems'
fields = ('problem', 'points', 'partial', 'is_pretested', 'max_submissions', 'output_prefix_override', 'order',
'rejudge_column')
readonly_fields = ('rejudge_column',)
verbose_name = _("Problem")
verbose_name_plural = "Problems"
fields = (
"problem",
"points",
"partial",
"is_pretested",
"max_submissions",
"output_prefix_override",
"order",
"rejudge_column",
)
readonly_fields = ("rejudge_column",)
form = ContestProblemInlineForm
def rejudge_column(self, obj):
if obj.id is None:
return ''
return format_html('<a class="button rejudge-link" href="{}">Rejudge</a>',
reverse('admin:judge_contest_rejudge', args=(obj.contest.id, obj.id)))
rejudge_column.short_description = ''
return ""
return format_html(
'<a class="button rejudge-link" href="{}">Rejudge</a>',
reverse("admin:judge_contest_rejudge", args=(obj.contest.id, obj.id)),
)
rejudge_column.short_description = ""
class ContestForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ContestForm, self).__init__(*args, **kwargs)
if 'rate_exclude' in self.fields:
if "rate_exclude" in self.fields:
if self.instance and self.instance.id:
self.fields['rate_exclude'].queryset = \
Profile.objects.filter(contest_history__contest=self.instance).distinct()
self.fields["rate_exclude"].queryset = Profile.objects.filter(
contest_history__contest=self.instance
).distinct()
else:
self.fields['rate_exclude'].queryset = Profile.objects.none()
self.fields['banned_users'].widget.can_add_related = False
self.fields['view_contest_scoreboard'].widget.can_add_related = False
self.fields["rate_exclude"].queryset = Profile.objects.none()
self.fields["banned_users"].widget.can_add_related = False
self.fields["view_contest_scoreboard"].widget.can_add_related = False
def clean(self):
cleaned_data = super(ContestForm, self).clean()
cleaned_data['banned_users'].filter(current_contest__contest=self.instance).update(current_contest=None)
cleaned_data["banned_users"].filter(
current_contest__contest=self.instance
).update(current_contest=None)
class Meta:
widgets = {
'authors': AdminHeavySelect2MultipleWidget(data_view='profile_select2'),
'curators': AdminHeavySelect2MultipleWidget(data_view='profile_select2'),
'testers': AdminHeavySelect2MultipleWidget(data_view='profile_select2'),
'private_contestants': AdminHeavySelect2MultipleWidget(data_view='profile_select2',
attrs={'style': 'width: 100%'}),
'organizations': AdminHeavySelect2MultipleWidget(data_view='organization_select2'),
'tags': AdminSelect2MultipleWidget,
'banned_users': AdminHeavySelect2MultipleWidget(data_view='profile_select2',
attrs={'style': 'width: 100%'}),
'view_contest_scoreboard': AdminHeavySelect2MultipleWidget(data_view='profile_select2',
attrs={'style': 'width: 100%'}),
"authors": AdminHeavySelect2MultipleWidget(data_view="profile_select2"),
"curators": AdminHeavySelect2MultipleWidget(data_view="profile_select2"),
"testers": AdminHeavySelect2MultipleWidget(data_view="profile_select2"),
"private_contestants": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
"organizations": AdminHeavySelect2MultipleWidget(
data_view="organization_select2"
),
"tags": AdminSelect2MultipleWidget,
"banned_users": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
"view_contest_scoreboard": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
}
if HeavyPreviewAdminPageDownWidget is not None:
widgets['description'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('contest_preview'))
widgets["description"] = HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("contest_preview")
)
class ContestAdmin(CompareVersionAdmin):
fieldsets = (
(None, {'fields': ('key', 'name', 'authors', 'curators', 'testers')}),
(_('Settings'), {'fields': ('is_visible', 'use_clarifications', 'hide_problem_tags', 'scoreboard_visibility',
'run_pretests_only', 'points_precision')}),
(_('Scheduling'), {'fields': ('start_time', 'end_time', 'time_limit')}),
(_('Details'), {'fields': ('description', 'og_image', 'logo_override_image', 'tags', 'summary')}),
(_('Format'), {'fields': ('format_name', 'format_config', 'problem_label_script')}),
(_('Rating'), {'fields': ('is_rated', 'rate_all', 'rating_floor', 'rating_ceiling', 'rate_exclude')}),
(_('Access'), {'fields': ('access_code', 'is_private', 'private_contestants', 'is_organization_private',
'organizations', 'view_contest_scoreboard')}),
(_('Justice'), {'fields': ('banned_users',)}),
(None, {"fields": ("key", "name", "authors", "curators", "testers")}),
(
_("Settings"),
{
"fields": (
"is_visible",
"use_clarifications",
"hide_problem_tags",
"scoreboard_visibility",
"run_pretests_only",
"points_precision",
)
},
),
(_("Scheduling"), {"fields": ("start_time", "end_time", "time_limit")}),
(
_("Details"),
{
"fields": (
"description",
"og_image",
"logo_override_image",
"tags",
"summary",
)
},
),
(
_("Format"),
{"fields": ("format_name", "format_config", "problem_label_script")},
),
(
_("Rating"),
{
"fields": (
"is_rated",
"rate_all",
"rating_floor",
"rating_ceiling",
"rate_exclude",
)
},
),
(
_("Access"),
{
"fields": (
"access_code",
"is_private",
"private_contestants",
"is_organization_private",
"organizations",
"view_contest_scoreboard",
)
},
),
(_("Justice"), {"fields": ("banned_users",)}),
)
list_display = ('key', 'name', 'is_visible', 'is_rated', 'start_time', 'end_time', 'time_limit', 'user_count')
search_fields = ('key', 'name')
list_display = (
"key",
"name",
"is_visible",
"is_rated",
"start_time",
"end_time",
"time_limit",
"user_count",
)
search_fields = ("key", "name")
inlines = [ContestProblemInline]
actions_on_top = True
actions_on_bottom = True
form = ContestForm
change_list_template = 'admin/judge/contest/change_list.html'
filter_horizontal = ['rate_exclude']
date_hierarchy = 'start_time'
change_list_template = "admin/judge/contest/change_list.html"
filter_horizontal = ["rate_exclude"]
date_hierarchy = "start_time"
def get_actions(self, request):
actions = super(ContestAdmin, self).get_actions(request)
if request.user.has_perm('judge.change_contest_visibility') or \
request.user.has_perm('judge.create_private_contest'):
for action in ('make_visible', 'make_hidden'):
if request.user.has_perm(
"judge.change_contest_visibility"
) or request.user.has_perm("judge.create_private_contest"):
for action in ("make_visible", "make_hidden"):
actions[action] = self.get_action(action)
return actions
def get_queryset(self, request):
queryset = Contest.objects.all()
if request.user.has_perm('judge.edit_all_contest'):
if request.user.has_perm("judge.edit_all_contest"):
return queryset
else:
return queryset.filter(Q(authors=request.profile) | Q(curators=request.profile)).distinct()
return queryset.filter(
Q(authors=request.profile) | Q(curators=request.profile)
).distinct()
def get_readonly_fields(self, request, obj=None):
readonly = []
if not request.user.has_perm('judge.contest_rating'):
readonly += ['is_rated', 'rate_all', 'rate_exclude']
if not request.user.has_perm('judge.contest_access_code'):
readonly += ['access_code']
if not request.user.has_perm('judge.create_private_contest'):
readonly += ['is_private', 'private_contestants', 'is_organization_private', 'organizations']
if not request.user.has_perm('judge.change_contest_visibility'):
readonly += ['is_visible']
if not request.user.has_perm('judge.contest_problem_label'):
readonly += ['problem_label_script']
if not request.user.has_perm("judge.contest_rating"):
readonly += ["is_rated", "rate_all", "rate_exclude"]
if not request.user.has_perm("judge.contest_access_code"):
readonly += ["access_code"]
if not request.user.has_perm("judge.create_private_contest"):
readonly += [
"is_private",
"private_contestants",
"is_organization_private",
"organizations",
]
if not request.user.has_perm("judge.change_contest_visibility"):
readonly += ["is_visible"]
if not request.user.has_perm("judge.contest_problem_label"):
readonly += ["problem_label_script"]
return readonly
def save_model(self, request, obj, form, change):
# `is_visible` will not appear in `cleaned_data` if user cannot edit it
if form.cleaned_data.get('is_visible') and not request.user.has_perm('judge.change_contest_visibility'):
if not form.cleaned_data['is_private'] and not form.cleaned_data['is_organization_private']:
if form.cleaned_data.get("is_visible") and not request.user.has_perm(
"judge.change_contest_visibility"
):
if (
not form.cleaned_data["is_private"]
and not form.cleaned_data["is_organization_private"]
):
raise PermissionDenied
if not request.user.has_perm('judge.create_private_contest'):
if not request.user.has_perm("judge.create_private_contest"):
raise PermissionDenied
super().save_model(request, obj, form, change)
# We need this flag because `save_related` deals with the inlines, but does not know if we have already rescored
self._rescored = False
if form.changed_data and any(f in form.changed_data for f in ('format_config', 'format_name')):
if form.changed_data and any(
f in form.changed_data for f in ("format_config", "format_name")
):
self._rescore(obj.key)
self._rescored = True
@ -188,10 +287,10 @@ class ContestAdmin(CompareVersionAdmin):
super().save_related(request, form, formsets, change)
# Only rescored if we did not already do so in `save_model`
if not self._rescored and any(formset.has_changed() for formset in formsets):
self._rescore(form.cleaned_data['key'])
self._rescore(form.cleaned_data["key"])
def has_change_permission(self, request, obj=None):
if not request.user.has_perm('judge.edit_own_contest'):
if not request.user.has_perm("judge.edit_own_contest"):
return False
if obj is None:
return True
@ -199,76 +298,113 @@ class ContestAdmin(CompareVersionAdmin):
def _rescore(self, contest_key):
from judge.tasks import rescore_contest
transaction.on_commit(rescore_contest.s(contest_key).delay)
def make_visible(self, request, queryset):
if not request.user.has_perm('judge.change_contest_visibility'):
queryset = queryset.filter(Q(is_private=True) | Q(is_organization_private=True))
if not request.user.has_perm("judge.change_contest_visibility"):
queryset = queryset.filter(
Q(is_private=True) | Q(is_organization_private=True)
)
count = queryset.update(is_visible=True)
self.message_user(request, ungettext('%d contest successfully marked as visible.',
'%d contests successfully marked as visible.',
count) % count)
make_visible.short_description = _('Mark contests as visible')
self.message_user(
request,
ungettext(
"%d contest successfully marked as visible.",
"%d contests successfully marked as visible.",
count,
)
% count,
)
make_visible.short_description = _("Mark contests as visible")
def make_hidden(self, request, queryset):
if not request.user.has_perm('judge.change_contest_visibility'):
queryset = queryset.filter(Q(is_private=True) | Q(is_organization_private=True))
if not request.user.has_perm("judge.change_contest_visibility"):
queryset = queryset.filter(
Q(is_private=True) | Q(is_organization_private=True)
)
count = queryset.update(is_visible=True)
self.message_user(request, ungettext('%d contest successfully marked as hidden.',
'%d contests successfully marked as hidden.',
count) % count)
make_hidden.short_description = _('Mark contests as hidden')
self.message_user(
request,
ungettext(
"%d contest successfully marked as hidden.",
"%d contests successfully marked as hidden.",
count,
)
% count,
)
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'),
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):
queryset = ContestSubmission.objects.filter(problem_id=problem_id).select_related('submission')
queryset = ContestSubmission.objects.filter(
problem_id=problem_id
).select_related("submission")
for model in queryset:
model.submission.judge(rejudge=True)
self.message_user(request, ungettext('%d submission was successfully scheduled for rejudging.',
'%d submissions were successfully scheduled for rejudging.',
len(queryset)) % len(queryset))
return HttpResponseRedirect(reverse('admin:judge_contest_change', args=(contest_id,)))
self.message_user(
request,
ungettext(
"%d submission was successfully scheduled for rejudging.",
"%d submissions were successfully scheduled for rejudging.",
len(queryset),
)
% len(queryset),
)
return HttpResponseRedirect(
reverse("admin:judge_contest_change", args=(contest_id,))
)
def rate_all_view(self, request):
if not request.user.has_perm('judge.contest_rating'):
if not request.user.has_perm("judge.contest_rating"):
raise PermissionDenied()
with transaction.atomic():
with connection.cursor() as cursor:
cursor.execute('TRUNCATE TABLE `%s`' % Rating._meta.db_table)
cursor.execute("TRUNCATE TABLE `%s`" % Rating._meta.db_table)
Profile.objects.update(rating=None)
for contest in Contest.objects.filter(is_rated=True, end_time__lte=timezone.now()).order_by('end_time'):
for contest in Contest.objects.filter(
is_rated=True, end_time__lte=timezone.now()
).order_by("end_time"):
rate_contest(contest)
return HttpResponseRedirect(reverse('admin:judge_contest_changelist'))
return HttpResponseRedirect(reverse("admin:judge_contest_changelist"))
def rate_view(self, request, id):
if not request.user.has_perm('judge.contest_rating'):
if not request.user.has_perm("judge.contest_rating"):
raise PermissionDenied()
contest = get_object_or_404(Contest, id=id)
if not contest.is_rated or not contest.ended:
raise Http404()
with transaction.atomic():
contest.rate()
return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('admin:judge_contest_changelist')))
return HttpResponseRedirect(
request.META.get("HTTP_REFERER", reverse("admin:judge_contest_changelist"))
)
def get_form(self, request, obj=None, **kwargs):
form = super(ContestAdmin, self).get_form(request, obj, **kwargs)
if 'problem_label_script' in form.base_fields:
if "problem_label_script" in form.base_fields:
# form.base_fields['problem_label_script'] does not exist when the user has only view permission
# on the model.
form.base_fields['problem_label_script'].widget = AceWidget('lua', request.profile.ace_theme)
perms = ('edit_own_contest', 'edit_all_contest')
form.base_fields['curators'].queryset = Profile.objects.filter(
Q(user__is_superuser=True) |
Q(user__groups__permissions__codename__in=perms) |
Q(user__user_permissions__codename__in=perms),
form.base_fields["problem_label_script"].widget = AceWidget(
"lua", request.profile.ace_theme
)
perms = ("edit_own_contest", "edit_all_contest")
form.base_fields["curators"].queryset = Profile.objects.filter(
Q(user__is_superuser=True)
| Q(user__groups__permissions__codename__in=perms)
| Q(user__user_permissions__codename__in=perms),
).distinct()
return form
@ -276,29 +412,48 @@ class ContestAdmin(CompareVersionAdmin):
class ContestParticipationForm(ModelForm):
class Meta:
widgets = {
'contest': AdminSelect2Widget(),
'user': AdminHeavySelect2Widget(data_view='profile_select2'),
"contest": AdminSelect2Widget(),
"user": AdminHeavySelect2Widget(data_view="profile_select2"),
}
class ContestParticipationAdmin(admin.ModelAdmin):
fields = ('contest', 'user', 'real_start', 'virtual', 'is_disqualified')
list_display = ('contest', 'username', 'show_virtual', 'real_start', 'score', 'cumtime', 'tiebreaker')
actions = ['recalculate_results']
fields = ("contest", "user", "real_start", "virtual", "is_disqualified")
list_display = (
"contest",
"username",
"show_virtual",
"real_start",
"score",
"cumtime",
"tiebreaker",
)
actions = ["recalculate_results"]
actions_on_bottom = actions_on_top = True
search_fields = ('contest__key', 'contest__name', 'user__user__username')
search_fields = ("contest__key", "contest__name", "user__user__username")
form = ContestParticipationForm
date_hierarchy = 'real_start'
date_hierarchy = "real_start"
def get_queryset(self, request):
return super(ContestParticipationAdmin, self).get_queryset(request).only(
'contest__name', 'contest__format_name', 'contest__format_config',
'user__user__username', 'real_start', 'score', 'cumtime', 'tiebreaker', 'virtual',
return (
super(ContestParticipationAdmin, self)
.get_queryset(request)
.only(
"contest__name",
"contest__format_name",
"contest__format_config",
"user__user__username",
"real_start",
"score",
"cumtime",
"tiebreaker",
"virtual",
)
)
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
if form.changed_data and 'is_disqualified' in form.changed_data:
if form.changed_data and "is_disqualified" in form.changed_data:
obj.set_disqualified(obj.is_disqualified)
def recalculate_results(self, request, queryset):
@ -306,17 +461,26 @@ class ContestParticipationAdmin(admin.ModelAdmin):
for participation in queryset:
participation.recompute_results()
count += 1
self.message_user(request, ungettext('%d participation recalculated.',
'%d participations recalculated.',
count) % count)
recalculate_results.short_description = _('Recalculate results')
self.message_user(
request,
ungettext(
"%d participation recalculated.",
"%d participations recalculated.",
count,
)
% count,
)
recalculate_results.short_description = _("Recalculate results")
def username(self, obj):
return obj.user.username
username.short_description = _('username')
username.admin_order_field = 'user__user__username'
username.short_description = _("username")
username.admin_order_field = "user__user__username"
def show_virtual(self, obj):
return obj.virtual or '-'
show_virtual.short_description = _('virtual')
show_virtual.admin_order_field = 'virtual'
return obj.virtual or "-"
show_virtual.short_description = _("virtual")
show_virtual.admin_order_field = "virtual"

View file

@ -11,23 +11,28 @@ from reversion_compare.admin import CompareVersionAdmin
from judge.dblock import LockModel
from judge.models import NavigationBar
from judge.widgets import AdminHeavySelect2MultipleWidget, AdminHeavySelect2Widget, HeavyPreviewAdminPageDownWidget
from judge.widgets import (
AdminHeavySelect2MultipleWidget,
AdminHeavySelect2Widget,
HeavyPreviewAdminPageDownWidget,
)
class NavigationBarAdmin(DraggableMPTTAdmin):
list_display = DraggableMPTTAdmin.list_display + ('key', 'linked_path')
fields = ('key', 'label', 'path', 'order', 'regex', 'parent')
list_display = DraggableMPTTAdmin.list_display + ("key", "linked_path")
fields = ("key", "label", "path", "order", "regex", "parent")
list_editable = () # Bug in SortableModelAdmin: 500 without list_editable being set
mptt_level_indent = 20
sortable = 'order'
sortable = "order"
def __init__(self, *args, **kwargs):
super(NavigationBarAdmin, self).__init__(*args, **kwargs)
self.__save_model_calls = 0
def linked_path(self, obj):
return format_html(u'<a href="{0}" target="_blank">{0}</a>', obj.path)
linked_path.short_description = _('link path')
return format_html('<a href="{0}" target="_blank">{0}</a>', obj.path)
linked_path.short_description = _("link path")
def save_model(self, request, obj, form, change):
self.__save_model_calls += 1
@ -36,7 +41,9 @@ class NavigationBarAdmin(DraggableMPTTAdmin):
def changelist_view(self, request, extra_context=None):
self.__save_model_calls = 0
with NavigationBar.objects.disable_mptt_updates():
result = super(NavigationBarAdmin, self).changelist_view(request, extra_context)
result = super(NavigationBarAdmin, self).changelist_view(
request, extra_context
)
if self.__save_model_calls:
with LockModel(write=(NavigationBar,)):
NavigationBar.objects.rebuild()
@ -46,74 +53,105 @@ class NavigationBarAdmin(DraggableMPTTAdmin):
class BlogPostForm(ModelForm):
def __init__(self, *args, **kwargs):
super(BlogPostForm, self).__init__(*args, **kwargs)
self.fields['authors'].widget.can_add_related = False
self.fields["authors"].widget.can_add_related = False
class Meta:
widgets = {
'authors': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
'organizations': AdminHeavySelect2MultipleWidget(data_view='organization_select2',
attrs={'style': 'width: 100%'}),
"authors": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
"organizations": AdminHeavySelect2MultipleWidget(
data_view="organization_select2", attrs={"style": "width: 100%"}
),
}
if HeavyPreviewAdminPageDownWidget is not None:
widgets['content'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('blog_preview'))
widgets['summary'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('blog_preview'))
widgets["content"] = HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("blog_preview")
)
widgets["summary"] = HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("blog_preview")
)
class BlogPostAdmin(CompareVersionAdmin):
fieldsets = (
(None, {'fields': ('title', 'slug', 'authors', 'visible', 'sticky', 'publish_on',
'is_organization_private', 'organizations')}),
(_('Content'), {'fields': ('content', 'og_image')}),
(_('Summary'), {'classes': ('collapse',), 'fields': ('summary',)}),
(
None,
{
"fields": (
"title",
"slug",
"authors",
"visible",
"sticky",
"publish_on",
"is_organization_private",
"organizations",
)
},
),
(_("Content"), {"fields": ("content", "og_image")}),
(_("Summary"), {"classes": ("collapse",), "fields": ("summary",)}),
)
prepopulated_fields = {'slug': ('title',)}
list_display = ('id', 'title', 'visible', 'sticky', 'publish_on')
list_display_links = ('id', 'title')
ordering = ('-publish_on',)
prepopulated_fields = {"slug": ("title",)}
list_display = ("id", "title", "visible", "sticky", "publish_on")
list_display_links = ("id", "title")
ordering = ("-publish_on",)
form = BlogPostForm
date_hierarchy = 'publish_on'
date_hierarchy = "publish_on"
def has_change_permission(self, request, obj=None):
return (request.user.has_perm('judge.edit_all_post') or
request.user.has_perm('judge.change_blogpost') and (
obj is None or
obj.authors.filter(id=request.profile.id).exists()))
return (
request.user.has_perm("judge.edit_all_post")
or request.user.has_perm("judge.change_blogpost")
and (obj is None or obj.authors.filter(id=request.profile.id).exists())
)
class SolutionForm(ModelForm):
def __init__(self, *args, **kwargs):
super(SolutionForm, self).__init__(*args, **kwargs)
self.fields['authors'].widget.can_add_related = False
self.fields["authors"].widget.can_add_related = False
class Meta:
widgets = {
'authors': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
'problem': AdminHeavySelect2Widget(data_view='problem_select2', attrs={'style': 'width: 250px'}),
"authors": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
"problem": AdminHeavySelect2Widget(
data_view="problem_select2", attrs={"style": "width: 250px"}
),
}
if HeavyPreviewAdminPageDownWidget is not None:
widgets['content'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('solution_preview'))
widgets["content"] = HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("solution_preview")
)
class LicenseForm(ModelForm):
class Meta:
if HeavyPreviewAdminPageDownWidget is not None:
widgets = {'text': HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('license_preview'))}
widgets = {
"text": HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("license_preview")
)
}
class LicenseAdmin(admin.ModelAdmin):
fields = ('key', 'link', 'name', 'display', 'icon', 'text')
list_display = ('name', 'key')
fields = ("key", "link", "name", "display", "icon", "text")
list_display = ("name", "key")
form = LicenseForm
class UserListFilter(admin.SimpleListFilter):
title = _('user')
parameter_name = 'user'
title = _("user")
parameter_name = "user"
def lookups(self, request, model_admin):
return User.objects.filter(is_staff=True).values_list('id', 'username')
return User.objects.filter(is_staff=True).values_list("id", "username")
def queryset(self, request, queryset):
if self.value():
@ -122,10 +160,24 @@ class UserListFilter(admin.SimpleListFilter):
class LogEntryAdmin(admin.ModelAdmin):
readonly_fields = ('user', 'content_type', 'object_id', 'object_repr', 'action_flag', 'change_message')
list_display = ('__str__', 'action_time', 'user', 'content_type', 'object_link', 'diff_link')
search_fields = ('object_repr', 'change_message')
list_filter = (UserListFilter, 'content_type')
readonly_fields = (
"user",
"content_type",
"object_id",
"object_repr",
"action_flag",
"change_message",
)
list_display = (
"__str__",
"action_time",
"user",
"content_type",
"object_link",
"diff_link",
)
search_fields = ("object_repr", "change_message")
list_filter = (UserListFilter, "content_type")
list_display_links = None
actions = None
@ -144,25 +196,35 @@ class LogEntryAdmin(admin.ModelAdmin):
else:
ct = obj.content_type
try:
link = format_html('<a href="{1}">{0}</a>', obj.object_repr,
reverse('admin:%s_%s_change' % (ct.app_label, ct.model), args=(obj.object_id,)))
link = format_html(
'<a href="{1}">{0}</a>',
obj.object_repr,
reverse(
"admin:%s_%s_change" % (ct.app_label, ct.model),
args=(obj.object_id,),
),
)
except NoReverseMatch:
link = obj.object_repr
return link
object_link.admin_order_field = 'object_repr'
object_link.short_description = _('object')
object_link.admin_order_field = "object_repr"
object_link.short_description = _("object")
def diff_link(self, obj):
if obj.is_deletion():
return None
ct = obj.content_type
try:
url = reverse('admin:%s_%s_history' % (ct.app_label, ct.model), args=(obj.object_id,))
link = format_html('<a href="{1}">{0}</a>', _('Diff'), url)
url = reverse(
"admin:%s_%s_history" % (ct.app_label, ct.model), args=(obj.object_id,)
)
link = format_html('<a href="{1}">{0}</a>', _("Diff"), url)
except NoReverseMatch:
link = None
return link
diff_link.short_description = _('diff')
diff_link.short_description = _("diff")
def queryset(self, request):
return super().queryset(request).prefetch_related('content_type')
return super().queryset(request).prefetch_related("content_type")

View file

@ -6,61 +6,88 @@ from django.utils.translation import gettext, gettext_lazy as _
from reversion.admin import VersionAdmin
from judge.models import Organization
from judge.widgets import AdminHeavySelect2MultipleWidget, AdminHeavySelect2Widget, HeavyPreviewAdminPageDownWidget
from judge.widgets import (
AdminHeavySelect2MultipleWidget,
AdminHeavySelect2Widget,
HeavyPreviewAdminPageDownWidget,
)
class OrganizationForm(ModelForm):
class Meta:
widgets = {
'admins': AdminHeavySelect2MultipleWidget(data_view='profile_select2'),
'registrant': AdminHeavySelect2Widget(data_view='profile_select2'),
"admins": AdminHeavySelect2MultipleWidget(data_view="profile_select2"),
"registrant": AdminHeavySelect2Widget(data_view="profile_select2"),
}
if HeavyPreviewAdminPageDownWidget is not None:
widgets['about'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('organization_preview'))
widgets["about"] = HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("organization_preview")
)
class OrganizationAdmin(VersionAdmin):
readonly_fields = ('creation_date',)
fields = ('name', 'slug', 'short_name', 'is_open', 'about', 'logo_override_image', 'slots', 'registrant',
'creation_date', 'admins')
list_display = ('name', 'short_name', 'is_open', 'slots', 'registrant', 'show_public')
prepopulated_fields = {'slug': ('name',)}
readonly_fields = ("creation_date",)
fields = (
"name",
"slug",
"short_name",
"is_open",
"about",
"logo_override_image",
"slots",
"registrant",
"creation_date",
"admins",
)
list_display = (
"name",
"short_name",
"is_open",
"slots",
"registrant",
"show_public",
)
prepopulated_fields = {"slug": ("name",)}
actions_on_top = True
actions_on_bottom = True
form = OrganizationForm
def show_public(self, obj):
return format_html('<a href="{0}" style="white-space:nowrap;">{1}</a>',
obj.get_absolute_url(), gettext('View on site'))
return format_html(
'<a href="{0}" style="white-space:nowrap;">{1}</a>',
obj.get_absolute_url(),
gettext("View on site"),
)
show_public.short_description = ''
show_public.short_description = ""
def get_readonly_fields(self, request, obj=None):
fields = self.readonly_fields
if not request.user.has_perm('judge.organization_admin'):
return fields + ('registrant', 'admins', 'is_open', 'slots')
if not request.user.has_perm("judge.organization_admin"):
return fields + ("registrant", "admins", "is_open", "slots")
return fields
def get_queryset(self, request):
queryset = Organization.objects.all()
if request.user.has_perm('judge.edit_all_organization'):
if request.user.has_perm("judge.edit_all_organization"):
return queryset
else:
return queryset.filter(admins=request.profile.id)
def has_change_permission(self, request, obj=None):
if not request.user.has_perm('judge.change_organization'):
if not request.user.has_perm("judge.change_organization"):
return False
if request.user.has_perm('judge.edit_all_organization') or obj is None:
if request.user.has_perm("judge.edit_all_organization") or obj is None:
return True
return obj.admins.filter(id=request.profile.id).exists()
class OrganizationRequestAdmin(admin.ModelAdmin):
list_display = ('username', 'organization', 'state', 'time')
readonly_fields = ('user', 'organization')
list_display = ("username", "organization", "state", "time")
readonly_fields = ("user", "organization")
def username(self, obj):
return obj.user.user.username
username.short_description = _('username')
username.admin_order_field = 'user__user__username'
username.short_description = _("username")
username.admin_order_field = "user__user__username"

View file

@ -14,45 +14,74 @@ from reversion.admin import VersionAdmin
from reversion_compare.admin import CompareVersionAdmin
from judge.models import LanguageLimit, Problem, ProblemClarification, ProblemTranslation, Profile, Solution
from judge.widgets import AdminHeavySelect2MultipleWidget, AdminSelect2MultipleWidget, AdminSelect2Widget, \
CheckboxSelectMultipleWithSelectAll, HeavyPreviewAdminPageDownWidget, HeavyPreviewPageDownWidget
from judge.models import (
LanguageLimit,
Problem,
ProblemClarification,
ProblemTranslation,
Profile,
Solution,
)
from judge.widgets import (
AdminHeavySelect2MultipleWidget,
AdminSelect2MultipleWidget,
AdminSelect2Widget,
CheckboxSelectMultipleWithSelectAll,
HeavyPreviewAdminPageDownWidget,
HeavyPreviewPageDownWidget,
)
class ProblemForm(ModelForm):
change_message = forms.CharField(max_length=256, label='Edit reason', required=False)
change_message = forms.CharField(
max_length=256, label="Edit reason", required=False
)
def __init__(self, *args, **kwargs):
super(ProblemForm, self).__init__(*args, **kwargs)
self.fields['authors'].widget.can_add_related = False
self.fields['curators'].widget.can_add_related = False
self.fields['testers'].widget.can_add_related = False
self.fields['banned_users'].widget.can_add_related = False
self.fields['change_message'].widget.attrs.update({
'placeholder': gettext('Describe the changes you made (optional)'),
})
self.fields["authors"].widget.can_add_related = False
self.fields["curators"].widget.can_add_related = False
self.fields["testers"].widget.can_add_related = False
self.fields["banned_users"].widget.can_add_related = False
self.fields["change_message"].widget.attrs.update(
{
"placeholder": gettext("Describe the changes you made (optional)"),
}
)
class Meta:
widgets = {
'authors': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
'curators': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
'testers': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
'banned_users': AdminHeavySelect2MultipleWidget(data_view='profile_select2',
attrs={'style': 'width: 100%'}),
'organizations': AdminHeavySelect2MultipleWidget(data_view='organization_select2',
attrs={'style': 'width: 100%'}),
'types': AdminSelect2MultipleWidget,
'group': AdminSelect2Widget,
"authors": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
"curators": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
"testers": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
"banned_users": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
"organizations": AdminHeavySelect2MultipleWidget(
data_view="organization_select2", attrs={"style": "width: 100%"}
),
"types": AdminSelect2MultipleWidget,
"group": AdminSelect2Widget,
}
if HeavyPreviewAdminPageDownWidget is not None:
widgets['description'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('problem_preview'))
widgets["description"] = HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("problem_preview")
)
class ProblemCreatorListFilter(admin.SimpleListFilter):
title = parameter_name = 'creator'
title = parameter_name = "creator"
def lookups(self, request, model_admin):
queryset = 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):
@ -63,24 +92,28 @@ class ProblemCreatorListFilter(admin.SimpleListFilter):
class LanguageLimitInlineForm(ModelForm):
class Meta:
widgets = {'language': AdminSelect2Widget}
widgets = {"language": AdminSelect2Widget}
class LanguageLimitInline(admin.TabularInline):
model = LanguageLimit
fields = ('language', 'time_limit', 'memory_limit')
fields = ("language", "time_limit", "memory_limit")
form = LanguageLimitInlineForm
class ProblemClarificationForm(ModelForm):
class Meta:
if HeavyPreviewPageDownWidget is not None:
widgets = {'description': HeavyPreviewPageDownWidget(preview=reverse_lazy('comment_preview'))}
widgets = {
"description": HeavyPreviewPageDownWidget(
preview=reverse_lazy("comment_preview")
)
}
class ProblemClarificationInline(admin.StackedInline):
model = ProblemClarification
fields = ('description',)
fields = ("description",)
form = ProblemClarificationForm
extra = 0
@ -88,20 +121,24 @@ class ProblemClarificationInline(admin.StackedInline):
class ProblemSolutionForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ProblemSolutionForm, self).__init__(*args, **kwargs)
self.fields['authors'].widget.can_add_related = False
self.fields["authors"].widget.can_add_related = False
class Meta:
widgets = {
'authors': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
"authors": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
}
if HeavyPreviewAdminPageDownWidget is not None:
widgets['content'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('solution_preview'))
widgets["content"] = HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("solution_preview")
)
class ProblemSolutionInline(admin.StackedInline):
model = Solution
fields = ('is_public', 'publish_on', 'authors', 'content')
fields = ("is_public", "publish_on", "authors", "content")
form = ProblemSolutionForm
extra = 0
@ -109,168 +146,250 @@ class ProblemSolutionInline(admin.StackedInline):
class ProblemTranslationForm(ModelForm):
class Meta:
if HeavyPreviewAdminPageDownWidget is not None:
widgets = {'description': HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('problem_preview'))}
widgets = {
"description": HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("problem_preview")
)
}
class ProblemTranslationInline(admin.StackedInline):
model = ProblemTranslation
fields = ('language', 'name', 'description')
fields = ("language", "name", "description")
form = ProblemTranslationForm
extra = 0
class ProblemAdmin(CompareVersionAdmin):
fieldsets = (
(None, {
'fields': (
'code', 'name', 'is_public', 'is_manually_managed', 'date', 'authors', 'curators', 'testers',
'is_organization_private', 'organizations', 'description', 'license',
),
}),
(_('Social Media'), {'classes': ('collapse',), 'fields': ('og_image', 'summary')}),
(_('Taxonomy'), {'fields': ('types', 'group')}),
(_('Points'), {'fields': (('points', 'partial'), 'short_circuit')}),
(_('Limits'), {'fields': ('time_limit', 'memory_limit')}),
(_('Language'), {'fields': ('allowed_languages',)}),
(_('Justice'), {'fields': ('banned_users',)}),
(_('History'), {'fields': ('change_message',)}),
(
None,
{
"fields": (
"code",
"name",
"is_public",
"is_manually_managed",
"date",
"authors",
"curators",
"testers",
"is_organization_private",
"organizations",
"description",
"license",
),
},
),
(
_("Social Media"),
{"classes": ("collapse",), "fields": ("og_image", "summary")},
),
(_("Taxonomy"), {"fields": ("types", "group")}),
(_("Points"), {"fields": (("points", "partial"), "short_circuit")}),
(_("Limits"), {"fields": ("time_limit", "memory_limit")}),
(_("Language"), {"fields": ("allowed_languages",)}),
(_("Justice"), {"fields": ("banned_users",)}),
(_("History"), {"fields": ("change_message",)}),
)
list_display = ['code', 'name', 'show_authors', 'points', 'vote_cnt', 'vote_mean', 'vote_median', 'vote_std', 'is_public', 'show_public']
ordering = ['code']
search_fields = ('code', 'name', 'authors__user__username', 'curators__user__username')
inlines = [LanguageLimitInline, ProblemClarificationInline, ProblemSolutionInline, ProblemTranslationInline]
list_display = [
"code",
"name",
"show_authors",
"points",
"vote_cnt",
"vote_mean",
"vote_median",
"vote_std",
"is_public",
"show_public",
]
ordering = ["code"]
search_fields = (
"code",
"name",
"authors__user__username",
"curators__user__username",
)
inlines = [
LanguageLimitInline,
ProblemClarificationInline,
ProblemSolutionInline,
ProblemTranslationInline,
]
list_max_show_all = 1000
actions_on_top = True
actions_on_bottom = True
list_filter = ('is_public', ProblemCreatorListFilter)
list_filter = ("is_public", ProblemCreatorListFilter)
form = ProblemForm
date_hierarchy = 'date'
date_hierarchy = "date"
def get_actions(self, request):
actions = super(ProblemAdmin, self).get_actions(request)
if request.user.has_perm('judge.change_public_visibility'):
func, name, desc = self.get_action('make_public')
if request.user.has_perm("judge.change_public_visibility"):
func, name, desc = self.get_action("make_public")
actions[name] = (func, name, desc)
func, name, desc = self.get_action('make_private')
func, name, desc = self.get_action("make_private")
actions[name] = (func, name, desc)
return actions
def get_readonly_fields(self, request, obj=None):
fields = self.readonly_fields
if not request.user.has_perm('judge.change_public_visibility'):
fields += ('is_public',)
if not request.user.has_perm('judge.change_manually_managed'):
fields += ('is_manually_managed',)
if not request.user.has_perm("judge.change_public_visibility"):
fields += ("is_public",)
if not request.user.has_perm("judge.change_manually_managed"):
fields += ("is_manually_managed",)
return fields
def show_authors(self, obj):
return ', '.join(map(attrgetter('user.username'), obj.authors.all()))
return ", ".join(map(attrgetter("user.username"), obj.authors.all()))
show_authors.short_description = _('Authors')
show_authors.short_description = _("Authors")
def show_public(self, obj):
return format_html('<a href="{1}">{0}</a>', gettext('View on site'), obj.get_absolute_url())
return format_html(
'<a href="{1}">{0}</a>', gettext("View on site"), obj.get_absolute_url()
)
show_public.short_description = ''
show_public.short_description = ""
def _rescore(self, request, problem_id):
from judge.tasks import rescore_problem
transaction.on_commit(rescore_problem.s(problem_id).delay)
def make_public(self, request, queryset):
count = queryset.update(is_public=True)
for problem_id in queryset.values_list('id', flat=True):
for problem_id in queryset.values_list("id", flat=True):
self._rescore(request, problem_id)
self.message_user(request, ungettext('%d problem successfully marked as public.',
'%d problems successfully marked as public.',
count) % count)
self.message_user(
request,
ungettext(
"%d problem successfully marked as public.",
"%d problems successfully marked as public.",
count,
)
% count,
)
make_public.short_description = _('Mark problems as public')
make_public.short_description = _("Mark problems as public")
def make_private(self, request, queryset):
count = queryset.update(is_public=False)
for problem_id in queryset.values_list('id', flat=True):
for problem_id in queryset.values_list("id", flat=True):
self._rescore(request, problem_id)
self.message_user(request, ungettext('%d problem successfully marked as private.',
'%d problems successfully marked as private.',
count) % count)
self.message_user(
request,
ungettext(
"%d problem successfully marked as private.",
"%d problems successfully marked as private.",
count,
)
% count,
)
make_private.short_description = _('Mark problems as private')
make_private.short_description = _("Mark problems as private")
def get_queryset(self, request):
queryset = Problem.objects.prefetch_related('authors__user')
queryset = Problem.objects.prefetch_related("authors__user")
queryset = queryset.annotate(
_vote_mean=Avg('problem_points_votes__points'),
_vote_std=StdDev('problem_points_votes__points'),
_vote_cnt=Count('problem_points_votes__points')
_vote_mean=Avg("problem_points_votes__points"),
_vote_std=StdDev("problem_points_votes__points"),
_vote_cnt=Count("problem_points_votes__points"),
)
if request.user.has_perm('judge.edit_all_problem'):
if request.user.has_perm("judge.edit_all_problem"):
return queryset
access = Q()
if request.user.has_perm('judge.edit_public_problem'):
if request.user.has_perm("judge.edit_public_problem"):
access |= Q(is_public=True)
if request.user.has_perm('judge.edit_own_problem'):
access |= Q(authors__id=request.profile.id) | Q(curators__id=request.profile.id)
if request.user.has_perm("judge.edit_own_problem"):
access |= Q(authors__id=request.profile.id) | Q(
curators__id=request.profile.id
)
return queryset.filter(access).distinct() if access else queryset.none()
def has_change_permission(self, request, obj=None):
if request.user.has_perm('judge.edit_all_problem') or obj is None:
if request.user.has_perm("judge.edit_all_problem") or obj is None:
return True
if request.user.has_perm('judge.edit_public_problem') and obj.is_public:
if request.user.has_perm("judge.edit_public_problem") and obj.is_public:
return True
if not request.user.has_perm('judge.edit_own_problem'):
if not request.user.has_perm("judge.edit_own_problem"):
return False
return obj.is_editor(request.profile)
def formfield_for_manytomany(self, db_field, request=None, **kwargs):
if db_field.name == 'allowed_languages':
kwargs['widget'] = CheckboxSelectMultipleWithSelectAll()
return super(ProblemAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
if db_field.name == "allowed_languages":
kwargs["widget"] = CheckboxSelectMultipleWithSelectAll()
return super(ProblemAdmin, self).formfield_for_manytomany(
db_field, request, **kwargs
)
def get_form(self, *args, **kwargs):
form = super(ProblemAdmin, self).get_form(*args, **kwargs)
form.base_fields['authors'].queryset = Profile.objects.all()
form.base_fields["authors"].queryset = Profile.objects.all()
return form
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
if form.changed_data and any(f in form.changed_data for f in ('is_public', 'points', 'partial')):
if form.changed_data and any(
f in form.changed_data for f in ("is_public", "points", "partial")
):
self._rescore(request, obj.id)
def construct_change_message(self, request, form, *args, **kwargs):
if form.cleaned_data.get('change_message'):
return form.cleaned_data['change_message']
return super(ProblemAdmin, self).construct_change_message(request, form, *args, **kwargs)
if form.cleaned_data.get("change_message"):
return form.cleaned_data["change_message"]
return super(ProblemAdmin, self).construct_change_message(
request, form, *args, **kwargs
)
def vote_mean(self, obj):
return round(obj._vote_mean, 1) if obj._vote_mean is not None else None
vote_mean.admin_order_field = '_vote_mean'
vote_mean.admin_order_field = "_vote_mean"
def vote_std(self, obj):
return round(obj._vote_std, 1) if obj._vote_std is not None else None
vote_std.admin_order_field = '_vote_std'
vote_std.admin_order_field = "_vote_std"
def vote_cnt(self, obj):
return obj._vote_cnt
vote_cnt.admin_order_field = '_vote_cnt'
vote_cnt.admin_order_field = "_vote_cnt"
def vote_median(self, obj):
votes = obj.problem_points_votes.values_list('points', flat=True)
return statistics.median(votes) if votes else None
votes = obj.problem_points_votes.values_list("points", flat=True)
return statistics.median(votes) if votes else None
class ProblemPointsVoteAdmin(admin.ModelAdmin):
list_display = ('vote_points', 'voter', 'voter_rating', 'voter_point', 'problem_name', 'problem_code', 'problem_points')
search_fields = ('voter__user__username', 'problem__code', 'problem__name')
readonly_fields = ('voter', 'problem', 'problem_code', 'problem_points', 'voter_rating', 'voter_point')
list_display = (
"vote_points",
"voter",
"voter_rating",
"voter_point",
"problem_name",
"problem_code",
"problem_points",
)
search_fields = ("voter__user__username", "problem__code", "problem__name")
readonly_fields = (
"voter",
"problem",
"problem_code",
"problem_points",
"voter_rating",
"voter_point",
)
def has_change_permission(self, request, obj=None):
if obj is None:
return request.user.has_perm('judge.edit_own_problem')
return request.user.has_perm("judge.edit_own_problem")
return obj.problem.is_editable_by(request.user)
def lookup_allowed(self, key, value):
@ -278,29 +397,35 @@ class ProblemPointsVoteAdmin(admin.ModelAdmin):
def problem_code(self, obj):
return obj.problem.code
problem_code.short_description = _('Problem code')
problem_code.admin_order_field = 'problem__code'
problem_code.short_description = _("Problem code")
problem_code.admin_order_field = "problem__code"
def problem_points(self, obj):
return obj.problem.points
problem_points.short_description = _('Points')
problem_points.admin_order_field = 'problem__points'
problem_points.short_description = _("Points")
problem_points.admin_order_field = "problem__points"
def problem_name(self, obj):
return obj.problem.name
problem_name.short_description = _('Problem name')
problem_name.admin_order_field = 'problem__name'
problem_name.short_description = _("Problem name")
problem_name.admin_order_field = "problem__name"
def voter_rating(self, obj):
return obj.voter.rating
voter_rating.short_description = _('Voter rating')
voter_rating.admin_order_field = 'voter__rating'
voter_rating.short_description = _("Voter rating")
voter_rating.admin_order_field = "voter__rating"
def voter_point(self, obj):
return round(obj.voter.performance_points)
voter_point.short_description = _('Voter point')
voter_point.admin_order_field = 'voter__performance_points'
voter_point.short_description = _("Voter point")
voter_point.admin_order_field = "voter__performance_points"
def vote_points(self, obj):
return obj.points
vote_points.short_description = _('Vote')
vote_points.short_description = _("Vote")

View file

@ -12,30 +12,40 @@ from judge.widgets import AdminPagedownWidget, AdminSelect2Widget
class ProfileForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
if 'current_contest' in self.base_fields:
if "current_contest" in self.base_fields:
# form.fields['current_contest'] does not exist when the user has only view permission on the model.
self.fields['current_contest'].queryset = self.instance.contest_history.select_related('contest') \
.only('contest__name', 'user_id', 'virtual')
self.fields['current_contest'].label_from_instance = \
lambda obj: '%s v%d' % (obj.contest.name, obj.virtual) if obj.virtual else obj.contest.name
self.fields[
"current_contest"
].queryset = self.instance.contest_history.select_related("contest").only(
"contest__name", "user_id", "virtual"
)
self.fields["current_contest"].label_from_instance = (
lambda obj: "%s v%d" % (obj.contest.name, obj.virtual)
if obj.virtual
else obj.contest.name
)
class Meta:
widgets = {
'timezone': AdminSelect2Widget,
'language': AdminSelect2Widget,
'ace_theme': AdminSelect2Widget,
'current_contest': AdminSelect2Widget,
"timezone": AdminSelect2Widget,
"language": AdminSelect2Widget,
"ace_theme": AdminSelect2Widget,
"current_contest": AdminSelect2Widget,
}
if AdminPagedownWidget is not None:
widgets['about'] = AdminPagedownWidget
widgets["about"] = AdminPagedownWidget
class TimezoneFilter(admin.SimpleListFilter):
title = _('timezone')
parameter_name = 'timezone'
title = _("timezone")
parameter_name = "timezone"
def lookups(self, request, model_admin):
return Profile.objects.values_list('timezone', 'timezone').distinct().order_by('timezone')
return (
Profile.objects.values_list("timezone", "timezone")
.distinct()
.order_by("timezone")
)
def queryset(self, request, queryset):
if self.value() is None:
@ -44,75 +54,116 @@ 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', 'is_banned_problem_voting', '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')
ordering = ('user__username',)
search_fields = ('user__username', 'ip', 'user__email')
list_filter = ('language', TimezoneFilter)
actions = ('recalculate_points',)
fields = (
"user",
"display_rank",
"about",
"organizations",
"timezone",
"language",
"ace_theme",
"math_engine",
"last_access",
"ip",
"mute",
"is_unlisted",
"is_banned_problem_voting",
"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",
)
ordering = ("user__username",)
search_fields = ("user__username", "ip", "user__email")
list_filter = ("language", TimezoneFilter)
actions = ("recalculate_points",)
actions_on_top = True
actions_on_bottom = True
form = ProfileForm
def get_queryset(self, request):
return super(ProfileAdmin, self).get_queryset(request).select_related('user')
return super(ProfileAdmin, self).get_queryset(request).select_related("user")
def get_fields(self, request, obj=None):
if request.user.has_perm('judge.totp'):
if request.user.has_perm("judge.totp"):
fields = list(self.fields)
fields.insert(fields.index('is_totp_enabled') + 1, 'totp_key')
fields.insert(fields.index("is_totp_enabled") + 1, "totp_key")
return tuple(fields)
else:
return self.fields
def get_readonly_fields(self, request, obj=None):
fields = self.readonly_fields
if not request.user.has_perm('judge.totp'):
fields += ('is_totp_enabled',)
if not request.user.has_perm("judge.totp"):
fields += ("is_totp_enabled",)
return fields
def show_public(self, obj):
return format_html('<a href="{0}" style="white-space:nowrap;">{1}</a>',
obj.get_absolute_url(), gettext('View on site'))
show_public.short_description = ''
return format_html(
'<a href="{0}" style="white-space:nowrap;">{1}</a>',
obj.get_absolute_url(),
gettext("View on site"),
)
show_public.short_description = ""
def admin_user_admin(self, obj):
return obj.username
admin_user_admin.admin_order_field = 'user__username'
admin_user_admin.short_description = _('User')
admin_user_admin.admin_order_field = "user__username"
admin_user_admin.short_description = _("User")
def email(self, obj):
return obj.user.email
email.admin_order_field = 'user__email'
email.short_description = _('Email')
email.admin_order_field = "user__email"
email.short_description = _("Email")
def timezone_full(self, obj):
return obj.timezone
timezone_full.admin_order_field = 'timezone'
timezone_full.short_description = _('Timezone')
timezone_full.admin_order_field = "timezone"
timezone_full.short_description = _("Timezone")
def date_joined(self, obj):
return obj.user.date_joined
date_joined.admin_order_field = 'user__date_joined'
date_joined.short_description = _('date joined')
date_joined.admin_order_field = "user__date_joined"
date_joined.short_description = _("date joined")
def recalculate_points(self, request, queryset):
count = 0
for profile in queryset:
profile.calculate_points()
count += 1
self.message_user(request, ungettext('%d user have scores recalculated.',
'%d users have scores recalculated.',
count) % count)
recalculate_points.short_description = _('Recalculate scores')
self.message_user(
request,
ungettext(
"%d user have scores recalculated.",
"%d users have scores recalculated.",
count,
)
% count,
)
recalculate_points.short_description = _("Recalculate scores")
def get_form(self, request, obj=None, **kwargs):
form = super(ProfileAdmin, self).get_form(request, obj, **kwargs)
if 'user_script' in form.base_fields:
if "user_script" in form.base_fields:
# form.base_fields['user_script'] does not exist when the user has only view permission on the model.
form.base_fields['user_script'].widget = AceWidget('javascript', request.profile.ace_theme)
form.base_fields["user_script"].widget = AceWidget(
"javascript", request.profile.ace_theme
)
return form

View file

@ -16,41 +16,63 @@ from judge.widgets import AdminHeavySelect2MultipleWidget, AdminPagedownWidget
class LanguageForm(ModelForm):
problems = ModelMultipleChoiceField(
label=_('Disallowed problems'),
label=_("Disallowed problems"),
queryset=Problem.objects.all(),
required=False,
help_text=_('These problems are NOT allowed to be submitted in this language'),
widget=AdminHeavySelect2MultipleWidget(data_view='problem_select2'))
help_text=_("These problems are NOT allowed to be submitted in this language"),
widget=AdminHeavySelect2MultipleWidget(data_view="problem_select2"),
)
class Meta:
if AdminPagedownWidget is not None:
widgets = {'description': AdminPagedownWidget}
widgets = {"description": AdminPagedownWidget}
class LanguageAdmin(VersionAdmin):
fields = ('key', 'name', 'short_name', 'common_name', 'ace', 'pygments', 'info', 'description',
'template', 'problems')
list_display = ('key', 'name', 'common_name', 'info')
fields = (
"key",
"name",
"short_name",
"common_name",
"ace",
"pygments",
"info",
"description",
"template",
"problems",
)
list_display = ("key", "name", "common_name", "info")
form = LanguageForm
def save_model(self, request, obj, form, change):
super(LanguageAdmin, self).save_model(request, obj, form, change)
obj.problem_set.set(Problem.objects.exclude(id__in=form.cleaned_data['problems'].values('id')))
obj.problem_set.set(
Problem.objects.exclude(id__in=form.cleaned_data["problems"].values("id"))
)
def get_form(self, request, obj=None, **kwargs):
self.form.base_fields['problems'].initial = \
Problem.objects.exclude(id__in=obj.problem_set.values('id')).values_list('pk', flat=True) if obj else []
self.form.base_fields["problems"].initial = (
Problem.objects.exclude(id__in=obj.problem_set.values("id")).values_list(
"pk", flat=True
)
if obj
else []
)
form = super(LanguageAdmin, self).get_form(request, obj, **kwargs)
if obj is not None:
form.base_fields['template'].widget = AceWidget(obj.ace, request.profile.ace_theme)
form.base_fields["template"].widget = AceWidget(
obj.ace, request.profile.ace_theme
)
return form
class GenerateKeyTextInput(TextInput):
def render(self, name, value, attrs=None, renderer=None):
text = super(TextInput, self).render(name, value, attrs)
return mark_safe(text + format_html(
'''\
return mark_safe(
text
+ format_html(
"""\
<a href="#" onclick="return false;" class="button" id="id_{0}_regen">Regenerate</a>
<script type="text/javascript">
django.jQuery(document).ready(function ($) {{
@ -65,37 +87,59 @@ django.jQuery(document).ready(function ($) {{
}});
}});
</script>
''', name))
""",
name,
)
)
class JudgeAdminForm(ModelForm):
class Meta:
widgets = {'auth_key': GenerateKeyTextInput}
widgets = {"auth_key": GenerateKeyTextInput}
if AdminPagedownWidget is not None:
widgets['description'] = AdminPagedownWidget
widgets["description"] = AdminPagedownWidget
class JudgeAdmin(VersionAdmin):
form = JudgeAdminForm
readonly_fields = ('created', 'online', 'start_time', 'ping', 'load', 'last_ip', 'runtimes', 'problems')
fieldsets = (
(None, {'fields': ('name', 'auth_key', 'is_blocked')}),
(_('Description'), {'fields': ('description',)}),
(_('Information'), {'fields': ('created', 'online', 'last_ip', 'start_time', 'ping', 'load')}),
(_('Capabilities'), {'fields': ('runtimes', 'problems')}),
readonly_fields = (
"created",
"online",
"start_time",
"ping",
"load",
"last_ip",
"runtimes",
"problems",
)
list_display = ('name', 'online', 'start_time', 'ping', 'load', 'last_ip')
ordering = ['-online', 'name']
fieldsets = (
(None, {"fields": ("name", "auth_key", "is_blocked")}),
(_("Description"), {"fields": ("description",)}),
(
_("Information"),
{"fields": ("created", "online", "last_ip", "start_time", "ping", "load")},
),
(_("Capabilities"), {"fields": ("runtimes", "problems")}),
)
list_display = ("name", "online", "start_time", "ping", "load", "last_ip")
ordering = ["-online", "name"]
def get_urls(self):
return ([url(r'^(\d+)/disconnect/$', self.disconnect_view, name='judge_judge_disconnect'),
url(r'^(\d+)/terminate/$', self.terminate_view, name='judge_judge_terminate')] +
super(JudgeAdmin, self).get_urls())
return [
url(
r"^(\d+)/disconnect/$",
self.disconnect_view,
name="judge_judge_disconnect",
),
url(
r"^(\d+)/terminate/$", self.terminate_view, name="judge_judge_terminate"
),
] + super(JudgeAdmin, self).get_urls()
def disconnect_judge(self, id, force=False):
judge = get_object_or_404(Judge, id=id)
judge.disconnect(force=force)
return HttpResponseRedirect(reverse('admin:judge_judge_changelist'))
return HttpResponseRedirect(reverse("admin:judge_judge_changelist"))
def disconnect_view(self, request, id):
return self.disconnect_judge(id)
@ -105,7 +149,7 @@ class JudgeAdmin(VersionAdmin):
def get_readonly_fields(self, request, obj=None):
if obj is not None and obj.online:
return self.readonly_fields + ('name',)
return self.readonly_fields + ("name",)
return self.readonly_fields
def has_delete_permission(self, request, obj=None):
@ -116,5 +160,5 @@ class JudgeAdmin(VersionAdmin):
if AdminPagedownWidget is not None:
formfield_overrides = {
TextField: {'widget': AdminPagedownWidget},
TextField: {"widget": AdminPagedownWidget},
}

View file

@ -13,239 +13,367 @@ from django.utils.html import format_html
from django.utils.translation import gettext, gettext_lazy as _, pgettext, ungettext
from django_ace import AceWidget
from judge.models import ContestParticipation, ContestProblem, ContestSubmission, Profile, Submission, \
SubmissionSource, SubmissionTestCase
from judge.models import (
ContestParticipation,
ContestProblem,
ContestSubmission,
Profile,
Submission,
SubmissionSource,
SubmissionTestCase,
)
from judge.utils.raw_sql import use_straight_join
class SubmissionStatusFilter(admin.SimpleListFilter):
parameter_name = title = 'status'
__lookups = (('None', _('None')), ('NotDone', _('Not done')), ('EX', _('Exceptional'))) + Submission.STATUS
parameter_name = title = "status"
__lookups = (
("None", _("None")),
("NotDone", _("Not done")),
("EX", _("Exceptional")),
) + Submission.STATUS
__handles = set(map(itemgetter(0), Submission.STATUS))
def lookups(self, request, model_admin):
return self.__lookups
def queryset(self, request, queryset):
if self.value() == 'None':
if self.value() == "None":
return queryset.filter(status=None)
elif self.value() == 'NotDone':
return queryset.exclude(status__in=['D', 'IE', 'CE', 'AB'])
elif self.value() == 'EX':
return queryset.exclude(status__in=['D', 'CE', 'G', 'AB'])
elif self.value() == "NotDone":
return queryset.exclude(status__in=["D", "IE", "CE", "AB"])
elif self.value() == "EX":
return queryset.exclude(status__in=["D", "CE", "G", "AB"])
elif self.value() in self.__handles:
return queryset.filter(status=self.value())
class SubmissionResultFilter(admin.SimpleListFilter):
parameter_name = title = 'result'
__lookups = (('None', _('None')), ('BAD', _('Unaccepted'))) + Submission.RESULT
parameter_name = title = "result"
__lookups = (("None", _("None")), ("BAD", _("Unaccepted"))) + Submission.RESULT
__handles = set(map(itemgetter(0), Submission.RESULT))
def lookups(self, request, model_admin):
return self.__lookups
def queryset(self, request, queryset):
if self.value() == 'None':
if self.value() == "None":
return queryset.filter(result=None)
elif self.value() == 'BAD':
return queryset.exclude(result='AC')
elif self.value() == "BAD":
return queryset.exclude(result="AC")
elif self.value() in self.__handles:
return queryset.filter(result=self.value())
class SubmissionTestCaseInline(admin.TabularInline):
fields = ('case', 'batch', 'status', 'time', 'memory', 'points', 'total')
readonly_fields = ('case', 'batch', 'total')
fields = ("case", "batch", "status", "time", "memory", "points", "total")
readonly_fields = ("case", "batch", "total")
model = SubmissionTestCase
can_delete = False
max_num = 0
class ContestSubmissionInline(admin.StackedInline):
fields = ('problem', 'participation', 'points')
fields = ("problem", "participation", "points")
model = ContestSubmission
def get_formset(self, request, obj=None, **kwargs):
kwargs['formfield_callback'] = partial(self.formfield_for_dbfield, request=request, obj=obj)
kwargs["formfield_callback"] = partial(
self.formfield_for_dbfield, request=request, obj=obj
)
return super(ContestSubmissionInline, self).get_formset(request, obj, **kwargs)
def formfield_for_dbfield(self, db_field, **kwargs):
submission = kwargs.pop('obj', None)
submission = kwargs.pop("obj", None)
label = None
if submission:
if db_field.name == 'participation':
kwargs['queryset'] = ContestParticipation.objects.filter(user=submission.user,
contest__problems=submission.problem) \
.only('id', 'contest__name')
if db_field.name == "participation":
kwargs["queryset"] = ContestParticipation.objects.filter(
user=submission.user, contest__problems=submission.problem
).only("id", "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')
elif db_field.name == "problem":
kwargs["queryset"] = ContestProblem.objects.filter(
problem=submission.problem
).only("id", "problem__name", "contest__name")
def label(obj):
return pgettext('contest problem', '%(problem)s in %(contest)s') % {
'problem': obj.problem.name, 'contest': obj.contest.name,
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)
field = super(ContestSubmissionInline, self).formfield_for_dbfield(
db_field, **kwargs
)
if label is not None:
field.label_from_instance = label
return field
class SubmissionSourceInline(admin.StackedInline):
fields = ('source',)
fields = ("source",)
model = SubmissionSource
can_delete = False
extra = 0
def get_formset(self, request, obj=None, **kwargs):
kwargs.setdefault('widgets', {})['source'] = AceWidget(mode=obj and obj.language.ace,
theme=request.profile.ace_theme)
kwargs.setdefault("widgets", {})["source"] = AceWidget(
mode=obj and obj.language.ace, theme=request.profile.ace_theme
)
return super().get_formset(request, obj, **kwargs)
class SubmissionAdmin(admin.ModelAdmin):
readonly_fields = ('user', 'problem', 'date', 'judged_date')
fields = ('user', 'problem', 'date', 'judged_date', 'time', 'memory', 'points', 'language', 'status', 'result',
'case_points', 'case_total', 'judged_on', 'error')
actions = ('judge', 'recalculate_score')
list_display = ('id', 'problem_code', 'problem_name', 'user_column', 'execution_time', 'pretty_memory',
'points', 'language_column', 'status', 'result', 'judge_column')
list_filter = ('language', SubmissionStatusFilter, SubmissionResultFilter)
search_fields = ('problem__code', 'problem__name', 'user__user__username')
readonly_fields = ("user", "problem", "date", "judged_date")
fields = (
"user",
"problem",
"date",
"judged_date",
"time",
"memory",
"points",
"language",
"status",
"result",
"case_points",
"case_total",
"judged_on",
"error",
)
actions = ("judge", "recalculate_score")
list_display = (
"id",
"problem_code",
"problem_name",
"user_column",
"execution_time",
"pretty_memory",
"points",
"language_column",
"status",
"result",
"judge_column",
)
list_filter = ("language", SubmissionStatusFilter, SubmissionResultFilter)
search_fields = ("problem__code", "problem__name", "user__user__username")
actions_on_top = True
actions_on_bottom = True
inlines = [SubmissionSourceInline, SubmissionTestCaseInline, ContestSubmissionInline]
inlines = [
SubmissionSourceInline,
SubmissionTestCaseInline,
ContestSubmissionInline,
]
def get_queryset(self, request):
queryset = Submission.objects.select_related('problem', 'user__user', 'language').only(
'problem__code', 'problem__name', 'user__user__username', 'language__name',
'time', 'memory', 'points', 'status', 'result',
queryset = Submission.objects.select_related(
"problem", "user__user", "language"
).only(
"problem__code",
"problem__name",
"user__user__username",
"language__name",
"time",
"memory",
"points",
"status",
"result",
)
use_straight_join(queryset)
if not request.user.has_perm('judge.edit_all_problem'):
if not request.user.has_perm("judge.edit_all_problem"):
id = request.profile.id
queryset = queryset.filter(Q(problem__authors__id=id) | Q(problem__curators__id=id)).distinct()
queryset = queryset.filter(
Q(problem__authors__id=id) | Q(problem__curators__id=id)
).distinct()
return queryset
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
if not request.user.has_perm('judge.edit_own_problem'):
if not request.user.has_perm("judge.edit_own_problem"):
return False
if request.user.has_perm('judge.edit_all_problem') or obj is None:
if request.user.has_perm("judge.edit_all_problem") or obj is None:
return True
return obj.problem.is_editor(request.profile)
def lookup_allowed(self, key, value):
return super(SubmissionAdmin, self).lookup_allowed(key, value) or key in ('problem__code',)
return super(SubmissionAdmin, self).lookup_allowed(key, value) or key in (
"problem__code",
)
def judge(self, request, queryset):
if not request.user.has_perm('judge.rejudge_submission') or not request.user.has_perm('judge.edit_own_problem'):
self.message_user(request, gettext('You do not have the permission to rejudge submissions.'),
level=messages.ERROR)
if not request.user.has_perm(
"judge.rejudge_submission"
) or not request.user.has_perm("judge.edit_own_problem"):
self.message_user(
request,
gettext("You do not have the permission to rejudge submissions."),
level=messages.ERROR,
)
return
queryset = queryset.order_by('id')
if not request.user.has_perm('judge.rejudge_submission_lot') and \
queryset.count() > settings.DMOJ_SUBMISSIONS_REJUDGE_LIMIT:
self.message_user(request, gettext('You do not have the permission to rejudge THAT many submissions.'),
level=messages.ERROR)
queryset = queryset.order_by("id")
if (
not request.user.has_perm("judge.rejudge_submission_lot")
and queryset.count() > settings.DMOJ_SUBMISSIONS_REJUDGE_LIMIT
):
self.message_user(
request,
gettext(
"You do not have the permission to rejudge THAT many submissions."
),
level=messages.ERROR,
)
return
if not request.user.has_perm('judge.edit_all_problem'):
if not request.user.has_perm("judge.edit_all_problem"):
id = request.profile.id
queryset = queryset.filter(Q(problem__authors__id=id) | Q(problem__curators__id=id))
queryset = queryset.filter(
Q(problem__authors__id=id) | Q(problem__curators__id=id)
)
judged = len(queryset)
for model in queryset:
model.judge(rejudge=True, batch_rejudge=True)
self.message_user(request, ungettext('%d submission was successfully scheduled for rejudging.',
'%d submissions were successfully scheduled for rejudging.',
judged) % judged)
judge.short_description = _('Rejudge the selected submissions')
self.message_user(
request,
ungettext(
"%d submission was successfully scheduled for rejudging.",
"%d submissions were successfully scheduled for rejudging.",
judged,
)
% judged,
)
judge.short_description = _("Rejudge the selected submissions")
def recalculate_score(self, request, queryset):
if not request.user.has_perm('judge.rejudge_submission'):
self.message_user(request, gettext('You do not have the permission to rejudge submissions.'),
level=messages.ERROR)
if not request.user.has_perm("judge.rejudge_submission"):
self.message_user(
request,
gettext("You do not have the permission to rejudge submissions."),
level=messages.ERROR,
)
return
submissions = list(queryset.defer(None).select_related(None).select_related('problem')
.only('points', 'case_points', 'case_total', 'problem__partial', 'problem__points'))
submissions = list(
queryset.defer(None)
.select_related(None)
.select_related("problem")
.only(
"points",
"case_points",
"case_total",
"problem__partial",
"problem__points",
)
)
for submission in submissions:
submission.points = round(submission.case_points / submission.case_total * submission.problem.points
if submission.case_total else 0, 1)
if not submission.problem.partial and submission.points < submission.problem.points:
submission.points = round(
submission.case_points
/ submission.case_total
* submission.problem.points
if submission.case_total
else 0,
1,
)
if (
not submission.problem.partial
and submission.points < submission.problem.points
):
submission.points = 0
submission.save()
submission.update_contest()
for profile in Profile.objects.filter(id__in=queryset.values_list('user_id', flat=True).distinct()):
for profile in Profile.objects.filter(
id__in=queryset.values_list("user_id", flat=True).distinct()
):
profile.calculate_points()
cache.delete('user_complete:%d' % profile.id)
cache.delete('user_attempted:%d' % profile.id)
cache.delete("user_complete:%d" % profile.id)
cache.delete("user_attempted:%d" % profile.id)
for participation in ContestParticipation.objects.filter(
id__in=queryset.values_list('contest__participation_id')).prefetch_related('contest'):
id__in=queryset.values_list("contest__participation_id")
).prefetch_related("contest"):
participation.recompute_results()
self.message_user(request, ungettext('%d submission were successfully rescored.',
'%d submissions were successfully rescored.',
len(submissions)) % len(submissions))
recalculate_score.short_description = _('Rescore the selected submissions')
self.message_user(
request,
ungettext(
"%d submission were successfully rescored.",
"%d submissions were successfully rescored.",
len(submissions),
)
% len(submissions),
)
recalculate_score.short_description = _("Rescore the selected submissions")
def problem_code(self, obj):
return obj.problem.code
problem_code.short_description = _('Problem code')
problem_code.admin_order_field = 'problem__code'
problem_code.short_description = _("Problem code")
problem_code.admin_order_field = "problem__code"
def problem_name(self, obj):
return obj.problem.name
problem_name.short_description = _('Problem name')
problem_name.admin_order_field = 'problem__name'
problem_name.short_description = _("Problem name")
problem_name.admin_order_field = "problem__name"
def user_column(self, obj):
return obj.user.user.username
user_column.admin_order_field = 'user__user__username'
user_column.short_description = _('User')
user_column.admin_order_field = "user__user__username"
user_column.short_description = _("User")
def execution_time(self, obj):
return round(obj.time, 2) if obj.time is not None else 'None'
execution_time.short_description = _('Time')
execution_time.admin_order_field = 'time'
return round(obj.time, 2) if obj.time is not None else "None"
execution_time.short_description = _("Time")
execution_time.admin_order_field = "time"
def pretty_memory(self, obj):
memory = obj.memory
if memory is None:
return gettext('None')
return gettext("None")
if memory < 1000:
return gettext('%d KB') % memory
return gettext("%d KB") % memory
else:
return gettext('%.2f MB') % (memory / 1024)
pretty_memory.admin_order_field = 'memory'
pretty_memory.short_description = _('Memory')
return gettext("%.2f MB") % (memory / 1024)
pretty_memory.admin_order_field = "memory"
pretty_memory.short_description = _("Memory")
def language_column(self, obj):
return obj.language.name
language_column.admin_order_field = 'language__name'
language_column.short_description = _('Language')
language_column.admin_order_field = "language__name"
language_column.short_description = _("Language")
def judge_column(self, obj):
return format_html('<input type="button" value="Rejudge" onclick="location.href=\'{}/judge/\'" />', obj.id)
judge_column.short_description = ''
return format_html(
'<input type="button" value="Rejudge" onclick="location.href=\'{}/judge/\'" />',
obj.id,
)
judge_column.short_description = ""
def get_urls(self):
return [
url(r'^(\d+)/judge/$', self.judge_view, name='judge_submission_rejudge'),
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'):
if not request.user.has_perm(
"judge.rejudge_submission"
) or not request.user.has_perm("judge.edit_own_problem"):
raise PermissionDenied()
submission = get_object_or_404(Submission, id=id)
if not request.user.has_perm('judge.edit_all_problem') and \
not submission.problem.is_editor(request.profile):
if not request.user.has_perm(
"judge.edit_all_problem"
) and not submission.problem.is_editor(request.profile):
raise PermissionDenied()
submission.judge(rejudge=True)
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))

View file

@ -8,45 +8,51 @@ from judge.widgets import AdminHeavySelect2MultipleWidget
class ProblemGroupForm(ModelForm):
problems = ModelMultipleChoiceField(
label=_('Included problems'),
label=_("Included problems"),
queryset=Problem.objects.all(),
required=False,
help_text=_('These problems are included in this group of problems'),
widget=AdminHeavySelect2MultipleWidget(data_view='problem_select2'))
help_text=_("These problems are included in this group of problems"),
widget=AdminHeavySelect2MultipleWidget(data_view="problem_select2"),
)
class ProblemGroupAdmin(admin.ModelAdmin):
fields = ('name', 'full_name', 'problems')
fields = ("name", "full_name", "problems")
form = ProblemGroupForm
def save_model(self, request, obj, form, change):
super(ProblemGroupAdmin, self).save_model(request, obj, form, change)
obj.problem_set.set(form.cleaned_data['problems'])
obj.problem_set.set(form.cleaned_data["problems"])
obj.save()
def get_form(self, request, obj=None, **kwargs):
self.form.base_fields['problems'].initial = [o.pk for o in obj.problem_set.all()] if obj else []
self.form.base_fields["problems"].initial = (
[o.pk for o in obj.problem_set.all()] if obj else []
)
return super(ProblemGroupAdmin, self).get_form(request, obj, **kwargs)
class ProblemTypeForm(ModelForm):
problems = ModelMultipleChoiceField(
label=_('Included problems'),
label=_("Included problems"),
queryset=Problem.objects.all(),
required=False,
help_text=_('These problems are included in this type of problems'),
widget=AdminHeavySelect2MultipleWidget(data_view='problem_select2'))
help_text=_("These problems are included in this type of problems"),
widget=AdminHeavySelect2MultipleWidget(data_view="problem_select2"),
)
class ProblemTypeAdmin(admin.ModelAdmin):
fields = ('name', 'full_name', 'problems')
fields = ("name", "full_name", "problems")
form = ProblemTypeForm
def save_model(self, request, obj, form, change):
super(ProblemTypeAdmin, self).save_model(request, obj, form, change)
obj.problem_set.set(form.cleaned_data['problems'])
obj.problem_set.set(form.cleaned_data["problems"])
obj.save()
def get_form(self, request, obj=None, **kwargs):
self.form.base_fields['problems'].initial = [o.pk for o in obj.problem_set.all()] if obj else []
self.form.base_fields["problems"].initial = (
[o.pk for o in obj.problem_set.all()] if obj else []
)
return super(ProblemTypeAdmin, self).get_form(request, obj, **kwargs)

View file

@ -4,36 +4,56 @@ from django.forms import ModelForm
from django.urls import reverse_lazy
from judge.models import TicketMessage
from judge.widgets import AdminHeavySelect2MultipleWidget, AdminHeavySelect2Widget, HeavyPreviewAdminPageDownWidget
from judge.widgets import (
AdminHeavySelect2MultipleWidget,
AdminHeavySelect2Widget,
HeavyPreviewAdminPageDownWidget,
)
class TicketMessageForm(ModelForm):
class Meta:
widgets = {
'user': AdminHeavySelect2Widget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
"user": AdminHeavySelect2Widget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
}
if HeavyPreviewAdminPageDownWidget is not None:
widgets['body'] = HeavyPreviewAdminPageDownWidget(preview=reverse_lazy('ticket_preview'))
widgets["body"] = HeavyPreviewAdminPageDownWidget(
preview=reverse_lazy("ticket_preview")
)
class TicketMessageInline(StackedInline):
model = TicketMessage
form = TicketMessageForm
fields = ('user', 'body')
fields = ("user", "body")
class TicketForm(ModelForm):
class Meta:
widgets = {
'user': AdminHeavySelect2Widget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
'assignees': AdminHeavySelect2MultipleWidget(data_view='profile_select2', attrs={'style': 'width: 100%'}),
"user": AdminHeavySelect2Widget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
"assignees": AdminHeavySelect2MultipleWidget(
data_view="profile_select2", attrs={"style": "width: 100%"}
),
}
class TicketAdmin(ModelAdmin):
fields = ('title', 'time', 'user', 'assignees', 'content_type', 'object_id', 'notes')
readonly_fields = ('time',)
list_display = ('title', 'user', 'time', 'linked_item')
fields = (
"title",
"time",
"user",
"assignees",
"content_type",
"object_id",
"notes",
)
readonly_fields = ("time",)
list_display = ("title", "user", "time", "linked_item")
inlines = [TicketMessageInline]
form = TicketForm
date_hierarchy = 'time'
date_hierarchy = "time"

View file

@ -5,14 +5,30 @@ from django.utils.translation import gettext, gettext_lazy as _, ungettext
from judge.models import VolunteerProblemVote
class VolunteerProblemVoteAdmin(admin.ModelAdmin):
fields = ('voter', 'problem', 'time', 'thinking_points', 'knowledge_points', 'feedback')
readonly_fields = ('time', 'problem', 'voter')
list_display = ('voter', 'problem_link', 'time', 'thinking_points', 'knowledge_points', 'feedback')
date_hierarchy = 'time'
fields = (
"voter",
"problem",
"time",
"thinking_points",
"knowledge_points",
"feedback",
)
readonly_fields = ("time", "problem", "voter")
list_display = (
"voter",
"problem_link",
"time",
"thinking_points",
"knowledge_points",
"feedback",
)
date_hierarchy = "time"
def problem_link(self, obj):
url = reverse('admin:judge_problem_change', args=(obj.problem.id,))
url = reverse("admin:judge_problem_change", args=(obj.problem.id,))
return format_html(f"<a href='{url}'>{obj.problem.code}</a>")
problem_link.short_description = _('Problem')
problem_link.admin_order_field = 'problem__code'
problem_link.short_description = _("Problem")
problem_link.admin_order_field = "problem__code"