diff --git a/mo/web/org_round.py b/mo/web/org_round.py index e0f471319a4af848f18ce4077b07ecff9354e5e5..1b7455556abb6444c6538d264dd9f8da5a5b0dbd 100644 --- a/mo/web/org_round.py +++ b/mo/web/org_round.py @@ -47,11 +47,19 @@ def org_rounds(): return render_template('org_rounds.html', rounds=rounds, level_names=mo.db.place_level_names) -@app.route('/org/contest/r/<int:id>/') +class TaskDeleteForm(FlaskForm): + delete_task_id = wtforms.IntegerField() + delete = wtforms.SubmitField('Smazat úlohu') + + +@app.route('/org/contest/r/<int:id>/', methods=('GET', 'POST')) def org_round(id: int): sess = db.get_session() round, rr = get_round_rr(id, None) + can_manage_round = rr.have_right(mo.rights.Right.manage_round) + can_manage_contestants = rr.have_right(mo.rights.Right.manage_contest) + contests = (sess.query(db.Contest) .filter_by(round=round) .options(joinedload(db.Contest.place)) @@ -59,13 +67,119 @@ def org_round(id: int): contests.sort(key=lambda c: locale.strxfrm(c.place.name)) + tasks = sess.query(db.Task).filter_by(round=round).all() + tasks.sort(key=lambda t: t.code) + + form_delete_task = TaskDeleteForm() + if can_manage_contestants and form_delete_task.validate_on_submit(): + delete_task = sess.query(db.Task).filter_by( + round_id=id, task_id=form_delete_task.delete_task_id.data + ).first() + if not delete_task: + flash('Úloha s daným ID v tomto kole neexistuje', 'danger') + elif sess.query(db.Solution).filter_by(task_id=delete_task.task_id).first() is not None: + flash(f'Úlohu {delete_task.code} nelze smazat, existují řešení vázající se na ní', 'danger') + elif sess.query(db.Paper).filter_by(for_task=delete_task.task_id).first() is not None: + flash(f'Úlohu {delete_task.code} nelze smazat, existují papíry vázající se na ní', 'danger') + elif sess.query(db.PointsHistory).filter_by(task_id=delete_task.task_id).first() is not None: + flash(f'Úlohu {delete_task.code} nelze smazat, existují přidělené body vázající se na ní', 'danger') + else: + sess.delete(delete_task) + mo.util.log( + type=db.LogType.task, + what=delete_task.task_id, + details={'action': 'delete', 'task': db.row2dict(delete_task)}, + ) + app.logger.info(f"Úloha {delete_task.code} ({delete_task.task_id}) smazána: {db.row2dict(delete_task)}") + sess.commit() + flash(f'Úloha {delete_task.code} úspěšně smazána', 'success') + return redirect(url_for('org_round', id=id)) + return render_template( 'org_round.html', round=round, contests=contests, + tasks=tasks, form_delete_task=form_delete_task, level_names=mo.db.place_level_names, - can_manage_round=rr.have_right(mo.rights.Right.manage_round), - can_manage_contestants=rr.have_right(mo.rights.Right.manage_contest), + can_manage_round=can_manage_round, + can_manage_contestants=can_manage_contestants, + ) + + +class TaskEditForm(FlaskForm): + code = wtforms.StringField('Kód úlohy') + name = wtforms.StringField('Název úlohy') + submit = wtforms.SubmitField('Uložit') + + +@app.route('/org/contest/r/<int:id>/task/new', methods=('GET', 'POST')) +def org_round_task_new(id: int): + sess = db.get_session() + round, rr = get_round_rr(id, mo.rights.Right.manage_round) + + form = TaskEditForm() + if form.validate_on_submit(): + task = db.Task() + task.round = round + form.populate_obj(task) + + if sess.query(db.Task).filter_by(round_id=id, code=task.code).first(): + flash('Úloha se stejným kódem již v tomto kole existuje', 'danger') + else: + sess.add(task) + sess.flush() + mo.util.log( + type=db.LogType.task, + what=task.task_id, + details={'action': 'add', 'task': db.row2dict(task)}, + ) + sess.commit() + app.logger.info(f"Úloha {task.code} ({task.task_id}) přidána: {db.row2dict(task)}") + flash('Nová úloha přidána', 'success') + return redirect(url_for('org_round', id=id)) + + return render_template( + 'org_round_task_edit.html', + round=round, task=None, form=form, + ) + + +@app.route('/org/contest/r/<int:id>/task/<int:task_id>/edit', methods=('GET', 'POST')) +def org_round_task_edit(id: int, task_id: int): + sess = db.get_session() + round, rr = get_round_rr(id, mo.rights.Right.manage_round) + + task = sess.query(db.Task).get(task_id) + if not task: + raise werkzeug.exceptions.NotFound() + + form = TaskEditForm(obj=task) + if form.validate_on_submit(): + if sess.query(db.Task).filter( + db.Task.task_id != task_id, db.Task.round_id == id, db.Task.code == form.code.data + ).first(): + flash('Úloha se stejným kódem již v tomto kole existuje', 'danger') + else: + form.populate_obj(task) + if sess.is_modified(task): + changes = db.get_object_changes(task) + + mo.util.log( + type=db.LogType.task, + what=task_id, + details={'action': 'edit', 'changes': changes}, + ) + sess.commit() + app.logger.info(f"Úloha {task.code} ({task_id}) modifikována, změny: {changes}") + flash('Změny úlohy uloženy', 'success') + else: + flash(u'Žádné změny k uložení', 'info') + + return redirect(url_for('org_round', id=id)) + + return render_template( + 'org_round_task_edit.html', + round=round, task=task, form=form, ) diff --git a/mo/web/templates/org_round.html b/mo/web/templates/org_round.html index 0509d3fce3d8befa1ab61164188fe0270de3d99f..5ab222a8440c21e0018cb9f51a89307de96a8cab 100644 --- a/mo/web/templates/org_round.html +++ b/mo/web/templates/org_round.html @@ -38,4 +38,36 @@ <p>Zatím nebyly založeny v žádné oblasti. {% endif %} +<h3>Úlohy</h3> +{% if can_manage_round %} +<a class="btn btn-primary right-float" href="{{ url_for('org_round_task_new', id=round.round_id) }}">Nová úloha</a> +{% endif %} +{% if tasks %} +<table class=data> + <thead> + <tr> + <th>Kód</th> + <th>Název</th> + {% if can_manage_round %}<th>Akce</th>{% endif %} + </tr> + </thead> + {% for task in tasks %} + <tr> + <td>{{ task.code }}</td> + <td>{{ task.name }}</td> + {% if can_manage_round %}<td> + <form action="" method="POST" onsubmit="return confirm('Opravdu nenávratně smazat?')" class="btn-group"> + {{ form_delete_task.csrf_token() }} + <input type="hidden" name="delete_task_id" value="{{ task.task_id }}"> + <a class="btn btn-xs btn-primary" href="{{ url_for('org_round_task_edit', id=round.round_id, task_id=task.task_id) }}">Editovat</a> + <button type="submit" class="btn btn-xs btn-danger">Smazat</button> + </form> + </td>{% endif %} + </tr> + {% endfor %} +</table> +{% else %} +<p>Zatím nebyly přidány žádné úlohy.</p> +{% endif %} + {% endblock %} diff --git a/mo/web/templates/org_round_task_edit.html b/mo/web/templates/org_round_task_edit.html new file mode 100644 index 0000000000000000000000000000000000000000..9eba638e966d33705c719291afe62ab46b678652 --- /dev/null +++ b/mo/web/templates/org_round_task_edit.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% import "bootstrap/wtf.html" as wtf %} +{% block body %} +<h2> + <a href='{{ url_for('org_round', id=round.round_id) }}'>Kolo {{ round.round_code() }}</a> + » {% if task %} Úloha {{ task.code }}: {{ task.name }}{% else %}Nová úloha{% endif %} +</h2> + +{{ wtf.quick_form(form, form_type='horizontal') }} + +{% endblock %}