From 4d18ae96f1652a44dd4761482c25df7836e0b891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Setni=C4=8Dka?= <setnicka@seznam.cz> Date: Sat, 2 Jan 2021 18:18:35 +0100 Subject: [PATCH] =?UTF-8?q?P=C5=99id=C3=A1v=C3=A1n=C3=AD=20a=20odeb=C3=ADr?= =?UTF-8?q?=C3=A1n=C3=AD=20pr=C3=A1v=20v=20detailu=20organiz=C3=A1tor?= =?UTF-8?q?=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mo/web/org_users.py | 85 ++++++++++++++++++++++++++-- mo/web/templates/org_user.html | 48 +++++++++++++++- mo/web/templates/org_users_orgs.html | 5 +- 3 files changed, 129 insertions(+), 9 deletions(-) diff --git a/mo/web/org_users.py b/mo/web/org_users.py index 2d19ccb5..34700c94 100644 --- a/mo/web/org_users.py +++ b/mo/web/org_users.py @@ -5,6 +5,7 @@ import wtforms from sqlalchemy import or_ from typing import Optional +from wtforms import validators from wtforms.validators import Required @@ -54,7 +55,6 @@ def org_users(): if filter.year.data: participant_filter = participant_filter.filter_by(year=filter.year.data) participant_filter_apply = True - print(filter.school_code.data) if filter.school_code.data: place = db.place_by_code(filter.school_code.data) if place: @@ -167,7 +167,22 @@ def org_users_orgs(): ) -@app.route('/org/user/<int:id>/') +class FormAddRole(FlaskForm): + role = wtforms.SelectField('Role', choices=[(name.name, role.name) for (name, role) in mo.rights.roles_by_type.items()]) + place_code = wtforms.StringField('Oblast') + year = wtforms.IntegerField('Ročník', validators=[validators.Optional()]) + category = wtforms.StringField("Kategorie") + seq = wtforms.IntegerField("Kolo", validators=[validators.Optional()]) + + submit = wtforms.SubmitField('Přidat roli') + + +class FormRemoveRole(FlaskForm): + remove_role_id = wtforms.IntegerField() + remove = wtforms.SubmitField('Odebrat roli') + + +@app.route('/org/user/<int:id>/', methods=('GET', 'POST')) def org_user(id: int): sess = db.get_session() user = sess.query(db.User).get(id) @@ -176,13 +191,75 @@ def org_user(id: int): rr = mo.rights.Rights(g.user) rr.get_generic() + can_assign_rights = rr.have_right(mo.rights.Right.assign_rights) participants = sess.query(db.Participant).filter_by(user_id=user.user_id) rounds = sess.query(db.Participation).filter_by(user_id=user.user_id) + form_add_role = FormAddRole() + form_remove_role = FormRemoveRole() + role_errors = [] + if can_assign_rights: + if form_add_role.submit.data and form_add_role.validate_on_submit(): + new_role = db.UserRole() + form_add_role.populate_obj(new_role) + + new_role.user_id = id + new_role.place = db.get_root_place() + new_role.assigned_by = g.user.user_id + + ok = True + place_code = form_add_role.place_code.data + if place_code: + place = db.get_place_by_code(place_code) + if not place: + role_errors.append("Nepovedlo se nalézt místo podle kódu") + ok = False + else: + new_role.place = place + + if not rr.can_set_role(new_role): + role_errors.append(f'Roli "{new_role}" nelze přidělit, není podmnožinou žádné vaší role') + ok = False + + if ok: + sess.add(new_role) + sess.flush() + mo.util.log( + type=db.LogType.user_role, + what=id, + details={'action': 'new', 'role': db.row2dict(new_role)}, + ) + sess.commit() + app.logger.info(f"New role for user id {id} added: {db.row2dict(new_role)}") + flash(f'Role "{new_role}" úspěšně přidána', 'success') + return redirect(url_for('org_user', id=id)) + + if form_remove_role.remove_role_id.data and form_remove_role.validate_on_submit(): + role = sess.query(db.UserRole).get(form_remove_role.remove_role_id.data) + if not role: + raise werkzeug.exceptions.NotFound + + if id == g.user.user_id: + role_errors.append('Nelze odebrat vlastní roli') + elif not rr.can_set_role(role): + role_errors.append(f'Roli "{role}" nelze odebrat, není podmnožinou žádné vaší role') + else: + sess.delete(role) + mo.util.log( + type=db.LogType.user_role, + what=id, + details={'action': 'delete', 'role': db.row2dict(role)}, + ) + sess.commit() + app.logger.info(f"Role for user {id} removed: {db.row2dict(role)}") + flash(f'Role "{role}" úspěšně odebrána', 'success') + return redirect(url_for('org_user', id=id)) + return render_template( - 'org_user.html', user=user, can_edit=rr.can_edit_user(user), - participants=participants, rounds=rounds + 'org_user.html', user=user, can_edit=rr.can_edit_user(user), can_assign_rights=can_assign_rights, + participants=participants, rounds=rounds, roles_by_type=mo.rights.roles_by_type, + form_add_role=form_add_role, form_remove_role=form_remove_role, role_errors=role_errors, ) diff --git a/mo/web/templates/org_user.html b/mo/web/templates/org_user.html index ef1b6a22..fdd07adc 100644 --- a/mo/web/templates/org_user.html +++ b/mo/web/templates/org_user.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% import "bootstrap/wtf.html" as wtf %} {% block body %} <h2>{% if user.is_org %}Organizátor:{% elif user.is_admin %}Správce:{% else %}Soutěžící:{% endif %} {{ user.first_name }} {{ user.last_name }}</h2> @@ -20,19 +21,60 @@ {% if user.is_org or user.is_admin %} <h3>Role</h3> +{% if can_assign_rights %} +<h4>Přidělení nové role</h4> +<p>Lze přidělit jen roli, která je podmnožinou nějaké vlastní role (včetně omezení na oblast, kolo, …).</p> +{% if role_errors %} +<div class="alert alert-danger" role="alert"> + {{ role_errors|join("<br>") }} +</div> +{% endif %} + +<form action="" method="POST" class="form form-inline" role="form"> + {{ form_add_role.csrf_token() }} + <div class="form-group"> + {{ wtf.form_field(form_add_role.role) }} + </div> + <div class="form-group"> + {{ wtf.form_field(form_add_role.place_code, placeholder='Kód / #ID', size=8) }} + </div> + <div class="form-group"> + {{ wtf.form_field(form_add_role.year, type='number', size=3, maxlength=2) }} + </div> + <div class="form-group"> + {{ wtf.form_field(form_add_role.category, size=2, maxlength=2) }} + </div> + <div class="form-group"> + {{ wtf.form_field(form_add_role.seq, type='number', size=3, maxlength=2) }} + </div> + <div class="form-group"> + {{ wtf.form_field(form_add_role.submit) }} + </div> +</form> +{% endif %} + <table class="data full"> <thead> <tr> - <th>Role</th><th>Ročník</th><th>Kategorie</th><th>Kolo</th><th>Oblast</th> + <th>Role</th><th>Oblast</th><th>Ročník</th><th>Kategorie</th><th>Kolo</th><th>Akce</th> </tr> </thead> {% for role in user.roles %} <tr> - <td>{{ role.role.name }}</td> + <td>{{ roles_by_type[role.role].name }}</td> + <td><a href="{{ url_for('org_place', id=role.place_id) }}">{{ role.place.type_name() + ": " + role.place.name or '*' }}</a></td> <td>{{ role.year or '*' }}</td> <td>{{ role.category or '*' }}</td> <td>{{ role.seq or '*' }}</td> - <td>{{ role.place.type_name() + ": " + role.place.name or '*' }}</td> + <td> + {% if can_assign_rights %} + <form action="" method="POST"> + {{ form_remove_role.csrf_token() }} + <input type="hidden" name="remove_role_id" value="{{ role.user_role_id }}"> + <button type="submit" class="btn btn-xs btn-danger">Odebrat</button> + </form> + {% endif %} + </td> </tr> {% endfor %} </table> diff --git a/mo/web/templates/org_users_orgs.html b/mo/web/templates/org_users_orgs.html index 0920ae7e..2987306b 100644 --- a/mo/web/templates/org_users_orgs.html +++ b/mo/web/templates/org_users_orgs.html @@ -48,10 +48,11 @@ <td>{{ user.first_name }}</td><td>{{ user.last_name }}</td> <td><a href="mailto:{{ user.email }}">{{ user.email }}</a></td> <td>{% if user.is_admin %}správce{% elif user.roles|count == 0 %}<i>žádná role</i>{% else %} + <ul> {% for role in user.roles %} - {% if loop.index != 1 %}→{% endif %} - {% if role.year %}{{role.year}}-{% endif %}{% if role.category %}{{role.category}}-{% endif %}{{ role.role.name }} + <li>{{ role }}</li> {%- endfor %} + </ul> {% endif %}</td> <td><div class='btn-group'> <a class="btn btn-xs btn-default" href="{{ url_for('org_user', id=user.user_id) }}">Detail</a> -- GitLab