Project 'mj/mo-submit' was moved to 'mo-p/osmo'. Please update any links and bookmarks that may still have the old path.
Select Git revision
org_round.py
Jiří Setnička authored
org_round.py 5.96 KiB
from typing import Optional, Tuple
from flask import render_template, g, redirect, url_for, flash, request
import locale
import os
import secrets
from flask_wtf.form import FlaskForm
from sqlalchemy.orm import joinedload
import werkzeug.exceptions
import wtforms
from wtforms import validators
from wtforms.fields.html5 import DateTimeLocalField
import mo
import mo.csv
import mo.db as db
import mo.imports
import mo.rights
import mo.util
from mo.web import app
from mo.web.org_contest import ImportForm, ParticipantsActionForm, ParticipantsFilterForm, get_contestants_query, make_contestant_table
def get_round(id: int) -> db.Round:
round = db.get_session().query(db.Round).get(id)
if not round:
raise werkzeug.exceptions.NotFound()
return round
def get_round_rr(id: int, right_needed: Optional[mo.rights.Right]) -> Tuple[db.Round, mo.rights.Rights]:
round = get_round(id)
rr = mo.rights.Rights(g.user)
rr.get_for_round(round)
if not (right_needed is None or rr.have_right(right_needed)):
raise werkzeug.exceptions.Forbidden()
return round, rr
@app.route('/org/contest/')
def org_rounds():
sess = db.get_session()
rounds = sess.query(db.Round).filter_by(year=mo.current_year).order_by(db.Round.year, db.Round.category, db.Round.seq)
return render_template('org_rounds.html', rounds=rounds, level_names=mo.db.place_level_names)
@app.route('/org/contest/r/<int:id>/')
def org_round(id: int):
sess = db.get_session()
round, rr = get_round_rr(id, None)
contests = (sess.query(db.Contest)
.filter_by(round=round)
.options(joinedload(db.Contest.place))
.all())
contests.sort(key=lambda c: locale.strxfrm(c.place.name))
return render_template(
'org_round.html',
round=round,
contests=contests,
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),
)
@app.route('/org/contest/r/<int:id>/list', methods=('GET', 'POST'))
def org_round_list(id: int):
round, rr = get_round_rr(id, mo.rights.Right.manage_contest)
format = request.args.get('format', "")
filter = ParticipantsFilterForm(request.args)
filter.validate()
query = get_contestants_query(
round=round,
school=db.get_place_by_code(filter.school.data),
contest_place=db.get_place_by_code(filter.contest_place.data),
participation_place=db.get_place_by_code(filter.participation_place.data),
participation_state=None if filter.participation_state.data == '*' else filter.participation_state.data
)
action_form = ParticipantsActionForm()
if action_form.do_action(round=round, rights=rr, query=query):
# Action happened, redirect
return redirect(request.url)
(count, query) = filter.apply_limits(query, pagesize=50)
# count = query.count()
if format == "":
table = make_contestant_table(query, add_contest_column=True, add_checkbox=True)
return render_template(
'org_round_list.html',
round=round,
table=table,
filter=filter, count=count, action_form=action_form,
)
else:
table = make_contestant_table(query)
return table.send_as(format)
@app.route('/org/contest/r/<int:id>/import', methods=('GET', 'POST'))
def org_round_import(id: int):
round, rr = get_round_rr(id, mo.rights.Right.manage_contest)
form = ImportForm()
errs = []
if form.validate_on_submit():
tmp_name = secrets.token_hex(16) + '.csv'
tmp_path = os.path.join(app.instance_path, 'imports', tmp_name)
form.file.data.save(tmp_path)
imp = mo.imports.Import(g.user)
if imp.import_contest(round, None, tmp_path):
flash(f'Účastníci importováni (založeno {imp.cnt_new_users} uživatelů, {imp.cnt_new_participations} účastí)', 'success')
return redirect(url_for('org_round', id=round.round_id))
else:
flash('Došlo k chybě při importu (detaily níže)', 'danger')
errs = imp.errors
return render_template(
'org_round_import.html',
round=round,
form=form,
errs=errs,
)
class RoundEditForm(FlaskForm):
state = wtforms.SelectField("Stav kola", choices=db.RoundState.choices())
# Only the desktop Firefox does not support datetime-local field nowadays,
# other browsers does provide date and time picker UI :(
submit_start = DateTimeLocalField(
"Začátek kola", validators=[validators.Optional()],
description="Ve formátu 2020-01-01 00:00:00"
)
ct_submit_end = DateTimeLocalField(
"Konec odevzdávání pro účastníky", validators=[validators.Optional()],
description="Ve formátu 2020-01-01 00:00:00"
)
pr_submit_end = DateTimeLocalField(
"Konec odevzdávání pro dozor", validators=[validators.Optional()],
description="Ve formátu 2020-01-01 00:00:00"
)
submit = wtforms.SubmitField('Uložit')
@app.route('/org/contest/r/<int:id>/edit', methods=('GET', 'POST'))
def org_round_edit(id: int):
sess = db.get_session()
round, rr = get_round_rr(id, mo.rights.Right.manage_round)
form = RoundEditForm(obj=round)
if form.validate_on_submit():
form.populate_obj(round)
if sess.is_modified(round):
changes = db.get_object_changes(round)
app.logger.info(f"Round {id} modified, changes: {changes}")
mo.util.log(
type=db.LogType.round,
what=id,
details={'action': 'edit', 'changes': changes},
)
sess.commit()
flash('Změny kola 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_edit.html',
round=round,
form=form,
)