diff --git a/mo/web/org_contest.py b/mo/web/org_contest.py index fdebce5c5e6dd8e9629a809fa11ceeddcc9b2876..bd786672373cc1852ce82c61d64ae0774616605f 100644 --- a/mo/web/org_contest.py +++ b/mo/web/org_contest.py @@ -17,7 +17,7 @@ import mo from mo.csv import FileFormat import mo.config as config import mo.db as db -from mo.imports import ImportType, create_import +from mo.imports import ImportType, ContestImport, ContestImportRow, create_import import mo.jobs.submit from mo.rights import Right, ContestRights import mo.util @@ -236,6 +236,47 @@ class ParticipantsActionForm(FlaskForm): return True +class ParticipantAddForm(FlaskForm): + email = wtforms.StringField("E-mail", validators=[validators.Required()]) + first_name = wtforms.StringField("Křestní jméno", validators=[validators.Required()]) + last_name = wtforms.StringField("Příjmení", validators=[validators.Required()]) + school_code = wtforms.StringField( + "Kód školy", + description="Viz katalog škol na tomto webu", + validators=[validators.Required()]) + rocnik = wtforms.StringField( + "Ročník", + description="Pro základní školy je to číslo od 1 do 9, pro <var>k</var>-tý ročník <var>r</var>-leté střední školy má formát <var>k</var>/<var>r</var>.", + validators=[validators.Required()]) + rok_naroz = wtforms.StringField("Rok narození") + participation_place = wtforms.SelectField('Soutěžní místo', coerce=int) + save = wtforms.SubmitField("Přidat") + + def set_contest(self, contest_id: int, site_id: int): + sess = db.get_session() + places = ( + sess.query(db.Place) + .select_from(db.Participation).join(db.Place) + .filter(db.Participation.contest_id == contest_id).all() + ) + if len(places) == 0: + places = ( + sess.query(db.Place) + .select_from(db.Contest).join(db.Place) + .filter(db.Contest.contest_id == contest_id).all() + ) + + self.participation_place.choices = [(p.place_id, p.name) for p in places] + if site_id: + self.participation_place.data = site_id + + def validate_email(form, field): + try: + field.data = mo.users.normalize_email(field.data) + except mo.CheckError as e: + raise wtforms.ValidationError(str(e)) + + def get_contest(id: int) -> Tuple[db.Contest, db.Contest]: """Vrací contest a master_contest pro zadané contest_id. Pro nedělená kola platí contest == master_contest. @@ -440,6 +481,44 @@ def org_contest_import(id: int): contest=contest, master_contest=master_contest ) +@app.route('/org/contest/c/<int:id>/ucastnici/pridat', methods=('GET', 'POST')) +@app.route('/org/contest/c/<int:id>/site/<int:site_id>/ucastnici/pridat', methods=('GET', 'POST')) +def org_contest_add_user(id: int, site_id: Optional[int] = None): + contest, site, rr = get_contest_site_rr(id, site_id, right_needed=Right.manage_contest) + + errs = None + form = ParticipantAddForm() + form.set_contest(id, site_id) + if form.validate_on_submit(): + row = ContestImportRow() + row.email = form.email.data + row.krestni = form.first_name.data + row.prijmeni = form.last_name.data + row.kod_skoly = form.school_code.data + row.rocnik = form.rocnik.data + row.rok_naroz = form.rok_naroz.data + row.kod_mista = '#'+str(form.participation_place.data) + + imp = ContestImport() + imp.user = g.user + imp.round = contest.round + imp.contest = contest + imp.gatekeeper = mo.rights.Gatekeeper(g.user) + imp.setup() + imp.import_row(row) + errs = imp.errors + if len(errs) == 0: + db.get_session().commit() + imp.notify_users() + return redirect(url_for('org_contest_list', id=id, site_id=site_id)) + else: + db.get_session().rollback() + + return render_template( + 'org_contest_add_user.html', + contest=contest, site=site, + form=form, errs=errs + ) @app.route('/org/contest/c/<int:id>/ucastnici', methods=('GET', 'POST')) @app.route('/org/contest/c/<int:id>/site/<int:site_id>/ucastnici', methods=('GET', 'POST')) diff --git a/mo/web/templates/org_contest.html b/mo/web/templates/org_contest.html index 36eb3b62772f8e11c69e1632c2796e9c2bfc361b..948a7cb0f02b7fba278b4c376bc2ac5e78cf31dc 100644 --- a/mo/web/templates/org_contest.html +++ b/mo/web/templates/org_contest.html @@ -73,25 +73,36 @@ {% if places_counts %} <table class=data> <thead> - <tr><th>Místo<th>Počet účastníků + <tr><th>Místo<th>Počet účastníků<th>Akce </thead> {% for (place, count) in places_counts %} <tr> <td><a href="{{ url_for('org_contest', id=contest.contest_id, site_id=place.place_id) }}">{{ place.name }}</a> <td>{{ count }} + <td> + <a class="btn btn-xs btn-primary" href="{{ url_for('org_contest', id=contest.contest_id, site_id=place.place_id) }}">Detail</a> + {% if can_manage %} + <a class="btn btn-xs btn-default" href="{{ url_for('org_contest_add_user', id=contest.contest_id, site_id=place.place_id) }}">Přidat účastníka</a> + {% endif %} </tr> {% endfor %} <tfoot> <tr> <th>Celkem <th>{{ places_counts|sum(attribute=1) }} + <th> </tr> </tfoot> </table> {% else %} -<i>Žádní účastníci a žádná soutěžní místa.</i> +<p><i>Žádní účastníci a žádná soutěžní místa.</i></p> {% endif %} {% endif %} +<div class="btn-group"> + {% if can_manage %} + <a class="btn btn-default" href='{{ url_for('org_contest_add_user', id=contest.contest_id) }}'>Přidat účastníka</a> + {% endif %} +</div> <h3>Úlohy</h3> {% if tasks %} diff --git a/mo/web/templates/org_contest_add_user.html b/mo/web/templates/org_contest_add_user.html new file mode 100644 index 0000000000000000000000000000000000000000..c1c03bac4d2464b6ab354925fc2c92d3c829f7b1 --- /dev/null +++ b/mo/web/templates/org_contest_add_user.html @@ -0,0 +1,26 @@ +{% extends "base.html" %} +{% import "bootstrap/wtf.html" as wtf %} +{% set round = contest.round %} +{% set site_id = site.place_id if site else None %} + +{% block title %} +{{ round.round_code() }}: Přidat účastníka {% if site %}do soutěžního místa {{ site.name }}{% else %}do oblasti {{ contest.place.name }}{% endif %} +{% endblock %} +{% block breadcrumbs %} +{{ contest_breadcrumbs(round=round, contest=contest, site=site, action="Přidat účastníka") }} +{% endblock %} + +{% block body %} + +{% if errs %} +<div class="alert alert-danger" role="alert" style="white-space: pre-line">{{ "" -}} +{% for e in errs %} +{{ e }} +{% endfor %} +</div> +{% endif %} + +{{ wtf.quick_form(form, form_type='simple', button_map={'save': 'primary'}) }} + +{% endblock %} + diff --git a/mo/web/templates/parts/org_participants_table_actions.html b/mo/web/templates/parts/org_participants_table_actions.html index 24eb85aa361049b900d3a1672d8637673e50cfda..0eec0d02a253fa76728b4d2623192de5c44acd3e 100644 --- a/mo/web/templates/parts/org_participants_table_actions.html +++ b/mo/web/templates/parts/org_participants_table_actions.html @@ -4,7 +4,10 @@ {{ table.to_html() }} - <a class="btn btn-primary pull-right" + {% if contest %} + <a class="btn btn-primary" href="{{ url_for('org_contest_add_user', id=contest.contest_id, site_id=site.place_id if site else None) }}">Přidat účastníka</a> + {% endif %} + <a class="btn btn-default" title="Zobrazí emailové adresy ve snadno zkopírovatelném formátu" href="{{ url_for('org_contest_list_emails', id=id, site_id=site_id, **request.args) if contest else url_for('org_round_list_emails', id=id, **request.args) }}"> Vypsat e-mailové adresy