diff --git a/mo/web/org_users.py b/mo/web/org_users.py index 683c0f792e14eb1bed26454724905c16a9ba0dbd..47b7991966d82aa10ab48430adb45fc4807cc3fa 100644 --- a/mo/web/org_users.py +++ b/mo/web/org_users.py @@ -664,3 +664,93 @@ def org_orgs_import(): year=mo.config.CURRENT_YEAR if form.only_this_year.data else None ) return generic_import_page(form, imp, url_for('org_orgs_import'), template='org_global_orgs_import.html') + + +class ConfirmDeleteForm(FlaskForm): + delete = SubmitField('Potvrdit smazání') + + +@app.route('/org/user/<int:user_id>/delete', methods=('GET', 'POST')) +def org_user_delete(user_id: int): + if not g.user.is_admin: + raise werkzeug.exceptions.Forbidden() + + sess = db.get_session() + user = sess.query(db.User).get(user_id) + if not user: + raise werkzeug.exceptions.NotFound() + + warnings = [] + errors = [] + + pants = sess.query(db.Participant).filter_by(user=user).all() + for pant in pants: + warnings.append(f'Účastní se {pant.year}. ročníku') + + pions = (sess.query(db.Participation) + .filter_by(user=user) + # .options(joinedload(db.Participation.contest, db.Participation.contest.round)) + .all()) + for pion in pions: + warnings.append(f'Účastní se kola {pion.contest.round.round_code()}') + + num_roles = sess.query(db.UserRole).filter_by(user=user).count() + if num_roles > 0: + warnings.append(f'Má přidělené role ({num_roles})') + + sols = (sess.query(db.Solution) + .filter_by(user=user) + # .options(joinedload(db.Solution.task, db.Solution.task.round)) + .all()) + for sol in sols: + errors.append(f'Odevzdal úlohu {sol.task.code} v kole {sol.task.round.round_code()}') + + num_papers = sess.query(db.Paper).filter_by(for_user_obj=user).count() + if num_papers: + errors.append(f'Patří mu řešení/opravy ({num_papers})') + + num_uploads = sess.query(db.Paper).filter_by(uploaded_by_obj=user).count() + if num_uploads: + errors.append(f'Nahrál řešení/opravy ({num_uploads})') + + logs = sess.query(db.Log).filter_by(user=user).all() + num_good_logs = 0 + num_bad_logs = 0 + for log in logs: + if log.details.get('reason', "") == 'user-join': + num_good_logs += 1 + else: + num_bad_logs += 1 + if num_good_logs > 0: + warnings.append(f'Vlastní záznamy v logu z registrace ({num_good_logs})') + if num_bad_logs > 0: + errors.append(f'Vlastní záznamy v logu ({num_bad_logs})') + + form = ConfirmDeleteForm() + if form.validate_on_submit() and not errors: + sess.rollback() + + conn = sess.connection() + pant_table = db.Participation.__table__ + pion_table = db.Participant.__table__ + role_table = db.UserRole.__table__ + log_table = db.Log.__table__ + conn.execute(pant_table.delete().where(pant_table.c.user_id == user.user_id)) + conn.execute(pion_table.delete().where(pion_table.c.user_id == user.user_id)) + conn.execute(role_table.delete().where(role_table.c.user_id == user.user_id)) + conn.execute(log_table.delete().where(log_table.c.changed_by == user.user_id)) + sess.commit() + + mo.util.log( + type=db.LogType.user, + what=user.user_id, + details={'action': 'delete', 'user': db.row2dict(user)}, + ) + sess.delete(user) + sess.commit() + + app.logger.info(f"Uživatel #{user.user_id} smazán") + flash('Uživatel smazán.', 'danger') + return redirect(url_for('org_orgs') if user.is_org else url_for('org_users')) + + return render_template('org_user_delete.html', user=user, form=form, warnings=warnings, errors=errors) diff --git a/mo/web/templates/org_org.html b/mo/web/templates/org_org.html index f242e2780b03f5d2b731b27f89c91516fd78dfbb..9c3c36f3bb0eeb23efa66dcb84a0459f3a4d0c61 100644 --- a/mo/web/templates/org_org.html +++ b/mo/web/templates/org_org.html @@ -31,6 +31,7 @@ {% endif %} {% if g.user.is_admin %} <a class="btn btn-default" href="{{ log_url('user', user.user_id) }}">Historie</a> + <a class="btn btn-danger" href="{{ url_for('org_user_delete', user_id=user.user_id) }}">Smazat</a> {% endif %} {% if can_incarnate %} <form action="{{ url_for('incarnate', id=user.user_id) }}" method=POST class='btn-group'> diff --git a/mo/web/templates/org_user.html b/mo/web/templates/org_user.html index edf1f7684ee37d97e80886c2064c33a45a2b7c7d..965bcb753c81442df73353810ec62c7eb20654de 100644 --- a/mo/web/templates/org_user.html +++ b/mo/web/templates/org_user.html @@ -39,6 +39,7 @@ {% endif %} {% if g.user.is_admin %} <a class="btn btn-default" href="{{ log_url('user', user.user_id) }}">Historie</a> + <a class="btn btn-danger" href="{{ url_for('org_user_delete', user_id=user.user_id) }}">Smazat</a> {% endif %} {% if can_incarnate %} <form action="{{ url_for('incarnate', id=user.user_id) }}" method=POST class='btn-group'> diff --git a/mo/web/templates/org_user_delete.html b/mo/web/templates/org_user_delete.html new file mode 100644 index 0000000000000000000000000000000000000000..5867867956ff9ac31532a0805fe87143d2083586 --- /dev/null +++ b/mo/web/templates/org_user_delete.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{% import "bootstrap/wtf.html" as wtf %} +{% block title %}Smazat uživatele: {{ user.full_name() }}{% endblock %} +{% block body %} + +{% if warnings %} +<h3>Varováni</h3> +<ul> + {% for w in warnings %} + <li>{{ w }} + {% endfor %} +</ul> +{% endif %} + +{% if errors %} +<h3>Chyby</h3> +<ul> + {% for e in errors %} + <li>{{ e }} + {% endfor %} +</ul> +{% endif %} + +{% if form and not errors %} +{{ wtf.quick_form(form, form_type='simple', button_map={'delete': 'danger'}) }} +{% endif %} + +{% endblock %}