Add contest tester/curator (DMOJ)
This commit is contained in:
parent
06318a97e5
commit
297b8a2a36
25 changed files with 611 additions and 230 deletions
|
@ -16,10 +16,9 @@ def sane_time_repr(delta):
|
|||
|
||||
|
||||
def api_v1_contest_list(request):
|
||||
queryset = Contest.objects.filter(is_visible=True, is_private=False,
|
||||
is_organization_private=False).prefetch_related(
|
||||
Prefetch('tags', queryset=ContestTag.objects.only('name'), to_attr='tag_list')).defer('description')
|
||||
|
||||
queryset = Contest.get_visible_contests(request.user).prefetch_related(
|
||||
Prefetch('tags', queryset=ContestTag.objects.only('name'), to_attr='tag_list'))
|
||||
|
||||
return JsonResponse({c.key: {
|
||||
'name': c.name,
|
||||
'start_time': c.start_time.isoformat(),
|
||||
|
@ -33,10 +32,7 @@ def api_v1_contest_detail(request, contest):
|
|||
contest = get_object_or_404(Contest, key=contest)
|
||||
|
||||
in_contest = contest.is_in_contest(request.user)
|
||||
can_see_rankings = contest.can_see_scoreboard(request.user)
|
||||
if contest.hide_scoreboard and in_contest:
|
||||
can_see_rankings = False
|
||||
|
||||
can_see_rankings = contest.can_see_full_scoreboard(request.user)
|
||||
problems = list(contest.contest_problems.select_related('problem')
|
||||
.defer('problem__description').order_by('order'))
|
||||
participations = (contest.users.filter(virtual=0, user__is_unlisted=False)
|
||||
|
|
|
@ -81,17 +81,14 @@ class PostList(ListView):
|
|||
.annotate(points=Max('points'), latest=Max('date'))
|
||||
.order_by('-latest')
|
||||
[:settings.DMOJ_BLOG_RECENTLY_ATTEMPTED_PROBLEMS_COUNT])
|
||||
|
||||
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True) \
|
||||
.order_by('start_time')
|
||||
|
||||
visible_contests = Contest.objects.filter(is_visible=True).order_by('start_time')
|
||||
q = Q(is_private=False, is_organization_private=False)
|
||||
if self.request.user.is_authenticated:
|
||||
q |= Q(is_organization_private=True, organizations__in=user.organizations.all())
|
||||
q |= Q(is_private=True, private_contestants=user)
|
||||
q |= Q(view_contest_scoreboard=user)
|
||||
visible_contests = visible_contests.filter(q)
|
||||
context['current_contests'] = visible_contests.filter(start_time__lte=now, end_time__gt=now).distinct()
|
||||
context['future_contests'] = visible_contests.filter(start_time__gt=now).distinct()
|
||||
context['current_contests'] = visible_contests.filter(start_time__lte=now, end_time__gt=now)
|
||||
context['future_contests'] = visible_contests.filter(start_time__gt=now)
|
||||
|
||||
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True)
|
||||
if self.request.user.is_authenticated:
|
||||
profile = self.request.profile
|
||||
context['own_open_tickets'] = (Ticket.objects.filter(Q(user=profile) | Q(assignees__in=[profile]), is_open=True).order_by('-id')
|
||||
|
|
|
@ -12,7 +12,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMix
|
|||
from django.core.cache import cache
|
||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
||||
from django.db import IntegrityError
|
||||
from django.db.models import Case, Count, FloatField, IntegerField, Max, Min, Q, Sum, Value, When
|
||||
from django.db.models import Case, Count, F, FloatField, IntegerField, Max, Min, Q, Sum, Value, When
|
||||
from django.db.models.expressions import CombinedExpression
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
|
@ -59,20 +59,7 @@ def _find_contest(request, key, private_check=True):
|
|||
|
||||
class ContestListMixin(object):
|
||||
def get_queryset(self):
|
||||
queryset = Contest.objects.all()
|
||||
if not self.request.user.has_perm('judge.see_private_contest'):
|
||||
q = Q(is_visible=True)
|
||||
if self.request.user.is_authenticated:
|
||||
q |= Q(organizers=self.request.profile)
|
||||
queryset = queryset.filter(q)
|
||||
if not self.request.user.has_perm('judge.edit_all_contest'):
|
||||
q = Q(is_private=False, is_organization_private=False)
|
||||
if self.request.user.is_authenticated:
|
||||
q |= Q(is_organization_private=True, organizations__in=self.request.profile.organizations.all())
|
||||
q |= Q(is_private=True, private_contestants=self.request.profile)
|
||||
q |= Q(view_contest_scoreboard=self.request.profile)
|
||||
queryset = queryset.filter(q)
|
||||
return queryset.distinct()
|
||||
return Contest.get_visible_contests(self.request.user)
|
||||
|
||||
|
||||
class ContestList(DiggPaginatorMixin, TitleMixin, ContestListMixin, ListView):
|
||||
|
@ -101,7 +88,7 @@ class ContestList(DiggPaginatorMixin, TitleMixin, ContestListMixin, ListView):
|
|||
|
||||
def _get_queryset(self):
|
||||
queryset = super(ContestList, self).get_queryset() \
|
||||
.order_by('-start_time', 'key').prefetch_related('tags', 'organizations', 'organizers')
|
||||
.order_by('-start_time', 'key').prefetch_related('tags', 'organizations', 'authors', 'curators', 'testers')
|
||||
|
||||
if 'contest' in self.request.GET:
|
||||
self.contest_query = query = ' '.join(self.request.GET.getlist('contest')).strip()
|
||||
|
@ -128,7 +115,9 @@ class ContestList(DiggPaginatorMixin, TitleMixin, ContestListMixin, ListView):
|
|||
if self.request.user.is_authenticated:
|
||||
for participation in ContestParticipation.objects.filter(virtual=0, user=self.request.profile,
|
||||
contest_id__in=present) \
|
||||
.select_related('contest').prefetch_related('contest__organizers'):
|
||||
.select_related('contest') \
|
||||
.prefetch_related('contest__authors', 'contest__curators', 'contest__testers')\
|
||||
.annotate(key=F('contest__key')):
|
||||
if not participation.ended:
|
||||
active.append(participation)
|
||||
present.remove(participation.contest)
|
||||
|
@ -164,37 +153,44 @@ class ContestMixin(object):
|
|||
slug_url_kwarg = 'contest'
|
||||
|
||||
@cached_property
|
||||
def is_organizer(self):
|
||||
return self.check_organizer()
|
||||
def is_editor(self):
|
||||
if not self.request.user.is_authenticated:
|
||||
return False
|
||||
return self.request.profile.id in self.object.editor_ids
|
||||
|
||||
def check_organizer(self, contest=None, user=None):
|
||||
if user is None:
|
||||
user = self.request.user
|
||||
return (contest or self.object).is_editable_by(user)
|
||||
@cached_property
|
||||
def is_tester(self):
|
||||
if not self.request.user.is_authenticated:
|
||||
return False
|
||||
return self.request.profile.id in self.object.tester_ids
|
||||
|
||||
@cached_property
|
||||
def can_edit(self):
|
||||
return self.object.is_editable_by(self.request.user)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ContestMixin, self).get_context_data(**kwargs)
|
||||
if self.request.user.is_authenticated:
|
||||
profile = self.request.profile
|
||||
in_contest = context['in_contest'] = (profile.current_contest is not None and
|
||||
profile.current_contest.contest == self.object)
|
||||
if in_contest:
|
||||
context['participation'] = profile.current_contest
|
||||
context['participating'] = True
|
||||
try:
|
||||
context['live_participation'] = (
|
||||
self.request.profile.contest_history.get(
|
||||
contest=self.object,
|
||||
virtual=ContestParticipation.LIVE,
|
||||
)
|
||||
)
|
||||
except ContestParticipation.DoesNotExist:
|
||||
context['live_participation'] = None
|
||||
context['has_joined'] = False
|
||||
else:
|
||||
try:
|
||||
context['participation'] = profile.contest_history.get(contest=self.object, virtual=0)
|
||||
except ContestParticipation.DoesNotExist:
|
||||
context['participating'] = False
|
||||
context['participation'] = None
|
||||
else:
|
||||
context['participating'] = True
|
||||
context['has_joined'] = True
|
||||
else:
|
||||
context['participating'] = False
|
||||
context['participation'] = None
|
||||
context['in_contest'] = False
|
||||
context['live_participation'] = None
|
||||
context['has_joined'] = False
|
||||
|
||||
context['now'] = timezone.now()
|
||||
context['is_organizer'] = self.is_organizer
|
||||
context['is_editor'] = self.is_editor
|
||||
context['is_tester'] = self.is_tester
|
||||
context['can_edit'] = self.can_edit
|
||||
|
||||
if not self.object.og_image or not self.object.summary:
|
||||
metadata = generate_opengraph('generated-meta-contest:%d' % self.object.id,
|
||||
|
@ -210,18 +206,22 @@ class ContestMixin(object):
|
|||
|
||||
def get_object(self, queryset=None):
|
||||
contest = super(ContestMixin, self).get_object(queryset)
|
||||
user = self.request.user
|
||||
profile = self.request.profile
|
||||
|
||||
if (profile is not None and
|
||||
ContestParticipation.objects.filter(id=profile.current_contest_id, contest_id=contest.id).exists()):
|
||||
return contest
|
||||
|
||||
if not contest.is_visible and not user.has_perm('judge.see_private_contest') and (
|
||||
not user.has_perm('judge.edit_own_contest') or
|
||||
not self.check_organizer(contest, user)):
|
||||
try:
|
||||
contest.access_check(self.request.user)
|
||||
except Contest.PrivateContest:
|
||||
raise PrivateContestError(contest.name, contest.is_private, contest.is_organization_private,
|
||||
contest.organizations.all())
|
||||
except Contest.Inaccessible:
|
||||
raise Http404()
|
||||
|
||||
else:
|
||||
return contest
|
||||
|
||||
if contest.is_private or contest.is_organization_private:
|
||||
private_contest_error = PrivateContestError(contest.name, contest.is_private,
|
||||
contest.is_organization_private, contest.organizations.all())
|
||||
|
@ -297,7 +297,7 @@ class ContestClone(ContestMixin, PermissionRequiredMixin, TitleMixin, SingleObje
|
|||
contest.organizations.set(organizations)
|
||||
contest.private_contestants.set(private_contestants)
|
||||
contest.view_contest_scoreboard.set(view_contest_scoreboard)
|
||||
contest.organizers.add(self.request.profile)
|
||||
contest.authors.add(self.request.profile)
|
||||
|
||||
for problem in contest_problems:
|
||||
problem.contest = contest
|
||||
|
@ -337,7 +337,7 @@ class ContestJoin(LoginRequiredMixin, ContestMixin, BaseDetailView):
|
|||
def join_contest(self, request, access_code=None):
|
||||
contest = self.object
|
||||
|
||||
if not contest.can_join and not self.is_organizer:
|
||||
if not contest.can_join and not (self.is_editor or self.is_tester):
|
||||
return generic_message(request, _('Contest not ongoing'),
|
||||
_('"%s" is not currently ongoing.') % contest.name)
|
||||
|
||||
|
@ -351,8 +351,7 @@ class ContestJoin(LoginRequiredMixin, ContestMixin, BaseDetailView):
|
|||
_('You have been declared persona non grata for this contest. '
|
||||
'You are permanently barred from joining this contest.'))
|
||||
|
||||
requires_access_code = (not (request.user.is_superuser or self.is_organizer) and
|
||||
contest.access_code and access_code != contest.access_code)
|
||||
requires_access_code = (not self.can_edit and contest.access_code and access_code != contest.access_code)
|
||||
if contest.ended:
|
||||
if requires_access_code:
|
||||
raise ContestAccessDenied()
|
||||
|
@ -371,22 +370,24 @@ class ContestJoin(LoginRequiredMixin, ContestMixin, BaseDetailView):
|
|||
else:
|
||||
break
|
||||
else:
|
||||
SPECTATE = ContestParticipation.SPECTATE
|
||||
LIVE = ContestParticipation.LIVE
|
||||
try:
|
||||
participation = ContestParticipation.objects.get(
|
||||
contest=contest, user=profile, virtual=(-1 if self.is_organizer else 0),
|
||||
contest=contest, user=profile, virtual=(SPECTATE if self.is_editor or self.is_tester else LIVE),
|
||||
)
|
||||
except ContestParticipation.DoesNotExist:
|
||||
if requires_access_code:
|
||||
raise ContestAccessDenied()
|
||||
|
||||
participation = ContestParticipation.objects.create(
|
||||
contest=contest, user=profile, virtual=(-1 if self.is_organizer else 0),
|
||||
contest=contest, user=profile, virtual=(SPECTATE if self.is_editor or self.is_tester else LIVE),
|
||||
real_start=timezone.now(),
|
||||
)
|
||||
else:
|
||||
if participation.ended:
|
||||
participation = ContestParticipation.objects.get_or_create(
|
||||
contest=contest, user=profile, virtual=-1,
|
||||
contest=contest, user=profile, virtual=SPECTATE,
|
||||
defaults={'real_start': timezone.now()},
|
||||
)[0]
|
||||
|
||||
|
@ -449,7 +450,7 @@ class ContestCalendar(TitleMixin, ContestListMixin, TemplateView):
|
|||
def get_contest_data(self, start, end):
|
||||
end += timedelta(days=1)
|
||||
contests = self.get_queryset().filter(Q(start_time__gte=start, start_time__lt=end) |
|
||||
Q(end_time__gte=start, end_time__lt=end)).defer('description')
|
||||
Q(end_time__gte=start, end_time__lt=end))
|
||||
starts, ends, oneday = (defaultdict(list) for i in range(3))
|
||||
for contest in contests:
|
||||
start_date = timezone.localtime(contest.start_time).date()
|
||||
|
@ -530,7 +531,7 @@ class ContestStats(TitleMixin, ContestMixin, DetailView):
|
|||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
if not (self.object.ended or self.object.is_editable_by(self.request.user)):
|
||||
if not (self.object.ended or self.can_edit):
|
||||
raise Http404()
|
||||
|
||||
queryset = Submission.objects.filter(contest_object=self.object)
|
||||
|
@ -542,9 +543,10 @@ class ContestStats(TitleMixin, ContestMixin, DetailView):
|
|||
queryset.values('problem__code', 'result').annotate(count=Count('result'))
|
||||
.values_list('problem__code', 'result', 'count'),
|
||||
)
|
||||
labels, codes = zip(
|
||||
*self.object.contest_problems.order_by('order').values_list('problem__name', 'problem__code'),
|
||||
)
|
||||
labels, codes = [], []
|
||||
contest_problems = self.object.contest_problems.order_by('order').values_list('problem__name', 'problem__code')
|
||||
if contest_problems:
|
||||
labels, codes = zip(*contest_problems)
|
||||
num_problems = len(labels)
|
||||
status_counts = [[] for i in range(num_problems)]
|
||||
for problem_code, result, count in status_count_queryset:
|
||||
|
@ -630,10 +632,6 @@ def get_contest_ranking_list(request, contest, participation=None, ranking_list=
|
|||
show_current_virtual=True, ranker=ranker):
|
||||
problems = list(contest.contest_problems.select_related('problem').defer('problem__description').order_by('order'))
|
||||
|
||||
if contest.hide_scoreboard and contest.is_in_contest(request.user):
|
||||
return ([(_('???'), make_contest_ranking_profile(contest, request.profile.current_contest, problems))],
|
||||
problems)
|
||||
|
||||
users = ranker(ranking_list(contest, problems), key=attrgetter('points', 'cumtime'))
|
||||
|
||||
if show_current_virtual:
|
||||
|
@ -651,7 +649,7 @@ def contest_ranking_ajax(request, contest, participation=None):
|
|||
if not exists:
|
||||
return HttpResponseBadRequest('Invalid contest', content_type='text/plain')
|
||||
|
||||
if not contest.can_see_scoreboard(request.user):
|
||||
if not contest.can_see_full_scoreboard(request.user):
|
||||
raise Http404()
|
||||
|
||||
users, problems = get_contest_ranking_list(request, contest, participation)
|
||||
|
@ -679,7 +677,7 @@ class ContestRankingBase(ContestMixin, TitleMixin, DetailView):
|
|||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
if not self.object.can_see_scoreboard(self.request.user):
|
||||
if not self.object.can_see_own_scoreboard(self.request.user):
|
||||
raise Http404()
|
||||
|
||||
users, problems = self.get_ranking_list()
|
||||
|
@ -697,6 +695,14 @@ class ContestRanking(ContestRankingBase):
|
|||
return _('%s Rankings') % self.object.name
|
||||
|
||||
def get_ranking_list(self):
|
||||
if not self.object.can_see_full_scoreboard(self.request.user):
|
||||
queryset = self.object.users.filter(user=self.request.profile, virtual=ContestParticipation.LIVE)
|
||||
return get_contest_ranking_list(
|
||||
self.request, self.object,
|
||||
ranking_list=partial(base_contest_ranking_list, queryset=queryset),
|
||||
ranker=lambda users, key: ((_('???'), user) for user in users),
|
||||
)
|
||||
|
||||
return get_contest_ranking_list(self.request, self.object)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -714,6 +720,9 @@ class ContestParticipationList(LoginRequiredMixin, ContestRankingBase):
|
|||
return _("%s's participation in %s") % (self.profile.username, self.object.name)
|
||||
|
||||
def get_ranking_list(self):
|
||||
if not self.object.can_see_full_scoreboard(self.request.user) and self.profile != self.request.profile:
|
||||
raise Http404()
|
||||
|
||||
queryset = self.object.users.filter(user=self.profile, virtual__gte=0).order_by('-virtual')
|
||||
live_link = format_html('<a href="{2}#!{1}">{0}</a>', _('Live'), self.profile.username,
|
||||
reverse('contest_ranking', args=[self.object.key]))
|
||||
|
@ -741,7 +750,7 @@ class ContestParticipationList(LoginRequiredMixin, ContestRankingBase):
|
|||
class ContestParticipationDisqualify(ContestMixin, SingleObjectMixin, View):
|
||||
def get_object(self, queryset=None):
|
||||
contest = super().get_object(queryset)
|
||||
if not contest.is_editable_by(self.request.user):
|
||||
if not self.can_edit:
|
||||
raise Http404()
|
||||
return contest
|
||||
|
||||
|
@ -762,7 +771,7 @@ class ContestMossMixin(ContestMixin, PermissionRequiredMixin):
|
|||
|
||||
def get_object(self, queryset=None):
|
||||
contest = super().get_object(queryset)
|
||||
if settings.MOSS_API_KEY is None:
|
||||
if settings.MOSS_API_KEY is None or not self.can_edit:
|
||||
raise Http404()
|
||||
if not contest.is_editable_by(self.request.user):
|
||||
raise Http404()
|
||||
|
|
|
@ -438,7 +438,8 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
|
|||
else:
|
||||
context['hot_problems'] = None
|
||||
context['point_start'], context['point_end'], context['point_values'] = 0, 0, {}
|
||||
context['hide_contest_scoreboard'] = self.contest.hide_scoreboard
|
||||
context['hide_contest_scoreboard'] = self.contest.scoreboard_visibility in \
|
||||
(self.contest.SCOREBOARD_AFTER_CONTEST, self.contest.SCOREBOARD_AFTER_PARTICIPATION)
|
||||
return context
|
||||
|
||||
def get_noui_slider_points(self):
|
||||
|
|
|
@ -54,29 +54,14 @@ class OrganizationSelect2View(Select2View):
|
|||
|
||||
class ProblemSelect2View(Select2View):
|
||||
def get_queryset(self):
|
||||
queryset = Problem.objects.filter(Q(code__icontains=self.term) | Q(name__icontains=self.term))
|
||||
if not self.request.user.has_perm('judge.see_private_problem'):
|
||||
filter = Q(is_public=True)
|
||||
if self.request.user.is_authenticated:
|
||||
filter |= Q(authors=self.request.profile) | Q(curators=self.request.profile)
|
||||
queryset = queryset.filter(filter).distinct()
|
||||
return queryset.distinct()
|
||||
return Problem.get_visible_problems(self.request.user) \
|
||||
.filter(Q(code__icontains=self.term) | Q(name__icontains=self.term))
|
||||
|
||||
|
||||
class ContestSelect2View(Select2View):
|
||||
def get_queryset(self):
|
||||
queryset = Contest.objects.filter(Q(key__icontains=self.term) | Q(name__icontains=self.term))
|
||||
if not self.request.user.has_perm('judge.see_private_contest'):
|
||||
queryset = queryset.filter(is_visible=True)
|
||||
if not self.request.user.has_perm('judge.edit_all_contest'):
|
||||
q = Q(is_private=False, is_organization_private=False)
|
||||
if self.request.user.is_authenticated:
|
||||
q |= Q(is_organization_private=True,
|
||||
organizations__in=self.request.profile.organizations.all())
|
||||
q |= Q(is_private=True, private_contestants=self.request.profile)
|
||||
q |= Q(view_contest_scoreboard=self.request.profile)
|
||||
queryset = queryset.filter(q)
|
||||
return queryset
|
||||
return Contest.get_visible_contests(self.request.user) \
|
||||
.filter(Q(key__icontains=self.term) | Q(name__icontains=self.term))
|
||||
|
||||
|
||||
class CommentSelect2View(Select2View):
|
||||
|
@ -119,8 +104,7 @@ class UserSearchSelect2View(BaseListView):
|
|||
class ContestUserSearchSelect2View(UserSearchSelect2View):
|
||||
def get_queryset(self):
|
||||
contest = get_object_or_404(Contest, key=self.kwargs['contest'])
|
||||
if not contest.can_see_scoreboard(self.request.user) or \
|
||||
contest.hide_scoreboard and contest.is_in_contest(self.request.user):
|
||||
if not contest.is_accessible_by(self.request.user) or not contest.can_see_full_scoreboard(self.request.user):
|
||||
raise Http404()
|
||||
|
||||
return Profile.objects.filter(contest_history__contest=contest,
|
||||
|
|
|
@ -43,7 +43,7 @@ from judge.utils.problems import get_result_data
|
|||
from judge.utils.problems import user_authored_ids
|
||||
from judge.utils.problems import user_completed_ids
|
||||
from judge.utils.problems import user_editable_ids
|
||||
from judge.utils.raw_sql import use_straight_join
|
||||
from judge.utils.raw_sql import join_sql_subquery, use_straight_join
|
||||
from judge.utils.views import DiggPaginatorMixin
|
||||
from judge.utils.views import TitleMixin
|
||||
|
||||
|
@ -292,11 +292,9 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
|
|||
queryset=ProblemTranslation.objects.filter(
|
||||
language=self.request.LANGUAGE_CODE), to_attr='_trans'))
|
||||
if self.in_contest:
|
||||
queryset = queryset.filter(
|
||||
contest__participation__contest_id=self.contest.id)
|
||||
if self.contest.hide_scoreboard and self.contest.is_in_contest(self.request.user):
|
||||
queryset = queryset.filter(
|
||||
contest__participation__user=self.request.profile)
|
||||
queryset = queryset.filter(contest_object=self.contest)
|
||||
if not self.contest.can_see_full_scoreboard(self.request.user):
|
||||
queryset = queryset.filter(user=self.request.profile)
|
||||
else:
|
||||
queryset = queryset.select_related(
|
||||
'contest_object').defer('contest_object__description')
|
||||
|
@ -304,12 +302,18 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
|
|||
# This is not technically correct since contest organizers *should* see these, but
|
||||
# the join would be far too messy
|
||||
if not self.request.user.has_perm('judge.see_private_contest'):
|
||||
queryset = queryset.exclude(
|
||||
contest_object_id__in=Contest.objects.filter(hide_scoreboard=True))
|
||||
# Show submissions for any contest you can edit or visible scoreboard
|
||||
contest_queryset = Contest.objects.filter(Q(authors=self.request.profile) |
|
||||
Q(curators=self.request.profile) |
|
||||
Q(scoreboard_visibility=Contest.SCOREBOARD_VISIBLE) |
|
||||
Q(end_time__lt=timezone.now())).distinct()
|
||||
queryset = queryset.filter(Q(user=self.request.profile) |
|
||||
Q(contest_object__in=contest_queryset) |
|
||||
Q(contest_object__isnull=True))
|
||||
|
||||
if self.selected_languages:
|
||||
queryset = queryset.filter(
|
||||
language_id__in=Language.objects.filter(key__in=self.selected_languages))
|
||||
language__in=Language.objects.filter(key__in=self.selected_languages))
|
||||
if self.selected_statuses:
|
||||
queryset = queryset.filter(result__in=self.selected_statuses)
|
||||
|
||||
|
@ -318,14 +322,13 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
|
|||
def get_queryset(self):
|
||||
queryset = self._get_queryset()
|
||||
if not self.in_contest:
|
||||
if not self.request.user.has_perm('judge.see_private_problem'):
|
||||
queryset = queryset.filter(problem__is_public=True)
|
||||
if not self.request.user.has_perm('judge.see_organization_problem'):
|
||||
filter = Q(problem__is_organization_private=False)
|
||||
if self.request.user.is_authenticated:
|
||||
filter |= Q(
|
||||
problem__organizations__in=self.request.profile.organizations.all())
|
||||
queryset = queryset.filter(filter)
|
||||
join_sql_subquery(
|
||||
queryset,
|
||||
subquery=str(Problem.get_visible_problems(self.request.user).distinct().only('id').query),
|
||||
params=[],
|
||||
join_fields=[('problem_id', 'id')],
|
||||
alias='visible_problems',
|
||||
)
|
||||
return queryset
|
||||
|
||||
def get_my_submissions_page(self):
|
||||
|
@ -452,7 +455,7 @@ class ProblemSubmissionsBase(SubmissionsListBase):
|
|||
reverse('problem_detail', args=[self.problem.code]))
|
||||
|
||||
def access_check_contest(self, request):
|
||||
if self.in_contest and not self.contest.can_see_scoreboard(request.user):
|
||||
if self.in_contest and not self.contest.can_see_own_scoreboard(request.user):
|
||||
raise Http404()
|
||||
|
||||
def access_check(self, request):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue