diff --git a/app/views/users.py b/app/views/users.py index 10f1124dd4..315601bbd1 100644 --- a/app/views/users.py +++ b/app/views/users.py @@ -41,8 +41,9 @@ from xml.etree import ElementTree import flask from flask import g, url_for, request, current_app, flash from flask import redirect, render_template - from flask_login import current_user +from flask_wtf import FlaskForm + from wtforms import HiddenField, PasswordField, StringField, SubmitField from wtforms.validators import DataRequired, Email, ValidationError, EqualTo @@ -62,7 +63,7 @@ from app.decorators import ( permission_required, ) -from app.scodoc import html_sco_header, sco_import_users, sco_excel, sco_roles_default +from app.scodoc import html_sco_header, sco_import_users, sco_roles_default from app.scodoc import sco_users from app.scodoc import sco_utils as scu from app.scodoc import sco_xml @@ -72,13 +73,14 @@ from app.scodoc.sco_import_users import generate_password from app.scodoc.sco_permissions_check import can_handle_passwd from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message from app.views import users_bp as bp -from flask_wtf import FlaskForm _ = lambda x: x # sans babel _l = _ class ChangePasswordForm(FlaskForm): + """formulaire changement mot de passe et mail""" + user_name = HiddenField() old_password = PasswordField(_l("Identifiez-vous")) new_password = PasswordField(_l("Nouveau mot de passe de l'utilisateur")) @@ -102,6 +104,7 @@ class ChangePasswordForm(FlaskForm): cancel = SubmitField("Annuler") def validate_email(self, email): + "vérifie que le mail est unique" user = User.query.filter_by(email=email.data.strip()).first() if user is not None and self.user_name.data != user.user_name: raise ValidationError( @@ -109,8 +112,9 @@ class ChangePasswordForm(FlaskForm): ) def validate_new_password(self, new_password): + "vérifie que le mot de passe est acceptable" if new_password.data != "" and not is_valid_password(new_password.data): - raise ValidationError(f"Mot de passe trop simple, recommencez") + raise ValidationError("Mot de passe trop simple, recommencez") def validate_old_password(self, old_password): if not current_user.check_password(old_password.data): @@ -129,6 +133,7 @@ class Mode(IntEnum): @permission_required(Permission.ScoUsersView) @scodoc7func def index_html(all_depts=False, with_inactives=False, format="html"): + "Page accueil utilisateur: tableau avec liste des comptes" return sco_users.index_html( all_depts=all_depts, with_inactives=with_inactives, @@ -136,15 +141,6 @@ def index_html(all_depts=False, with_inactives=False, format="html"): ) -@bp.route("/user_info") -@scodoc -@permission_required(Permission.ScoUsersView) -@scodoc7func -def user_info(user_name, format="json"): - info = sco_users.user_info(user_name) - return scu.sendResult(info, name="user", format=format) - - @bp.route("/create_user_form", methods=["GET", "POST"]) @scodoc @permission_required(Permission.ScoUsersAdmin) @@ -173,7 +169,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False): if not the_user: raise ScoValueError("utilisateur inexistant") initvalues = the_user.to_dict() - H.append("

Modification de l'utilisateur %s

" % user_name) + H.append(f"

Modification de l'utilisateur {user_name}

") else: H.append("

Création d'un utilisateur

") @@ -196,9 +192,9 @@ def create_user_form(user_name=None, edit=0, all_roles=False): ] # Départements auxquels ont peut associer des rôles via ce dialogue: # si SuperAdmin, tous les rôles standards dans tous les départements - # sinon, les départements dans lesquels l'utilisateur a le droit + # sinon, les départements dans lesquels l'utilisateur a la permission ScoUsersAdmin if is_super_admin: - log("create_user_form called by %s (super admin)" % (current_user.user_name,)) + log(f"create_user_form called by {current_user.user_name} (super admin)") administrable_dept_acronyms = [d.acronym for d in Departement.query.all()] else: # Si on n'est pas SuperAdmin, liste les départements dans lesquels on a la @@ -266,8 +262,8 @@ def create_user_form(user_name=None, edit=0, all_roles=False): f"{dept or 'tout dépt.'}: {r.name}" for (r, dept) in displayed_roles ] disabled_roles = {} # pour désactiver les roles que l'on ne peut pas éditer - for i in range(len(displayed_roles_strings)): - if displayed_roles_strings[i] not in editable_roles_strings: + for i, role_string in enumerate(displayed_roles_strings): + if role_string not in editable_roles_strings: disabled_roles[i] = True descr = [ ("edit", {"input_type": "hidden", "default": edit}), @@ -380,7 +376,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False): "input_type": "text", "size": 12, "allow_null": True, - "explanation": """département de rattachement de l'utilisateur + "explanation": """département de rattachement de l'utilisateur (s'il s'agit d'un administrateur, laisser vide si vous voulez qu'il puisse créer des utilisateurs dans d'autres départements) """, @@ -418,8 +414,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False): "d", { "input_type": "separator", - "title": "L'utilisateur appartient au département %s" - % auth_dept, + "title": f"L'utilisateur appartient au département {auth_dept}", }, ) ) @@ -429,8 +424,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False): "d", { "input_type": "separator", - "title": "L'utilisateur sera crée dans le département %s" - % auth_dept, + "title": f"L'utilisateur sera crée dans le département {auth_dept}", }, ) ) @@ -469,7 +463,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False): ), ] vals = scu.get_request_args() - if "tf_submitted" in vals and not "roles" in vals: + if "tf_submitted" in vals and "roles" not in vals: vals["roles"] = [] if "tf_submitted" in vals: # Ajoute roles existants mais non modifiables (disabled dans le form) @@ -507,13 +501,15 @@ def create_user_form(user_name=None, edit=0, all_roles=False): user_name = vals["user_name"] # ce login existe ? err = None - users = sco_users._user_list(user_name) - if edit and not users: # safety net, le user_name ne devrait pas changer - err = "identifiant %s inexistant" % user_name - if not edit and users: - err = "identifiant %s déjà utilisé" % user_name + existing_user = User.query.filter_by(user_name=user_name) + if ( + edit and existing_user is None + ): # safety net, le user_name ne devrait pas changer + err = f"identifiant {user_name} inexistant" + if not edit and existing_user is not None: + err = f"identifiant %{user_name} déjà utilisé" if err: - H.append(tf_error_message("""Erreur: %s""" % err)) + H.append(tf_error_message(f"""Erreur: {err}""")) return "\n".join(H) + "\n" + tf[1] + F ok, msg = sco_users.check_modif_user( edit, @@ -570,15 +566,20 @@ def create_user_form(user_name=None, edit=0, all_roles=False): vals["roles_string"] = ",".join(roles) # ok, edit - log("sco_users: editing %s by %s" % (user_name, current_user.user_name)) - log("sco_users: previous_values=%s" % initvalues) - log("sco_users: new_values=%s" % vals) + log(f"sco_users: editing {user_name} by {current_user.user_name}") + log(f"sco_users: previous_values={initvalues}") + log(f"sco_users: new_values={vals}") sco_users.user_edit(user_name, vals) + flash(f"Utilisateur {user_name} modifié") return flask.redirect( - "user_info_page?user_name=%s&head_message=Utilisateur %s modifié" - % (user_name, user_name) + url_for( + "users.user_info_page", + scodoc_dept=g.scodoc_dept, + user_name=user_name, + ) ) - else: # creation utilisateur + + else: # création utilisateur vals["roles_string"] = ",".join(vals["roles"]) # check identifiant if not re.match(r"^[a-zA-Z0-9@\\\-_\\\.]+$", vals["user_name"]): @@ -623,8 +624,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False): raise ScoValueError("département invalide") # ok, go log( - "sco_users: new_user %s by %s" - % (vals["user_name"], current_user.user_name) + f"""sco_users: new_user {vals["user_name"]} by {current_user.user_name}""" ) the_user = User() the_user.from_dict(vals, new_user=True) @@ -678,7 +678,8 @@ def import_users_form(): H = [ head, """

Téléchargement d'une nouvelle liste d'utilisateurs

-

A utiliser pour importer de nouveaux utilisateurs (enseignants ou secrétaires) +

A utiliser pour importer de nouveaux + utilisateurs (enseignants ou secrétaires)

L'opération se déroule en deux étapes. Dans un premier temps, @@ -690,7 +691,7 @@ def import_users_form():

""", ] - help = """

+ help_msg = """

Lors de la creation des utilisateurs, les opérations suivantes sont effectuées:

    @@ -727,28 +728,34 @@ def import_users_form(): submitlabel="Télécharger", ) if tf[0] == 0: - return "\n".join(H) + tf[1] + "
" + help + F + return "\n".join(H) + tf[1] + "" + help_msg + F elif tf[0] == -1: return flask.redirect(url_for("scolar.index_html", docodc_dept=g.scodoc_dept)) - else: - # IMPORT - ok, diag, nb_created = sco_import_users.import_excel_file( - tf[2]["xlsfile"], tf[2]["force"] + + # IMPORT + ok, diags, nb_created = sco_import_users.import_excel_file( + tf[2]["xlsfile"], tf[2]["force"] + ) + H = [html_sco_header.sco_header(page_title="Import utilisateurs")] + H.append("") + if ok: + dest_url = url_for("users.index_html", scodoc_dept=g.scodoc_dept, all_depts=1) + H.append( + f"""

Ok, Import terminé ({nb_created} utilisateurs créés)!

+

Continuer

+ """ ) - H = [html_sco_header.sco_header(page_title="Import utilisateurs")] - H.append("") - if ok: - dest = url_for("users.index_html", scodoc_dept=g.scodoc_dept, all_depts=1) - H.append("

Ok, Import terminé (%s utilisateurs créés)!

" % nb_created) - H.append('

Continuer

' % dest) - else: - dest = url_for("users.import_users_form", scodoc_dept=g.scodoc_dept) - H.append("

Erreur, importation annulée !

") - H.append('

Continuer

' % dest) - return "\n".join(H) + html_sco_header.sco_footer() + else: + dest_url = url_for("users.import_users_form", scodoc_dept=g.scodoc_dept) + H.append( + f"""

Erreur, importation annulée !

+

Continuer

+ """ + ) + return "\n".join(H) + html_sco_header.sco_footer() @bp.route("/user_info_page") @@ -759,11 +766,9 @@ def user_info_page(user_name=None): """Display page of info about given user. If user_name not specified, user current_user """ - from app.scodoc.sco_permissions_check import can_handle_passwd - if user_name is not None: # scodoc7func converti en int ! user_name = str(user_name) - # peut on divulguer ces infos ? + # peut-on divulguer ces infos ? if not can_handle_passwd(current_user, allow_admindepts=True): raise AccessDenied("Vous n'avez pas la permission de voir cette page") @@ -877,26 +882,29 @@ def change_password(user_name, password, password2): if not can_handle_passwd(u): # access denied log( - "change_password: access denied (authuser=%s, user_name=%s)" - % (current_user, user_name) + f"change_password: access denied (authuser={current_user}, user_name={user_name})" ) raise AccessDenied("vous n'avez pas la permission de changer ce mot de passe") H = [] F = html_sco_header.sco_footer() # check password + dest_url = url_for( + "users.form_change_password", scodoc_dept=g.scodoc_dept, user_name=user_name + ) if password != password2: H.append( - """

Les deux mots de passes saisis sont différents !

-

Recommencer

""" - % user_name + f"""

Les deux mots de passes saisis sont différents !

+

Recommencer

+ """ ) else: if not is_valid_password(password): H.append( - """

ce mot de passe n\'est pas assez compliqué !
(oui, il faut un mot de passe vraiment compliqué !)

-

Recommencer

- """ - % user_name + f"""

ce mot de passe n'est pas assez compliqué ! +
(oui, il faut un mot de passe vraiment compliqué !) +

+

Recommencer

+ """ ) else: # ok, strong password @@ -907,21 +915,26 @@ def change_password(user_name, password, password2): # ici page simplifiee car on peut ne plus avoir # le droit d'acceder aux feuilles de style H.append( - "

Changement effectué !

Ne notez pas ce mot de passe, mais mémorisez le !

Rappel: il est interdit de communiquer son mot de passe à un tiers, même si c'est un collègue de confiance !

Si vous n'êtes pas administrateur, le système va vous redemander votre login et nouveau mot de passe au prochain accès.

" + """

Changement effectué !

+

Ne notez pas ce mot de passe, mais mémorisez le !

+

Rappel: il est interdit de communiquer son mot de passe à + un tiers, même si c'est un collègue de confiance !

+

Si vous n'êtes pas administrateur, le système va vous redemander + votre login et nouveau mot de passe au prochain accès. +

""" ) return ( - """ - + f""" + Mot de passe changé - +

Mot de passe changé !

""" - % (scu.SCO_ENCODING, scu.SCO_ENCODING) + "\n".join(H) - + 'Continuer' - % scu.ScoURL() + + f'Continuer' ) return html_sco_header.sco_header() + "\n".join(H) + F