diff --git a/mo/web/org_round.py b/mo/web/org_round.py index 993c0904896bdbc4798f4513c41ae63d4ef3e440..08864412158c168f58e4f9da01678caa96939e78 100644 --- a/mo/web/org_round.py +++ b/mo/web/org_round.py @@ -1,10 +1,12 @@ import decimal from flask import render_template, g, redirect, url_for, flash, request import locale +import flask_wtf.file from flask_wtf.form import FlaskForm import bleach from bleach.sanitizer import ALLOWED_TAGS import markdown +import os from sqlalchemy import func from sqlalchemy.orm import joinedload from sqlalchemy.sql.functions import coalesce @@ -426,7 +428,6 @@ class RoundEditForm(FlaskForm): ) # Only the desktop Firefox does not support datetime-local field nowadays, # other browsers does provide date and time picker UI :( - tasks_file = wtforms.StringField("Soubor se zadáním", description="Cesta k ručně uploadovanému souboru", filters=[lambda x: x or None]) ct_tasks_start = MODateTimeField("Čas zveřejnění úloh pro účastníky", validators=[validators.Optional()]) pr_tasks_start = MODateTimeField("Čas zveřejnění úloh pro dozor", validators=[validators.Optional()]) ct_submit_end = MODateTimeField("Konec odevzdávání pro účastníky", validators=[validators.Optional()]) @@ -520,6 +521,61 @@ def org_task_statement(id: int): return mo.web.util.send_task_statement(round) +class StatementEditForm(FlaskForm): + file = flask_wtf.file.FileField("Soubor", render_kw={'autofocus': True}) + upload = wtforms.SubmitField('Nahrát') + delete = wtforms.SubmitField('Smazat') + + +@app.route('/org/contest/r/<int:id>/task-statement/edit', methods=('GET', 'POST')) +def org_edit_statement(id: int): + sess = db.get_session() + round, _, rr = get_round_rr(id, Right.manage_round, True) + + def log_changes(): + if sess.is_modified(round): + changes = db.get_object_changes(round) + app.logger.info(f"Kolo #{id} změněno, změny: {changes}") + mo.util.log( + type=db.LogType.round, + what=id, + details={'action': 'edit', 'changes': changes}, + ) + + form = StatementEditForm() + if form.validate_on_submit(): + if form.upload.data: + if form.file.data is not None: + file = form.file.data.stream + secure_category = werkzeug.utils.secure_filename(round.category) + stmt_dir = f'{round.year}-{secure_category}-{round.seq}' + full_dir = os.path.join(mo.util.data_dir('statements'), stmt_dir) + os.makedirs(full_dir, exist_ok=True) + full_name = mo.util.link_to_dir(file.name, full_dir, suffix='.pdf') + file_name = os.path.join(stmt_dir, os.path.basename(full_name)) + app.logger.info(f'Nahráno zadání: {file_name}') + + round.tasks_file = file_name + log_changes() + sess.commit() + flash('Zadání nahráno', 'success') + return redirect(url_for('org_round', id=id)) + else: + flash('Vyberte si prosím soubor', 'danger') + if form.delete.data: + round.tasks_file = None + log_changes() + sess.commit() + flash('Zadání smazáno', 'success') + return redirect(url_for('org_round', id=id)) + + return render_template( + 'org_edit_statement.html', + round=round, + form=form, + ) + + class MessageAddForm(FlaskForm): title = wtforms.StringField('Nadpis', validators=[validators.Required()]) markdown = wtforms.TextAreaField( diff --git a/mo/web/templates/org_edit_statement.html b/mo/web/templates/org_edit_statement.html new file mode 100644 index 0000000000000000000000000000000000000000..3f5a3cf06d560096db40821cc50e27b9ac22cfb6 --- /dev/null +++ b/mo/web/templates/org_edit_statement.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% import "bootstrap/wtf.html" as wtf %} + +{% block title %}Zadání kola {{ round.round_code() }}{% endblock %} +{% block breadcrumbs %} +{{ contest_breadcrumbs(round=round, action="Zadáni") }} +{% endblock %} +{% block body %} + +{{ wtf.quick_form(form, form_type='horizontal', button_map={'upload': 'primary', 'delete': 'danger'}) }} + +{% endblock %} diff --git a/mo/web/templates/org_round.html b/mo/web/templates/org_round.html index 9648bb8bc7e1631ede11d568919478d95c7ce82e..17637aeaae19e82a285d533061e2d7b8c4dec380 100644 --- a/mo/web/templates/org_round.html +++ b/mo/web/templates/org_round.html @@ -37,7 +37,7 @@ </table> <table class=data style="float: left;"> <thead> - <tr><th colspan=2>Termíny + <tr><th colspan=2>Termíny a zadání </thead> <tr><td>Účastníci vidí zadání od<td>{{ round.ct_tasks_start|time_and_timedelta }} <tr><td>Účastníci odevzdávají do<td>{{ round.ct_submit_end|time_and_timedelta }} @@ -77,6 +77,7 @@ {% endif %} {% if can_manage_round %} <a class="btn btn-default" href='{{ url_for('org_round_edit', id=round.round_id) }}'>Nastavení a termíny</a> + <a class="btn btn-default" href='{{ url_for('org_edit_statement', id=round.round_id) }}'>Zadání</a> {% endif %} {% if round.has_messages %} <a class="btn btn-default" href='{{ url_for('org_round_messages', id=round.round_id) }}'>Zprávičky</a>