Reformat using black
This commit is contained in:
parent
efee4ad081
commit
a87fb49918
221 changed files with 19127 additions and 7310 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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},
|
||||
}
|
||||
|
|
|
@ -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", "/"))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue