diff --git a/judge/models/comment.py b/judge/models/comment.py index 1fb0906ada..0756c7c7b3 100644 --- a/judge/models/comment.py +++ b/judge/models/comment.py @@ -15,7 +15,7 @@ from judge.models.contest import Contest from judge.models.interface import BlogPost -from judge.models.problem import Problem +from judge.models.problem import Problem, Solution from judge.models.profile import Profile from judge.utils.cachedict import CacheDict @@ -62,10 +62,12 @@ def most_recent(cls, user, n, batch=None): .defer('author__about', 'body').order_by('-id') problem_cache = CacheDict(lambda code: Problem.objects.defer('description', 'summary').get(code=code)) + solution_cache = CacheDict(lambda code: Solution.objects.defer('content').get(problem__code=code)) contest_cache = CacheDict(lambda key: Contest.objects.defer('description').get(key=key)) blog_cache = CacheDict(lambda id: BlogPost.objects.defer('summary', 'content').get(id=id)) problem_access = CacheDict(lambda code: problem_cache[code].is_accessible_by(user)) + solution_access = CacheDict(lambda code: problem_access[code] and solution_cache[code].is_accessible_by(user)) contest_access = CacheDict(lambda key: contest_cache[key].is_accessible_by(user)) blog_access = CacheDict(lambda id: blog_cache[id].can_see(user)) @@ -78,29 +80,26 @@ def most_recent(cls, user, n, batch=None): break for comment in slice: page_key = comment.page[2:] - if comment.page.startswith('p:') or comment.page.startswith('s:'): - try: - if problem_access[page_key]: - comment.page_title = problem_cache[page_key].name - output.append(comment) - except Problem.DoesNotExist: - pass - elif comment.page.startswith('c:'): - try: - if contest_access[page_key]: - comment.page_title = contest_cache[page_key].name - output.append(comment) - except Contest.DoesNotExist: - pass - elif comment.page.startswith('b:'): - try: - if blog_access[page_key]: - comment.page_title = blog_cache[page_key].title - output.append(comment) - except BlogPost.DoesNotExist: - pass + try: + if comment.page.startswith('p:'): + has_access = problem_access[page_key] + comment.page_title = problem_cache[page_key].name + elif comment.page.startswith('s:'): + has_access = solution_access[page_key] + comment.page_title = _('Editorial for %s') % problem_cache[page_key].name + elif comment.page.startswith('c:'): + has_access = contest_access[page_key] + comment.page_title = contest_cache[page_key].name + elif comment.page.startswith('b:'): + has_access = blog_access[page_key] + comment.page_title = blog_cache[page_key].title + else: + has_access = True + except ObjectDoesNotExist: + pass else: - output.append(comment) + if has_access: + output.append(comment) if len(output) >= n: return output return output @@ -150,8 +149,10 @@ def page_title(self): def is_accessible_by(self, user): try: - if self.page.startswith('p:') or self.page.startswith('s:'): + if self.page.startswith('p:'): return Problem.objects.get(code=self.page[2:]).is_accessible_by(user) + elif self.page.startswith('s:'): + return Solution.objects.get(problem__code=self.page[2:]).is_accessible_by(user) elif self.page.startswith('c:'): return Contest.objects.get(key=self.page[2:]).is_accessible_by(user) elif self.page.startswith('b:'): diff --git a/judge/models/problem.py b/judge/models/problem.py index 88dbaa665a..001feff0f5 100644 --- a/judge/models/problem.py +++ b/judge/models/problem.py @@ -9,6 +9,7 @@ from django.db.models.expressions import RawSQL from django.db.models.functions import Coalesce from django.urls import reverse +from django.utils import timezone from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ @@ -460,6 +461,15 @@ def get_absolute_url(self): def __str__(self): return _('Editorial for %s') % self.problem.name + def is_accessible_by(self, user): + if self.is_public and self.publish_on < timezone.now(): + return True + if user.has_perm('judge.see_private_solution'): + return True + if self.problem.is_editable_by(user): + return True + return False + class Meta: permissions = ( ('see_private_solution', _('See hidden solutions')), diff --git a/judge/views/problem.py b/judge/views/problem.py index 5461a05c90..cee7208fb1 100644 --- a/judge/views/problem.py +++ b/judge/views/problem.py @@ -15,7 +15,7 @@ from django.shortcuts import get_object_or_404 from django.template.loader import get_template from django.urls import reverse -from django.utils import timezone, translation +from django.utils import translation from django.utils.functional import cached_property from django.utils.html import escape, format_html from django.utils.safestring import mark_safe @@ -118,10 +118,7 @@ def get_context_data(self, **kwargs): solution = get_object_or_404(Solution, problem=self.object) - if (not solution.is_public or solution.publish_on > timezone.now()) and \ - not self.request.user.has_perm('judge.see_private_solution') or \ - (self.request.user.is_authenticated and - self.request.profile.current_contest): + if not solution.is_accessible_by(self.request.user) or self.request.in_contest: raise Http404() context['solution'] = solution context['has_solved_problem'] = self.object.id in self.get_completed_problems() diff --git a/templates/problem/problem.html b/templates/problem/problem.html index 65bd6a3e9d..1f7e4c2643 100644 --- a/templates/problem/problem.html +++ b/templates/problem/problem.html @@ -126,8 +126,7 @@

{{ title }}

{% endif %}
{{ _('All submissions') }}
{{ _('Best submissions') }}
- {% if editorial and editorial.is_public and - not (request.user.is_authenticated and request.profile.current_contest) %} + {% if (editorial and editorial.is_accessible_by(request.user)) and not request.in_contest %}
{{ _('Read editorial') }}
{% endif %}