Skip to content
Snippets Groups Projects

Reforma orgovského rozhraní ke kolům a soutěžím

1 file
+ 5
0
Compare changes
  • Side-by-side
  • Inline
+ 58
48
@@ -198,31 +198,6 @@ class Rights:
return self.have_right(Right.edit_orgs)
return self.have_right(Right.edit_users)
# Interní rozhodovaní o dostupnosti zadání
def _check_view_statement(self, round: db.Round):
if round.tasks_file is None:
return False
if self.have_right(Right.manage_round):
# Správce kola může vždy všechno
return True
# Pokud už soutěž skončila, přístup k zadání má každý org.
# XXX: Rozhodujeme podle stavu kola, nikoliv soutěže!
if round.state in [db.RoundState.grading, db.RoundState.closed]:
return True
# Od stanoveného času vidí zadání orgové s právem view_statement.
if (self.have_right(Right.view_statement)
and round.state != db.RoundState.preparing
and round.pr_tasks_start is not None
and mo.now >= round.pr_tasks_start):
return True
# Ve zbylých případech jsme konzervativní a zadání neukazujeme
return False
class RoundRights(Rights):
"""Práva ke kolu."""
@@ -237,8 +212,11 @@ class RoundRights(Rights):
# Metody offer_* testují, zda se má v UI nabízet příslušná funkce.
# Skutečnou kontrolu práv dělá až implementace funkce podle stavu soutěže.
def _get_state(self) -> db.RoundState:
return self.round.state
def _is_active(self) -> bool:
return self.round.state not in [db.RoundState.preparing, db.RoundState.closed]
return self._get_state() not in [db.RoundState.preparing, db.RoundState.closed]
def offer_upload_solutions(self) -> bool:
return (self.have_right(Right.upload_submits)
@@ -252,11 +230,47 @@ class RoundRights(Rights):
return (self.have_right(Right.manage_contest)
or (self.have_right(Right.edit_points) and self._is_active()))
def can_view_statement(self) -> bool:
return self._check_view_statement(self.round)
def can_upload_solutions(self) -> bool:
return (self.have_right(Right.upload_submits)
or self.have_right(Right.upload_solutions) and self._get_state() == db.RoundState.running)
def can_upload_feedback(self) -> bool:
return (self.have_right(Right.upload_submits)
or self.have_right(Right.upload_feedback) and self._get_state() == db.RoundState.grading)
def can_edit_points(self) -> bool:
return (self.have_right(Right.edit_points) and self._get_state() == db.RoundState.grading
or self.have_right(Right.manage_contest))
def can_create_solutions(self) -> bool:
return self.can_upload_solutions() or self.can_upload_feedback()
class ContestRights(Rights):
def can_view_statement(self):
round = self.round
if round.tasks_file is None:
return False
if self.have_right(Right.manage_round):
# Správce kola může vždy všechno
return True
# Pokud už soutěž skončila, přístup k zadání má každý org.
# XXX: Rozhodujeme podle stavu kola, nikoliv soutěže!
if round.state in [db.RoundState.grading, db.RoundState.closed]:
return True
# Od stanoveného času vidí zadání orgové s právem view_statement.
if (self.have_right(Right.view_statement)
and round.state != db.RoundState.preparing
and round.pr_tasks_start is not None
and mo.now >= round.pr_tasks_start):
return True
# Ve zbylých případech jsme konzervativní a zadání neukazujeme
return False
class ContestRights(RoundRights):
"""Práva k soutěži."""
contest: db.Contest
@@ -264,22 +278,10 @@ class ContestRights(Rights):
def __repr__(self):
ros = " ".join([r.role.name for r in self.user_roles])
ris = " ".join([r.name for r in self.rights])
return f"ContestRights(uid={self.user.user_id} is_admin={self.user.is_admin} contest=#{self.contest.contest_id} roles=<{ros}> rights=<{ris}>)"
def can_upload_solutions(self) -> bool:
return (self.have_right(Right.upload_submits)
or self.have_right(Right.upload_solutions) and self.contest.state == db.RoundState.running)
def can_upload_feedback(self) -> bool:
return (self.have_right(Right.upload_submits)
or self.have_right(Right.upload_feedback) and self.contest.state == db.RoundState.grading)
return f"ContestRights(uid={self.user.user_id} is_admin={self.user.is_admin} round=#{self.round.round_id} contest=#{self.contest.contest_id} roles=<{ros}> rights=<{ris}>)"
def can_edit_points(self) -> bool:
return (self.have_right(Right.edit_points) and self.contest.state == db.RoundState.grading
or self.have_right(Right.manage_contest))
def can_view_statement(self) -> bool:
return self._check_view_statement(self.contest.round)
def _get_state(self) -> db.RoundState:
return self.contest.state
class Gatekeeper:
@@ -299,12 +301,17 @@ class Gatekeeper:
self.parent_cache = {}
self.rights_cache = {}
def get_parents(self, place: db.Place) -> List[db.Place]:
def get_ancestors(self, place: db.Place) -> List[db.Place]:
pid = place.place_id
if pid not in self.parent_cache:
self.parent_cache[pid] = db.get_place_parents(place)
self.parent_cache[pid] = db.get_place_ancestors(place)
return self.parent_cache[pid]
def is_ancestor_of(self, ancestor: db.Place, of: db.Place) -> bool:
ancestors = self.get_ancestors(of)
parent_ids = set(p.place_id for p in ancestors)
return ancestor.place_id in parent_ids
def rights_for(
self, place: Optional[db.Place] = None, year: Optional[int] = None,
cat: Optional[str] = None, seq: Optional[int] = None,
@@ -336,7 +343,7 @@ class Gatekeeper:
for role in self.roles:
try_role(role, None)
else:
for at in self.get_parents(place):
for at in self.get_ancestors(place):
for role in self.roles:
try_role(role, at)
@@ -347,9 +354,11 @@ class Gatekeeper:
"""Posbírá role a práva, ale ignoruje omezení rolí na místa a soutěže. Hodí se pro práva k editaci uživatelů apod."""
return self.rights_for()
def rights_for_round(self, round: db.Round, any_place: bool) -> RoundRights:
def rights_for_round(self, round: db.Round, any_place: bool = False, for_place: Optional[db.Place] = None) -> RoundRights:
if any_place:
place = None
elif for_place:
place = for_place
else:
place = db.get_root_place()
rights = RoundRights()
@@ -364,6 +373,7 @@ class Gatekeeper:
def rights_for_contest(self, contest: db.Contest, site: Optional[db.Place] = None) -> ContestRights:
rights = ContestRights()
rights.round = contest.round
rights.contest = contest
rights._clone_from(self.rights_for(
place=site or contest.place,
Loading