From b3d80b5100301597232b8b9c22fe2bc54c618e9d Mon Sep 17 00:00:00 2001 From: cuom1999 Date: Sun, 27 Dec 2020 19:59:57 -0600 Subject: [PATCH] Add set scoreboard view --- judge/admin/contest.py | 5 ++++- .../0112_contest_view_contest_scoreboard.py | 18 ++++++++++++++++++ judge/models/contest.py | 7 +++++++ judge/views/blog.py | 1 + judge/views/contests.py | 3 +++ judge/views/select2.py | 1 + 6 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 judge/migrations/0112_contest_view_contest_scoreboard.py diff --git a/judge/admin/contest.py b/judge/admin/contest.py index 906fcee..8293708 100644 --- a/judge/admin/contest.py +++ b/judge/admin/contest.py @@ -86,6 +86,7 @@ class ContestForm(ModelForm): 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 def clean(self): cleaned_data = super(ContestForm, self).clean() @@ -100,6 +101,8 @@ class ContestForm(ModelForm): '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: @@ -116,7 +119,7 @@ class ContestAdmin(VersionAdmin): (_('Format'), {'fields': ('format_name', 'format_config')}), (_('Rating'), {'fields': ('is_rated', 'rate_all', 'rating_floor', 'rating_ceiling', 'rate_exclude')}), (_('Access'), {'fields': ('access_code', 'is_private', 'private_contestants', 'is_organization_private', - 'organizations')}), + 'organizations', 'view_contest_scoreboard')}), (_('Justice'), {'fields': ('banned_users',)}), ) list_display = ('key', 'name', 'is_visible', 'is_rated', 'start_time', 'end_time', 'time_limit', 'user_count') diff --git a/judge/migrations/0112_contest_view_contest_scoreboard.py b/judge/migrations/0112_contest_view_contest_scoreboard.py new file mode 100644 index 0000000..9a0dab2 --- /dev/null +++ b/judge/migrations/0112_contest_view_contest_scoreboard.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.17 on 2020-12-28 01:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('judge', '0111_contest_decimal_points'), + ] + + operations = [ + migrations.AddField( + model_name='contest', + name='view_contest_scoreboard', + field=models.ManyToManyField(blank=True, help_text='These users will be able to view the scoreboard.', related_name='view_contest_scoreboard', to='judge.Profile', verbose_name='view contest scoreboard'), + ), + ] diff --git a/judge/models/contest.py b/judge/models/contest.py index 8b5c182..07d3624 100644 --- a/judge/models/contest.py +++ b/judge/models/contest.py @@ -68,6 +68,9 @@ class Contest(models.Model): help_text=_('Whether the scoreboard should remain hidden for the duration ' 'of the contest.'), default=False) + view_contest_scoreboard = models.ManyToManyField(Profile, verbose_name=_('view contest scoreboard'), blank=True, + related_name='view_contest_scoreboard', + help_text=_('These users will be able to view the scoreboard.')) use_clarifications = models.BooleanField(verbose_name=_('no comments'), help_text=_("Use clarification system instead of comments."), default=True) @@ -142,6 +145,8 @@ class Contest(models.Model): return True if user.is_authenticated and self.organizers.filter(id=user.profile.id).exists(): return True + if user.is_authenticated and self.view_contest_scoreboard.filter(id=user.profile.id).exists(): + return True if not self.is_visible: return False if self.start_time is not None and self.start_time > timezone.now(): @@ -212,6 +217,8 @@ class Contest(models.Model): # User is in the group of private contestants if self.private_contestants.filter(id=user.profile.id).exists(): return True + if self.view_contest_scoreboard.filter(id=user.profile.id).exists(): + return True # If the user can view all contests if user.has_perm('judge.see_private_contest'): diff --git a/judge/views/blog.py b/judge/views/blog.py index 9a5744d..5f90c91 100644 --- a/judge/views/blog.py +++ b/judge/views/blog.py @@ -80,6 +80,7 @@ class PostList(ListView): 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() diff --git a/judge/views/contests.py b/judge/views/contests.py index 8e89aad..2ab511d 100644 --- a/judge/views/contests.py +++ b/judge/views/contests.py @@ -70,6 +70,7 @@ class ContestListMixin(object): 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() @@ -254,6 +255,7 @@ class ContestClone(ContestMixin, PermissionRequiredMixin, TitleMixin, SingleObje tags = contest.tags.all() organizations = contest.organizations.all() private_contestants = contest.private_contestants.all() + view_contest_scoreboard = contest.view_contest_scoreboard.all() contest_problems = contest.contest_problems.all() contest.pk = None @@ -265,6 +267,7 @@ class ContestClone(ContestMixin, PermissionRequiredMixin, TitleMixin, SingleObje contest.tags.set(tags) contest.organizations.set(organizations) contest.private_contestants.set(private_contestants) + contest.view_contest_scoreboard.set(view_contest_scoreboard) contest.organizers.add(self.request.profile) for problem in contest_problems: diff --git a/judge/views/select2.py b/judge/views/select2.py index b58b36b..cf8e249 100644 --- a/judge/views/select2.py +++ b/judge/views/select2.py @@ -74,6 +74,7 @@ class ContestSelect2View(Select2View): 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