Skip to content
Snippets Groups Projects
Commit 42e12f74 authored by Martin Mareš's avatar Martin Mareš
Browse files

UI pro dávkové bodování

parent ee6af9ef
No related branches found
No related tags found
1 merge request!32Dávkové bodování
This commit is part of merge request !30. Comments created here will be created in the context of that merge request.
...@@ -615,6 +615,7 @@ def get_solution_context(contest_id: int, user_id: Optional[int], task_id: Optio ...@@ -615,6 +615,7 @@ def get_solution_context(contest_id: int, user_id: Optional[int], task_id: Optio
user=user, user=user,
task=task, task=task,
site=site, site=site,
# XXX: Potřebujeme tohle všechno? Nechceme spíš vracet rr a nechat každého, ať na něm volá metody?
allow_view=allow_view, allow_view=allow_view,
allow_upload_solutions=rr.can_upload_solutions(round), allow_upload_solutions=rr.can_upload_solutions(round),
allow_upload_feedback=rr.can_upload_feedback(round), allow_upload_feedback=rr.can_upload_feedback(round),
...@@ -1153,6 +1154,69 @@ def org_contest_task_upload(contest_id: int, task_id: int, site_id: Optional[int ...@@ -1153,6 +1154,69 @@ def org_contest_task_upload(contest_id: int, task_id: int, site_id: Optional[int
can_upload_feedback=sc.allow_upload_feedback) can_upload_feedback=sc.allow_upload_feedback)
class BatchPointsForm(FlaskForm):
file = flask_wtf.file.FileField("Soubor")
fmt = wtforms.SelectField(
"Formát souboru",
choices=FileFormat.choices(), coerce=FileFormat.coerce,
default=FileFormat.cs_csv,
)
submit = wtforms.SubmitField('Nahrát body')
get_template = wtforms.SubmitField('Stáhnout šablonu')
def generic_batch_points(round: db.Round, contest: Optional[db.Contest], task: db.Task):
"""Společná funkce pro download/upload bodů do soutěží a kol."""
form = BatchPointsForm()
errs = []
if form.validate_on_submit():
fmt = form.fmt.data
imp = create_import(user=g.user, type=ImportType.points, fmt=fmt, round=round, contest=contest, task=task)
if form.submit.data:
if form.file.data is not None:
file = form.file.data.stream
import_tmp = mo.util.link_to_dir(file.name, mo.util.data_dir('imports'), suffix='.csv')
if imp.run(import_tmp):
if imp.cnt_rows == 0:
flash('Soubor neobsahoval žádné řádky s daty', 'danger')
else:
flash(f'Importováno ({imp.cnt_rows} řádků, změněny body u {imp.cnt_set_points} řešení)', 'success')
if contest is not None:
return redirect(url_for('org_contest', id=contest.contest_id))
else:
return redirect(url_for('org_round', id=round.round_id))
else:
errs = imp.errors
else:
flash('Vyberte si prosím soubor', 'danger')
elif form.get_template.data:
out = imp.get_template()
resp = app.make_response(out)
resp.content_type = fmt.get_content_type()
resp.headers.add('Content-Disposition', 'attachment; filename=OSMO-' + imp.template_basename + '.' + fmt.get_extension())
return resp
return render_template(
'org_generic_batch_points.html',
round=round, contest=contest, task=task,
form=form,
errs=errs,
)
@app.route('/org/contest/c/<int:contest_id>/task/<int:task_id>/batch-points', methods=('GET', 'POST'))
def org_contest_task_batch_points(contest_id: int, task_id: int):
sc = get_solution_context(contest_id, None, task_id, None)
assert sc.task is not None
if not sc.allow_edit_points:
raise werkzeug.exceptions.Forbidden()
return generic_batch_points(round=sc.round, contest=sc.contest, task=sc.task)
@app.route('/org/contest/c/<int:contest_id>/user/<int:user_id>') @app.route('/org/contest/c/<int:contest_id>/user/<int:user_id>')
def org_contest_user(contest_id: int, user_id: int): def org_contest_user(contest_id: int, user_id: int):
sc = get_solution_context(contest_id, user_id, None, None) sc = get_solution_context(contest_id, user_id, None, None)
... ...
......
import datetime
from flask import render_template, g, redirect, url_for, flash, request from flask import render_template, g, redirect, url_for, flash, request
import locale import locale
from flask_wtf.form import FlaskForm from flask_wtf.form import FlaskForm
...@@ -17,7 +16,7 @@ from mo.rights import Right, Rights ...@@ -17,7 +16,7 @@ from mo.rights import Right, Rights
import mo.util import mo.util
from mo.web import app from mo.web import app
from mo.web.org_contest import ParticipantsActionForm, ParticipantsFilterForm, get_contestants_query, make_contestant_table, \ from mo.web.org_contest import ParticipantsActionForm, ParticipantsFilterForm, get_contestants_query, make_contestant_table, \
generic_import, generic_batch_download, generic_batch_upload generic_import, generic_batch_download, generic_batch_upload, generic_batch_points
def get_round(id: int) -> db.Round: def get_round(id: int) -> db.Round:
...@@ -38,6 +37,13 @@ def get_round_rr(id: int, right_needed: Optional[Right], any_place: bool) -> Tup ...@@ -38,6 +37,13 @@ def get_round_rr(id: int, right_needed: Optional[Right], any_place: bool) -> Tup
return round, rr return round, rr
def get_task(round: db.Round, task_id: int) -> db.Task:
task = db.get_session().query(db.Task).get(task_id)
if not task or task.round_id != round.round_id:
raise werkzeug.exceptions.NotFound()
return task
@app.route('/org/contest/') @app.route('/org/contest/')
def org_rounds(): def org_rounds():
sess = db.get_session() sess = db.get_session()
...@@ -271,30 +277,27 @@ def org_round_task_edit(id: int, task_id: int): ...@@ -271,30 +277,27 @@ def org_round_task_edit(id: int, task_id: int):
@app.route('/org/contest/r/<int:round_id>/task/<int:task_id>/download', methods=('GET', 'POST')) @app.route('/org/contest/r/<int:round_id>/task/<int:task_id>/download', methods=('GET', 'POST'))
def org_round_task_download(round_id: int, task_id: int): def org_round_task_download(round_id: int, task_id: int):
sess = db.get_session()
round, rr = get_round_rr(round_id, Right.view_submits, False) round, rr = get_round_rr(round_id, Right.view_submits, False)
task = get_task(round, task_id)
task = sess.query(db.Task).get(task_id)
if not task or task.round_id != round_id:
raise werkzeug.exceptions.NotFound()
return generic_batch_download(round=round, contest=None, site=None, task=task) return generic_batch_download(round=round, contest=None, site=None, task=task)
@app.route('/org/contest/r/<int:round_id>/task/<int:task_id>/upload', methods=('GET', 'POST')) @app.route('/org/contest/r/<int:round_id>/task/<int:task_id>/upload', methods=('GET', 'POST'))
def org_round_task_upload(round_id: int, task_id: int): def org_round_task_upload(round_id: int, task_id: int):
sess = db.get_session()
round, rr = get_round_rr(round_id, Right.view_submits, False) round, rr = get_round_rr(round_id, Right.view_submits, False)
task = get_task(round, task_id)
task = sess.query(db.Task).get(task_id)
if not task or task.round_id != round_id:
raise werkzeug.exceptions.NotFound()
return generic_batch_upload(round=round, contest=None, site=None, task=task, return generic_batch_upload(round=round, contest=None, site=None, task=task,
can_upload_solutions=rr.can_upload_solutions(round), can_upload_solutions=rr.can_upload_solutions(round),
can_upload_feedback=rr.can_upload_feedback(round)) can_upload_feedback=rr.can_upload_feedback(round))
@app.route('/org/contest/r/<int:round_id>/task/<int:task_id>/batch-points', methods=('GET', 'POST'))
def org_round_task_batch_points(round_id: int, task_id: int):
round, rr = get_round_rr(round_id, Right.edit_points, True)
task = get_task(round, task_id)
return generic_batch_points(round=round, contest=None, task=task)
@app.route('/org/contest/r/<int:id>/list', methods=('GET', 'POST')) @app.route('/org/contest/r/<int:id>/list', methods=('GET', 'POST'))
def org_round_list(id: int): def org_round_list(id: int):
round, rr = get_round_rr(id, Right.manage_contest, True) round, rr = get_round_rr(id, Right.manage_contest, True)
... ...
......
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Dávkové bodování úlohy {{ task.code }} {{ task.name }}{% endblock %}
{% block breadcrumbs %}
{{ contest_breadcrumbs(round=round, contest=contest, task=task, action="Dávkové bodování") }}
{% endblock %}
{% block body %}
{% if errs %}
<h3>Chyby při importu</h3>
<pre><div class="alert alert-danger" role="alert">{{ "" -}}
{% for e in errs %}
{{ e }}
{% endfor %}
</div></pre>
{% endif %}
<p>Zde si můžete stáhnout bodovací formulář v zadaném formátu a pak ho nahrát zpět
s vyplněnými body.
{{ wtf.quick_form(form, form_type='simple', button_map={'submit': 'primary'}) }}
{% endblock %}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment