From 9cd31e66f05ecfd922db503935f34633ae073059 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 29 Dec 2021 11:26:54 +0100 Subject: [PATCH] =?UTF-8?q?Edition/cr=C3=A9eation=20utilisateurs:=20choix?= =?UTF-8?q?=20d=C3=A9partement=20selon=20les=20permissions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/auth/models.py | 18 +++++++- app/views/users.py | 110 ++++++++++++++++++++++++++++++--------------- 2 files changed, 90 insertions(+), 38 deletions(-) diff --git a/app/auth/models.py b/app/auth/models.py index d9c5455b7..bc4edb65f 100644 --- a/app/auth/models.py +++ b/app/auth/models.py @@ -19,7 +19,8 @@ from werkzeug.security import generate_password_hash, check_password_hash import jwt from app import db, login - +from app.models import Departement +from app.models import SHORT_STR_LEN from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_permissions import Permission from app.scodoc.sco_roles_default import SCO_ROLES_DEFAULTS @@ -55,7 +56,7 @@ class User(UserMixin, db.Model): nom = db.Column(db.String(64)) prenom = db.Column(db.String(64)) - dept = db.Column(db.String(32), index=True) + dept = db.Column(db.String(SHORT_STR_LEN), index=True) active = db.Column(db.Boolean, default=True, index=True) password_hash = db.Column(db.String(128)) @@ -71,6 +72,13 @@ class User(UserMixin, db.Model): roles = db.relationship("Role", secondary="user_role", viewonly=True) Permission = Permission + _departement = db.relationship( + "Departement", + foreign_keys=[Departement.acronym], + primaryjoin=(dept == Departement.acronym), + lazy="dynamic", + ) + def __init__(self, **kwargs): self.roles = [] self.user_roles = [] @@ -221,6 +229,12 @@ class User(UserMixin, db.Model): return None return user + def get_dept_id(self) -> int: + "returns user's department id, or None" + if self.dept: + return self._departement.first().id + return None + # Permissions management: def has_permission(self, perm: int, dept=False): """Check if user has permission `perm` in given `dept`. diff --git a/app/views/users.py b/app/views/users.py index b54cbf0c5..f14ecf2a5 100644 --- a/app/views/users.py +++ b/app/views/users.py @@ -167,10 +167,10 @@ def create_user_form(user_name=None, edit=0, all_roles=1): if edit: if not user_name: raise ValueError("missing argument: user_name") - u = User.query.filter_by(user_name=user_name).first() - if not u: + the_user = User.query.filter_by(user_name=user_name).first() + if not the_user: raise ScoValueError("utilisateur inexistant") - initvalues = u.to_dict() + initvalues = the_user.to_dict() H.append("

Modification de l'utilisateur %s

" % user_name) else: H.append("

Création d'un utilisateur

") @@ -197,11 +197,11 @@ def create_user_form(user_name=None, edit=0, all_roles=1): # sinon, les départements dans lesquels l'utilisateur a le droit if is_super_admin: log("create_user_form called by %s (super admin)" % (current_user.user_name,)) - dept_ids = [d.acronym for d in Departement.query.all()] + 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 # permission ScoUsersAdmin - dept_ids = sorted( + administrable_dept_acronyms = sorted( set( [ x.dept @@ -211,7 +211,9 @@ def create_user_form(user_name=None, edit=0, all_roles=1): ) ) - editable_roles_set = {(r, dept) for r in standard_roles for dept in dept_ids} + editable_roles_set = { + (r, dept) for r in standard_roles for dept in administrable_dept_acronyms + } # if not edit: submitlabel = "Créer utilisateur" @@ -224,9 +226,11 @@ def create_user_form(user_name=None, edit=0, all_roles=1): initvalues["roles"] = [] if "date_expiration" in initvalues: initvalues["date_expiration"] = ( - u.date_expiration.strftime("%d/%m/%Y") if u.date_expiration else "" + the_user.date_expiration.strftime("%d/%m/%Y") + if the_user.date_expiration + else "" ) - initvalues["status"] = "" if u.active else "old" + initvalues["status"] = "" if the_user.active else "old" orig_roles = { # set des roles existants avant édition UserRole.role_dept_from_string(role_dept) for role_dept in initvalues["roles"] @@ -347,11 +351,12 @@ def create_user_form(user_name=None, edit=0, all_roles=1): }, ), ] - + # Si auth n'a pas de departement (admin global) + # propose de choisir librement le dept du nouvel utilisateur + # sinon, menu proposant l'ensembe des départements dans lesquels + # nous avons la permission ScoUserAdmin + le dept actuel de l'utilisateur + # modifié. if not auth_dept: - # si auth n'a pas de departement (admin global) - # propose de choisir le dept du nouvel utilisateur - # sinon, il sera créé dans le même département que auth descr.append( ( "dept", @@ -360,35 +365,57 @@ def create_user_form(user_name=None, edit=0, all_roles=1): "input_type": "text", "size": 12, "allow_null": True, - "explanation": """département d\'appartenance 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)""", + "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) + """, }, ) ) can_choose_dept = True else: - can_choose_dept = False - if edit: + selectable_dept_acronyms = set(administrable_dept_acronyms) + if edit: # ajoute dept actuel de l'utilisateur + selectable_dept_acronyms |= {the_user.dept} + if len(selectable_dept_acronyms) > 1: + can_choose_dept = True + selectable_dept_acronyms = sorted(list(selectable_dept_acronyms)) descr.append( ( - "d", + "dept", { - "input_type": "separator", - "title": "L'utilisateur appartient au département %s" - % auth_dept, + "title": "Département", + "input_type": "menu", + "explanation": """département de rattachement de l'utilisateur""", + "labels": selectable_dept_acronyms, + "allowed_values": selectable_dept_acronyms, }, ) ) - else: - descr.append( - ( - "d", - { - "input_type": "separator", - "title": "L'utilisateur sera crée dans le département %s" - % auth_dept, - }, + else: # pas de choix de département + can_choose_dept = False + if edit: + descr.append( + ( + "d", + { + "input_type": "separator", + "title": "L'utilisateur appartient au département %s" + % auth_dept, + }, + ) + ) + else: + descr.append( + ( + "d", + { + "input_type": "separator", + "title": "L'utilisateur sera crée dans le département %s" + % auth_dept, + }, + ) ) - ) descr += [ ( @@ -512,6 +539,10 @@ def create_user_form(user_name=None, edit=0, all_roles=1): del vals["status"] # no one can't change its own status if "status" in vals: vals["active"] = vals["status"] == "" + # Département: + if auth_dept: # pas super-admin + if vals["dept"] not in selectable_dept_acronyms: + del vals["dept"] # ne change pas de dept # traitement des roles: ne doit pas affecter les roles # que l'on en controle pas: for role in orig_roles_strings: # { "Ens_RT", "Secr_CJ", ... } @@ -565,30 +596,37 @@ def create_user_form(user_name=None, edit=0, all_roles=1): """Mot de passe trop simple, recommencez !""" ) return "\n".join(H) + msg + "\n" + tf[1] + F + # Département: if not can_choose_dept: vals["dept"] = auth_dept + else: + if auth_dept: # pas super-admin + if vals["dept"] not in selectable_dept_acronyms: + raise ScoValueError("département invalide") # ok, go log( "sco_users: new_user %s by %s" % (vals["user_name"], current_user.user_name) ) - u = User() - u.from_dict(vals, new_user=True) - db.session.add(u) + the_user = User() + the_user.from_dict(vals, new_user=True) + db.session.add(the_user) db.session.commit() # envoi éventuel d'un message if mode == Mode.WELCOME_AND_CHANGE_PASSWORD or mode == Mode.WELCOME_ONLY: if mode == Mode.WELCOME_AND_CHANGE_PASSWORD: - token = u.get_reset_password_token() + token = the_user.get_reset_password_token() else: token = None send_email( "[ScoDoc] Création de votre compte", sender=from_mail, # current_app.config["ADMINS"][0], - recipients=[u.email], - text_body=render_template("email/welcome.txt", user=u, token=token), + recipients=[the_user.email], + text_body=render_template( + "email/welcome.txt", user=the_user, token=token + ), html_body=render_template( - "email/welcome.html", user=u, token=token + "email/welcome.html", user=the_user, token=token ), )