Skip to content
Snippets Groups Projects

WIP: Zárodek uživatelské části webu a submitování

Closed Martin Mareš requested to merge devel into master
Compare and Show latest version
4 files
+ 127
14
Compare changes
  • Side-by-side
  • Inline

Files

+ 120
10
from dataclasses import dataclass
from flask import render_template, g, redirect, url_for, flash, request
from flask_wtf import FlaskForm
import flask_wtf.file
@@ -15,6 +16,7 @@ import mo.csv
import mo.db as db
import mo.imports
import mo.rights
from mo.rights import Right, Rights
import mo.util
from mo.web import app
from mo.web.util import PagerForm
@@ -62,7 +64,7 @@ class ParticipantsActionForm(FlaskForm):
remove_participation = wtforms.SubmitField("Smazat záznam o účasti")
def do_action(self, round: db.Round, rights: mo.rights.Rights, query: Query) -> bool:
def do_action(self, round: db.Round, rights: Rights, query: Query) -> bool:
"""Do participation modification on partipations from given query
(possibly filtered by checkboxes). `rights` param is used to check rights
for contest of each modified participation or for contest in which
@@ -91,7 +93,7 @@ class ParticipantsActionForm(FlaskForm):
flash(f"Nepovedlo se najít soutěž v kole {round.round_code()} v oblasti {contest_place.name}", 'danger')
return False
rights.get_for_contest(contest)
if not rights.have_right(mo.rights.Right.manage_contest):
if not rights.have_right(Right.manage_contest):
flash(f"Nemáte právo ke správě soutěže v kole {round.round_code()} v oblasti {contest_place.name}, nelze do ní přesunout účastníky", 'danger')
return False
elif self.remove_participation.data:
@@ -116,7 +118,7 @@ class ParticipantsActionForm(FlaskForm):
if pion.contest_id in rights_cache:
continue
rights.get_for_contest(pion.contest)
if rights.have_right(mo.rights.Right.manage_contest):
if rights.have_right(Right.manage_contest):
rights_cache.add(pion.contest_id)
continue
flash(
@@ -182,10 +184,10 @@ def get_contest(id: int) -> db.Contest:
return contest
def get_contest_rr(id: int, right_needed: Optional[mo.rights.Right] = None) -> Tuple[db.Contest, mo.rights.Rights]:
def get_contest_rr(id: int, right_needed: Optional[Right] = None) -> Tuple[db.Contest, Rights]:
contest = get_contest(id)
rr = mo.rights.Rights(g.user)
rr = Rights(g.user)
rr.get_for_contest(contest)
if not (right_needed is None or rr.have_right(right_needed)):
@@ -202,13 +204,13 @@ def org_contest(id: int):
'org_contest.html',
contest=contest,
rights=sorted(rr.current_rights, key=lambda r: r. name),
can_manage=rr.have_right(mo.rights.Right.manage_contest),
can_manage=rr.have_right(Right.manage_contest),
)
@app.route('/org/contest/c/<int:id>/import', methods=('GET', 'POST'))
def org_contest_import(id: int):
contest, rr = get_contest_rr(id, mo.rights.Right.manage_contest)
contest, rr = get_contest_rr(id, Right.manage_contest)
form = ImportForm()
errs = []
@@ -249,7 +251,7 @@ def org_contest_import_template():
@app.route('/org/contest/c/<int:id>/ucastnici', methods=('GET', 'POST'))
def org_contest_list(id: int):
contest, rr = get_contest_rr(id)
can_edit = rr.have_right(mo.rights.Right.manage_contest)
can_edit = rr.have_right(Right.manage_contest)
format = request.args.get('format', "")
filter = ParticipantsFilterForm(request.args)
@@ -371,7 +373,7 @@ def make_contestant_table(query: Query, add_checkbox: bool = False, add_contest_
def org_contest_solutions(id: int):
# FIXME: Práva?
# FIXME: Hlavička stránky podle Jirkova předělání
contest, rr = get_contest_rr(id, mo.rights.Right.manage_contest)
contest, rr = get_contest_rr(id, Right.manage_contest)
format = request.args.get('format', "")
sess = db.get_session()
@@ -444,9 +446,117 @@ def org_contest_solutions(id: int):
return table.send_as(format)
@dataclass
class SolutionContext:
contest: db.Contest
round: db.Round
pion: db.Participation
task: db.Task
solution: Optional[db.Solution]
allow_view: bool
allow_upload_solutions: bool
allow_upload_feedback: bool
def get_solution_context(contest_id: int, site_id: Optional[int], user_id: int, task_id: int) -> SolutionContext:
sess = db.get_session()
# Nejprve zjistíme, zda existuje soutěž
contest = get_contest(contest_id)
round = contest.round
# Zkontrolujeme, zda se účastník opravdu účastní soutěže
pion = (sess.query(db.Participation)
.filter_by(user_id=user_id, contest_id=contest_id)
.options(joinedload(db.Participation.place))
.one_or_none())
if not pion:
raise werkzeug.exceptions.NotFound()
# A zda soutěží na zadaném soutěžním místě, je-li určeno
if site_id is not None and site_id != pion.site_id:
raise werkzeug.exceptions.NotFound()
# Najdeme úlohu a ověříme, že je součástí soutěže
task = sess.query(db.Task).get(task_id)
if not task or task.round_id != round:
raise werkzeug.exceptions.NotFound()
# Najdeme řešení úlohy (nemusí existovat)
sol = (sess.query(db.Solution)
.filter_by(user_id=user_id, task_id=task_id)
.one_or_none())
# Pokud je uvedeno soutěžní místo, hledáme práva k němu, jinak k soutěži
if site_id is not None:
site = pion.place
else:
site = contest.place
rr = Rights(g.user)
rr.get_for_contest_site(contest, site)
# Kdo má právo na jaké operace
allow_upload_solutions = (rr.have_right(Right.manage_contest)
or (rr.have_right(Right.upload_solutions) and round.state == db.RoundState.running))
allow_upload_feedback = (rr.have_right(Right.manage_contest)
or (rr.have_right(Right.upload_feedback) and round.state == db.RoundState.grading))
allow_view = (rr.have_right(Right.manage_contest)
or (rr.have_right(Right.upload_solutions) and round.state in (db.RoundState.running, db.RoundState.grading, db.RoundState.closed))
or (rr.have_right(Right.upload_feedback) and round.state in (db.RoundState.grading, db.RoundState.closed)))
if not allow_view:
raise werkzeug.exceptions.Forbidden()
return SolutionContext(
contest=contest,
round=round,
pion=pion,
task=task,
solution=sol,
allow_view=allow_view,
allow_upload_solutions=allow_upload_solutions,
allow_upload_feedback=allow_upload_feedback,
)
@app.route('/org/contest/c/<int:contest_id>/submit/<int:user_id>/<int:task_id>/')
def org_submit_list(contest_id, user_id, task_id):
sc = get_solution_context(contest_id, None, user_id, task_id)
# FIXME
return render_template('not_implemented.html')
@app.route('/org/contest/c/<int:contest_id>/site/<int:site_id>/submit/<int:user_id>/<int:task_id>/')
def org_submit_site_list(contest_id, site_id, user_id, task_id):
sc = get_solution_context(contest_id, site_id, user_id, task_id)
# FIXME
return render_template('not_implemented.html')
@app.route('/org/contest/c/<int:contest_id>/paper/<int:paper_id>/')
def org_submit_paper(contest_id, paper_id):
# sc = get_solution_context(contest_id, None, user_id, task_id)
# FIXME
return render_template('not_implemented.html')
@app.route('/org/contest/c/<int:contest_id>/site/<int:site_id>/paper/<int:paper_id>/')
def org_submit_site_paper(contest_id, paper_id):
# sc = get_solution_context(contest_id, None, user_id, task_id)
# FIXME
return render_template('not_implemented.html')
@app.route('/org/contest/c/<int:id>/proctor-import', methods=('GET', 'POST'))
def org_proctor_import(id: int):
contest, rr = get_contest_rr(id, mo.rights.Right.manage_contest)
contest, rr = get_contest_rr(id, Right.manage_contest)
form = ImportForm()
errs = []
Loading