Skip to content

Commit

Permalink
Attachments visibility follow-up (sio2project#339)
Browse files Browse the repository at this point in the history
* Fix displaying attachments hidden to non-admins

This is a follow-up of sio2project#233, by which only testspackages were handled
somewhat properly. The 'admin_only' field has been added, as the pub_date
alone isn't enough to determine whether the attachment would be visible if
the user wasn't an admin - one example is a ContestAttachment for a round
that starts in the future.

* Fix checking if a testspackage can be downloaded

* Update and extend the tests for testspackages

* Rework the Contest/ProblemAttachment tests
  • Loading branch information
otargowski authored Apr 5, 2024
1 parent 9690e43 commit 0fcee5e
Show file tree
Hide file tree
Showing 11 changed files with 287 additions and 247 deletions.
4 changes: 2 additions & 2 deletions oioioi/acm/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ def render_submission_date(self, submission, shortened=False):
def ranking_controller(self):
return ACMRankingController(self.contest)

def can_see_round(self, request_or_context, round):
def can_see_round(self, request_or_context, round, no_admin=False):
context = self.make_context(request_or_context)
if context.is_admin:
if not no_admin and context.is_admin:
return True
rtimes = self.get_round_times(request_or_context, round)
return rtimes.is_active(context.timestamp)
Expand Down
18 changes: 18 additions & 0 deletions oioioi/base/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,24 @@ def cacher(request):
return cacher


def request_cached_complex(fn):
"""Adds per-request caching for functions which operate on more than a request.
Additional arguments and keyword arguments passed to the wrapped function
must be hashable, which generally means that their type must be immutable.
"""

@functools.wraps(fn)
def cacher(request, *args, **kwargs):
if not hasattr(request, '_cache'):
setattr(request, '_cache', {})
key = (fn, tuple(args), tuple(kwargs.items()))
if key not in request._cache:
request._cache[key] = fn(request, *args, **kwargs)
return request._cache[key]

return cacher


# Generating HTML


Expand Down
2 changes: 1 addition & 1 deletion oioioi/contests/attachment_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def register(self, attachment_generator=None, order=sys.maxsize):
:Parameters:
Function that takes elements from `**kwargs` as arguments and
returns dictionary containing following keys: `category`,
`name`, `description`, `link`, `pub_date`.
`name`, `description`, `link`, `pub_date`, `admin_only`.
"""
if attachment_generator is not None:
self._registry.register(attachment_generator, order)
Expand Down
18 changes: 10 additions & 8 deletions oioioi/contests/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,15 +511,15 @@ def sort_key(round):

return sorted(queryset, key=sort_key)

def can_see_round(self, request_or_context, round):
def can_see_round(self, request_or_context, round, no_admin=False):
"""Determines if the current user is allowed to see the given round.
If not, everything connected with this round will be hidden.
The default implementation checks if the round is not in the future.
"""
context = self.make_context(request_or_context)
if context.is_admin:
if not no_admin and context.is_admin:
return True
rtimes = self.get_round_times(request_or_context, round)
return not rtimes.is_future(context.timestamp)
Expand Down Expand Up @@ -550,7 +550,7 @@ def can_see_ranking(self, request_or_context):
def default_can_see_ranking(self, request_or_context):
return True

def can_see_problem(self, request_or_context, problem_instance):
def can_see_problem(self, request_or_context, problem_instance, no_admin=False):
"""Determines if the current user is allowed to see the given problem.
If not, the problem will be hidden from all lists, so that its name
Expand All @@ -562,9 +562,11 @@ def can_see_problem(self, request_or_context, problem_instance):
context = self.make_context(request_or_context)
if not problem_instance.round:
return False
if context.is_admin:
if not no_admin and context.is_admin:
return True
return self.can_see_round(request_or_context, problem_instance.round)
return self.can_see_round(
request_or_context, problem_instance.round, no_admin=no_admin
)

def can_see_statement(self, request_or_context, problem_instance):
"""Determines if the current user is allowed to see the statement for
Expand Down Expand Up @@ -987,7 +989,7 @@ class PastRoundsHiddenContestControllerMixin(object):
Do not use it with overlapping rounds.
"""

def can_see_round(self, request_or_context, round):
def can_see_round(self, request_or_context, round, no_admin=False):
"""Decides whether the given round should be shown for the given user.
The algorithm is as follows:
Expand All @@ -1006,7 +1008,7 @@ def can_see_round(self, request_or_context, round):
1. Otherwise the decision is made by the superclass method.
"""
context = self.make_context(request_or_context)
if context.is_admin:
if not no_admin and context.is_admin:
return True

rtimes = self.get_round_times(None, round)
Expand All @@ -1022,7 +1024,7 @@ def can_see_round(self, request_or_context, round):
return False

return super(PastRoundsHiddenContestControllerMixin, self).can_see_round(
request_or_context, round
request_or_context, round, no_admin
)


Expand Down
Loading

0 comments on commit 0fcee5e

Please sign in to comment.