Merge branch 'master' of https://scodoc.org/git/viennet/ScoDoc into refactor_nt

This commit is contained in:
Emmanuel Viennet 2021-12-29 11:32:32 +01:00
commit 78e8b407d2
2 changed files with 90 additions and 38 deletions

View File

@ -19,7 +19,8 @@ from werkzeug.security import generate_password_hash, check_password_hash
import jwt import jwt
from app import db, login 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_exceptions import ScoValueError
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_roles_default import SCO_ROLES_DEFAULTS 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)) nom = db.Column(db.String(64))
prenom = 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) active = db.Column(db.Boolean, default=True, index=True)
password_hash = db.Column(db.String(128)) 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) roles = db.relationship("Role", secondary="user_role", viewonly=True)
Permission = Permission Permission = Permission
_departement = db.relationship(
"Departement",
foreign_keys=[Departement.acronym],
primaryjoin=(dept == Departement.acronym),
lazy="dynamic",
)
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.roles = [] self.roles = []
self.user_roles = [] self.user_roles = []
@ -221,6 +229,12 @@ class User(UserMixin, db.Model):
return None return None
return user 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: # Permissions management:
def has_permission(self, perm: int, dept=False): def has_permission(self, perm: int, dept=False):
"""Check if user has permission `perm` in given `dept`. """Check if user has permission `perm` in given `dept`.

View File

@ -167,10 +167,10 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
if edit: if edit:
if not user_name: if not user_name:
raise ValueError("missing argument: user_name") raise ValueError("missing argument: user_name")
u = User.query.filter_by(user_name=user_name).first() the_user = User.query.filter_by(user_name=user_name).first()
if not u: if not the_user:
raise ScoValueError("utilisateur inexistant") raise ScoValueError("utilisateur inexistant")
initvalues = u.to_dict() initvalues = the_user.to_dict()
H.append("<h2>Modification de l'utilisateur %s</h2>" % user_name) H.append("<h2>Modification de l'utilisateur %s</h2>" % user_name)
else: else:
H.append("<h2>Création d'un utilisateur</h2>") H.append("<h2>Création d'un utilisateur</h2>")
@ -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 # sinon, les départements dans lesquels l'utilisateur a le droit
if is_super_admin: if is_super_admin:
log("create_user_form called by %s (super admin)" % (current_user.user_name,)) 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: else:
# Si on n'est pas SuperAdmin, liste les départements dans lesquels on a la # Si on n'est pas SuperAdmin, liste les départements dans lesquels on a la
# permission ScoUsersAdmin # permission ScoUsersAdmin
dept_ids = sorted( administrable_dept_acronyms = sorted(
set( set(
[ [
x.dept 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: if not edit:
submitlabel = "Créer utilisateur" submitlabel = "Créer utilisateur"
@ -224,9 +226,11 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
initvalues["roles"] = [] initvalues["roles"] = []
if "date_expiration" in initvalues: if "date_expiration" in initvalues:
initvalues["date_expiration"] = ( 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 orig_roles = { # set des roles existants avant édition
UserRole.role_dept_from_string(role_dept) UserRole.role_dept_from_string(role_dept)
for role_dept in initvalues["roles"] 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: 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( descr.append(
( (
"dept", "dept",
@ -360,35 +365,57 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
"input_type": "text", "input_type": "text",
"size": 12, "size": 12,
"allow_null": True, "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 can_choose_dept = True
else: else:
can_choose_dept = False selectable_dept_acronyms = set(administrable_dept_acronyms)
if edit: 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( descr.append(
( (
"d", "dept",
{ {
"input_type": "separator", "title": "Département",
"title": "L'utilisateur appartient au département %s" "input_type": "menu",
% auth_dept, "explanation": """département de rattachement de l'utilisateur""",
"labels": selectable_dept_acronyms,
"allowed_values": selectable_dept_acronyms,
}, },
) )
) )
else: else: # pas de choix de département
descr.append( can_choose_dept = False
( if edit:
"d", descr.append(
{ (
"input_type": "separator", "d",
"title": "L'utilisateur sera crée dans le département %s" {
% auth_dept, "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 += [ 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 del vals["status"] # no one can't change its own status
if "status" in vals: if "status" in vals:
vals["active"] = vals["status"] == "" 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 # traitement des roles: ne doit pas affecter les roles
# que l'on en controle pas: # que l'on en controle pas:
for role in orig_roles_strings: # { "Ens_RT", "Secr_CJ", ... } 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 !""" """Mot de passe trop simple, recommencez !"""
) )
return "\n".join(H) + msg + "\n" + tf[1] + F return "\n".join(H) + msg + "\n" + tf[1] + F
# Département:
if not can_choose_dept: if not can_choose_dept:
vals["dept"] = auth_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 # ok, go
log( log(
"sco_users: new_user %s by %s" "sco_users: new_user %s by %s"
% (vals["user_name"], current_user.user_name) % (vals["user_name"], current_user.user_name)
) )
u = User() the_user = User()
u.from_dict(vals, new_user=True) the_user.from_dict(vals, new_user=True)
db.session.add(u) db.session.add(the_user)
db.session.commit() db.session.commit()
# envoi éventuel d'un message # envoi éventuel d'un message
if mode == Mode.WELCOME_AND_CHANGE_PASSWORD or mode == Mode.WELCOME_ONLY: if mode == Mode.WELCOME_AND_CHANGE_PASSWORD or mode == Mode.WELCOME_ONLY:
if mode == Mode.WELCOME_AND_CHANGE_PASSWORD: if mode == Mode.WELCOME_AND_CHANGE_PASSWORD:
token = u.get_reset_password_token() token = the_user.get_reset_password_token()
else: else:
token = None token = None
send_email( send_email(
"[ScoDoc] Création de votre compte", "[ScoDoc] Création de votre compte",
sender=from_mail, # current_app.config["ADMINS"][0], sender=from_mail, # current_app.config["ADMINS"][0],
recipients=[u.email], recipients=[the_user.email],
text_body=render_template("email/welcome.txt", user=u, token=token), text_body=render_template(
"email/welcome.txt", user=the_user, token=token
),
html_body=render_template( html_body=render_template(
"email/welcome.html", user=u, token=token "email/welcome.html", user=the_user, token=token
), ),
) )