Skip to content
Snippets Groups Projects
Commit 9cf17b66 authored by Jiří Setnička's avatar Jiří Setnička
Browse files

Vytváření řešení ze stránky úlohy

Vytvořen nový endpoint org_contest_task_create. Vše v pozadí obsluhuje
stejná univerzální tabulka, jen na správných místech vypisuje správné
formuláře ve správném módu (má teď mód zobrazení, zakládání řešení a
bodování).

Přidány odkazy z různých míst.
parent 7b97ac14
Branches
No related tags found
1 merge request!30Zakládání řešení zadáváním bodů
This commit is part of merge request !30. Comments created here will be created in the context of that merge request.
...@@ -903,20 +903,24 @@ class TaskPointsForm(FlaskForm): ...@@ -903,20 +903,24 @@ class TaskPointsForm(FlaskForm):
submit = wtforms.SubmitField("Uložit body") submit = wtforms.SubmitField("Uložit body")
class TaskCreateForm(FlaskForm):
submit = wtforms.SubmitField("Založit označená řešení")
@app.route('/org/contest/c/<int:contest_id>/task/<int:task_id>/') @app.route('/org/contest/c/<int:contest_id>/task/<int:task_id>/')
@app.route('/org/contest/c/<int:contest_id>/site/<int:site_id>/task/<int:task_id>/') @app.route('/org/contest/c/<int:contest_id>/site/<int:site_id>/task/<int:task_id>/')
@app.route('/org/contest/c/<int:contest_id>/task/<int:task_id>/points', methods=('GET', 'POST'), endpoint="org_contest_task_points") @app.route('/org/contest/c/<int:contest_id>/task/<int:task_id>/points', methods=('GET', 'POST'), endpoint="org_contest_task_points")
@app.route('/org/contest/c/<int:contest_id>/task/<int:task_id>/create', methods=('GET', 'POST'), endpoint="org_contest_task_create")
@app.route('/org/contest/c/<int:contest_id>/site/<int:site_id>/task/<int:task_id>/create', methods=('GET', 'POST'), endpoint="org_contest_task_create")
def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = None): def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = None):
sc = get_solution_context(contest_id, None, task_id, site_id) sc = get_solution_context(contest_id, None, task_id, site_id)
edit_points = request.endpoint == "org_contest_task_points" action_create = request.endpoint == "org_contest_task_create"
if edit_points: action_points = request.endpoint == "org_contest_task_points"
assert site_id is None if action_create and not sc.allow_create_solutions:
if not sc.allow_edit_points: raise werkzeug.exceptions.Forbidden()
if action_points and not sc.allow_edit_points:
raise werkzeug.exceptions.Forbidden() raise werkzeug.exceptions.Forbidden()
if sc.round.state != db.RoundState.grading:
flash("Kolo není ve stavu opravování, nelze zadávat body", "warning")
return redirect(url_for('org_contest_task', contest_id=contest_id, task_id=task_id))
sess = db.get_session() sess = db.get_session()
...@@ -925,8 +929,41 @@ def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = Non ...@@ -925,8 +929,41 @@ def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = Non
rows.sort(key=lambda r: r[0].user.sort_key()) rows.sort(key=lambda r: r[0].user.sort_key())
points_form: Optional[TaskPointsForm] = None points_form: Optional[TaskPointsForm] = None
create_form: Optional[TaskCreateForm] = None
if action_create:
create_form = TaskCreateForm()
if create_form.validate_on_submit():
new_sol_count = 0
for pion, sol in rows:
if sol:
continue # již existuje
if not request.form.get(f"create_sol_{pion.user_id}"):
continue # nikdo nežádá o vytvoření
sol = db.Solution(task=sc.task, user=pion.user)
sess.add(sol)
mo.util.log(
type=db.LogType.participant,
what=pion.user_id,
details={
'action': 'solution-created',
'task': task_id,
},
)
app.logger.info(f"Řešení úlohy {sc.task.code} od účastníka {pion.user_id} založeno")
new_sol_count += 1
if edit_points: if new_sol_count > 0:
sess.commit()
flash(inflect_by_number(new_sol_count, "Založeno", "Založena", "Založeno") + ' '
+ inflect_number(new_sol_count, "nové řešení", "nová řešení", "nových řešení"),
"success")
else:
flash("Žádné změny k uložení", "info")
return redirect(url_for('org_contest_task', contest_id=contest_id, task_id=task_id, site_id=site_id))
if action_points:
points_form = TaskPointsForm() points_form = TaskPointsForm()
if points_form.validate_on_submit(): if points_form.validate_on_submit():
count = 0 count = 0
...@@ -935,10 +972,13 @@ def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = Non ...@@ -935,10 +972,13 @@ def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = Non
if sol is None: if sol is None:
continue continue
points = request.form.get(f"points_{sol.user_id}", type=int) points = request.form.get(f"points_{sol.user_id}", type=int)
if points and points < 0: if points is None:
continue
if points < 0:
flash('Nelze zadat záporné body', 'danger') flash('Nelze zadat záporné body', 'danger')
ok = False ok = False
break break
if points != sol.points: if points != sol.points:
# Save points # Save points
sol.points = points sol.points = points
...@@ -953,7 +993,7 @@ def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = Non ...@@ -953,7 +993,7 @@ def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = Non
if ok: if ok:
if count > 0: if count > 0:
sess.commit() sess.commit()
flash("Změněny body u " + inflect_number(count, "řešitele", "řešitelů", "řešitelů"), "success") flash("Změněny body u " + inflect_number(count, "řešení", "řešení", "řešení"), "success")
else: else:
flash("Žádné změny k uložení", "info") flash("Žádné změny k uložení", "info")
return redirect(url_for('org_contest_task', contest_id=contest_id, task_id=task_id)) return redirect(url_for('org_contest_task', contest_id=contest_id, task_id=task_id))
...@@ -972,8 +1012,7 @@ def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = Non ...@@ -972,8 +1012,7 @@ def org_contest_task(contest_id: int, task_id: int, site_id: Optional[int] = Non
"org_contest_task.html", "org_contest_task.html",
sc=sc, rows=rows, paper_counts=paper_counts, sc=sc, rows=rows, paper_counts=paper_counts,
paper_link=lambda u, p: mo.web.util.org_paper_link(sc.contest, sc.site, u, p), paper_link=lambda u, p: mo.web.util.org_paper_link(sc.contest, sc.site, u, p),
can_upload=sc.allow_upload_feedback, points_form=points_form, create_form=create_form, request_form=request.form,
points_form=points_form, request_form=request.form,
) )
......
...@@ -98,6 +98,9 @@ ...@@ -98,6 +98,9 @@
{% if can_upload %} {% if can_upload %}
<a class='btn btn-xs btn-primary' href="{{ url_for('org_contest_task_upload', contest_id=contest.contest_id, task_id=task.task_id, site_id=site_id) }}">Nahrát</a> <a class='btn btn-xs btn-primary' href="{{ url_for('org_contest_task_upload', contest_id=contest.contest_id, task_id=task.task_id, site_id=site_id) }}">Nahrát</a>
{% endif %} {% endif %}
{% if can_create_solutions %}
<a class="btn btn-xs btn-primary" href="{{ url_for('org_contest_task_create', contest_id=contest.contest_id, task_id=task.task_id, site_id=site_id) }}">Založit řešení</a>
{% endif %}
{% if not site and can_edit_points %} {% if not site and can_edit_points %}
<a class="btn btn-xs btn-primary" href="{{ url_for('org_contest_task_points', contest_id=contest.contest_id, task_id=task.task_id) }}">Zadat body</a> <a class="btn btn-xs btn-primary" href="{{ url_for('org_contest_task_points', contest_id=contest.contest_id, task_id=task.task_id) }}">Zadat body</a>
<a class="btn btn-xs btn-default" href="{{ url_for('org_contest_task_batch_points', contest_id=contest.contest_id, task_id=task.task_id) }}">Nahrát body</a> <a class="btn btn-xs btn-default" href="{{ url_for('org_contest_task_batch_points', contest_id=contest.contest_id, task_id=task.task_id) }}">Nahrát body</a>
......
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
{% set site_id = site.place_id if site else None %} {% set site_id = site.place_id if site else None %}
{% set task = sc.task %} {% set task = sc.task %}
{% block title %}{% if points_form %}Editace bodů{% else %}Odevzdaná řešení{% endif %} úlohy {{ task.code }} {{ task.name }}{% endblock %} {% block title %}{{ "Zadávání bodů" if points_form else "Založení řešení" if create_form else "Odevzdaná řešení" }} úlohy {{ task.code }} {{ task.name }}{% endblock %}
{% block breadcrumbs %} {% block breadcrumbs %}
{{ contest_breadcrumbs(round=round, contest=contest, site=site, task=task, action="Editace bodů" if points_form else None) }} {{ contest_breadcrumbs(round=round, contest=contest, site=site, task=task, action="Zadávání bodů" if points_form else "Založení řešení" if create_form else None) }}
{% endblock %} {% endblock %}
{% block body %} {% block body %}
...@@ -23,17 +23,18 @@ ...@@ -23,17 +23,18 @@
{% include "parts/org_submit_warning.html" %} {% include "parts/org_submit_warning.html" %}
{% if points_form %} {% set form = points_form or create_form %}
{% if form %}
<form class="form" method="POST"> <form class="form" method="POST">
{{ points_form.csrf_token }} {{ form.csrf_token }}
{% endif %} {% endif %}
{% with for_user=None, for_task=task, rows=rows %} {% with for_user=None, for_task=task, rows=rows %}
{% include "parts/org_solution_table.html" %} {% include "parts/org_solution_table.html" %}
{% endwith %} {% endwith %}
{% if points_form %} {% if form %}
<div class='btn-group'> <div class='btn-group'>
{{ wtf.form_field(points_form.submit, class="btn btn-primary") }} {{ wtf.form_field(form.submit, class="btn btn-primary" ) }}
<a class="btn btn-default" href="{{ url_for('org_contest_task', contest_id=ct_id, task_id=task.task_id) }}">Zrušit editaci bodů</a> <a class="btn btn-default" href="{{ url_for('org_contest_task', contest_id=ct_id, task_id=task.task_id, site_id=site_id) }}">Zrušit</a>
</div> </div>
</form> </form>
{% else %} {% else %}
...@@ -42,6 +43,9 @@ ...@@ -42,6 +43,9 @@
{% if sc.allow_upload_feedback %} {% if sc.allow_upload_feedback %}
<a class='btn btn-primary' href="{{ url_for('org_contest_task_upload', contest_id=ct_id, site_id=site_id, task_id=task.task_id) }}">Nahrát opravená řešení</a> <a class='btn btn-primary' href="{{ url_for('org_contest_task_upload', contest_id=ct_id, site_id=site_id, task_id=task.task_id) }}">Nahrát opravená řešení</a>
{% endif %} {% endif %}
{% if sc.allow_create_solutions %}
<a class="btn btn-primary" href="{{ url_for('org_contest_task_create', contest_id=ct_id, task_id=task.task_id, site_id=site_id) }}">Založit řešení</a>
{% endif %}
{% if not site and sc.allow_edit_points %} {% if not site and sc.allow_edit_points %}
<a class="btn btn-primary" href="{{ url_for('org_contest_task_points', contest_id=ct_id, task_id=task.task_id) }}">Zadat body</a> <a class="btn btn-primary" href="{{ url_for('org_contest_task_points', contest_id=ct_id, task_id=task.task_id) }}">Zadat body</a>
{% endif %} {% endif %}
......
<p><i>{% if for_user %}U každé úlohy je zobrazeno účastníkovo {% else %}U každého účastníka je zobrazeno jeho {% endif %} <p><i>
finální řešení, finální oprava a přidělené body. Historii všech odevzdání, oprav a bodů naleznete v detailu řešení. {% if create_form %}
Zaškrtnutím políček u řešení, která dosud neexistují, a odesláním tlačítkem pod tabulkou tato řešení založíte.
To se hodí, pokud se nechystáte do systému nahrávat soubory řešení, ale jen chcete řešení vytvořit, aby jim
bylo možné vyplnit body. Pokud nějaké řešení založíte omylem, lze toto prázdné řešení smazat v jeho detailu.
{% else %}
Historii všech odevzdání, oprav a bodů pro každé řešení naleznete v jeho detailu.
{% if sc.allow_upload_feedback or sc.allow_edit_points %}Tamtéž můžete odevzdávat nové verze a změnit, které řešení/oprava je {% if sc.allow_upload_feedback or sc.allow_edit_points %}Tamtéž můžete odevzdávat nové verze a změnit, které řešení/oprava je
finální (ve výchozím stavu poslední nahrané).{% endif %} finální (ve výchozím stavu poslední nahrané).{% elif sc.allow_upload_solutions %}Tamtéž můžete odevzdat nové řešení.{% endif %}
{% if for_task and sc.allow_create_solutions %} Hromadně založit řešení pro více řešitelů můžete pomocí tlačítek pod tabulkou.{% endif %}
{% endif %}
</i></p> </i></p>
<p><i>Legenda k symbolům: <span class='sol-warn icon'></span> odevzdané po termínu, <p><i>Legenda: <span class='sol-warn icon'></span> odevzdané po termínu,
<span class="icon">🛈</span> nahráno někým jiným, než řešitelem, <span class="icon">🗐</span> existuje více verzí. Symboly po najetí myší zobrazí bližší informace. <span class="icon">🛈</span> nahráno někým jiným, než řešitelem, <span class="icon">🗐</span> existuje více verzí. Symboly po najetí myší zobrazí bližší informace.
</i></p> </i></p>
...@@ -15,11 +22,11 @@ finální (ve výchozím stavu poslední nahrané).{% endif %} ...@@ -15,11 +22,11 @@ finální (ve výchozím stavu poslední nahrané).{% endif %}
{% if for_task %}<th>Stav účasti{% endif %} {% if for_task %}<th>Stav účasti{% endif %}
<th>Finální řešení <th>Finální řešení
<th>Finální oprava <th>Finální oprava
<th>Poznámky
<th>Přidělené body <th>Přidělené body
{% if not for_user and not site and sc.allow_edit_points and not points_form %} {% if not for_user and not site and sc.allow_edit_points and not points_form %}
<a title="Editovat body" href="{{ url_for('org_contest_task_points', contest_id=contest.contest_id, task_id=task.task_id) }}" class="icon pull-right"></a> <a title="Editovat body" href="{{ url_for('org_contest_task_points', contest_id=contest.contest_id, task_id=task.task_id) }}" class="icon pull-right"></a>
{% endif %} {% endif %}
<th>Poznámky
<th>Akce <th>Akce
</tr> </tr>
</thead> </thead>
...@@ -73,19 +80,25 @@ finální (ve výchozím stavu poslední nahrané).{% endif %} ...@@ -73,19 +80,25 @@ finální (ve výchozím stavu poslední nahrané).{% endif %}
<span title="Celkem {{ paper_counts[key]|inflected('verze', 'verze', 'verzí') }}" class="icon">🗐</span> <span title="Celkem {{ paper_counts[key]|inflected('verze', 'verze', 'verzí') }}" class="icon">🗐</span>
{% endif %} {% endif %}
{% else %}–{% endif %} {% else %}–{% endif %}
<td>{% if points_form %} <td style="text-align: center;">
<input type="number" class="form-control" name="points_{{sol.user_id}}" value="{{ request_form.get("points_{}".format(sol.user_id)) or sol.points }}" size="4"> {% if sol.note %}<span class="icon" title="Poznámka pro řešitele: {{ sol.note }}">🗩</span>{% endif %}
{% if sol.org_note %} <span class="icon" title="Interní poznámka: {{ sol.org_note }}">🗩</span>{% endif %}
<td>
{% if points_form %}
<input type="number" class="form-control" name="points_{{u.user_id}}" value="{{ request_form.get("points_{}".format(u.user_id)) or sol.points }}" size="4">
{% else %} {% else %}
{% if sol.points is not none %}{{ sol.points}}{% else %}<span class="unknown">?</span>{% endif %} {% if sol.points is not none %}{{ sol.points}}{% else %}<span class="unknown">?</span>{% endif %}
{% endif %} {% endif %}
{% else %} {% else %}
<td><td><td> <td colspan="4" class="text-center">
{% if create_form %}
<input type="checkbox" name="create_sol_{{u.user_id}}" id="create_sol_{{u.user_id}}"{% if request_form.get("create_sol_{}".format(u.user_id)) %}checked{% endif %}>
<label for="create_sol_{{u.user_id}}">Založit řešení</label>
{% else %}–{% endif %}
{% endif %} {% endif %}
<td style="text-align: center;"> <td><div class="btn-group">
{% if sol and sol.note %}<span class="icon" title="Poznámka pro řešitele: {{ sol.note }}">🗩</span>{% endif %}
{% if sol and sol.org_note %} <span class="icon" title="Interní poznámka: {{ sol.org_note }}">🗩</span>{% endif %}
<td>
<a class="btn btn-xs btn-primary" href="{{ url_for('org_submit_list', contest_id=ct_id, user_id=u.user_id, task_id=task.task_id, site_id=site_id) }}">Detail</a> <a class="btn btn-xs btn-primary" href="{{ url_for('org_submit_list', contest_id=ct_id, user_id=u.user_id, task_id=task.task_id, site_id=site_id) }}">Detail</a>
</div>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
...@@ -172,6 +172,13 @@ nav#main-menu a.active { ...@@ -172,6 +172,13 @@ nav#main-menu a.active {
border-radius: 4px 4px; border-radius: 4px 4px;
} }
.checked_toggle input.toggle:checked ~ .checked_hide {
display: none;
}
.checked_toggle input.toggle:not(:checked) ~ .checked_show {
display: none;
}
/* Round states */ /* Round states */
.rstate-preparing { .rstate-preparing {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment