2021-06-26 21:57:54 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# ScoDoc
#
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
"""
Module users : interface gestion utilisateurs
ré - écriture pour Flask ScoDoc7 / ZScoUsers . py
Vues s ' appuyant sur auth et sco_users
Emmanuel Viennet , 2021
"""
2021-07-27 16:55:50 +02:00
import datetime
2021-07-03 16:19:42 +02:00
import re
2021-07-11 13:03:13 +02:00
from xml . etree import ElementTree
2021-06-28 10:45:00 +02:00
2021-08-01 10:16:16 +02:00
import flask
2021-08-28 16:01:41 +02:00
from flask import g , url_for , request
from flask import redirect , render_template
2021-08-22 13:24:36 +02:00
2021-06-28 10:45:00 +02:00
from flask_login import current_user
2021-06-26 21:57:54 +02:00
2021-07-01 18:54:07 +02:00
from app import db
2021-08-28 16:01:41 +02:00
from app . auth . forms import DeactivateUserForm
2021-06-26 21:57:54 +02:00
from app . auth . models import Permission
from app . auth . models import User
2021-07-03 16:19:42 +02:00
from app . auth . models import Role
from app . auth . models import UserRole
2021-08-13 09:31:49 +02:00
from app . models import Departement
2021-06-26 21:57:54 +02:00
from app . decorators import (
2021-08-13 00:34:58 +02:00
scodoc ,
2021-06-26 21:57:54 +02:00
scodoc7func ,
permission_required ,
)
2021-08-22 13:24:36 +02:00
from app . scodoc import html_sco_header , sco_import_users , sco_excel
2021-06-26 21:57:54 +02:00
from app . scodoc import sco_users
2021-06-27 12:11:39 +02:00
from app . scodoc import sco_utils as scu
2021-07-11 13:03:13 +02:00
from app . scodoc import sco_xml
2021-08-29 19:57:32 +02:00
from app import log
2021-07-03 16:19:42 +02:00
from app . scodoc . sco_exceptions import AccessDenied , ScoValueError
2021-07-01 18:54:07 +02:00
from app . scodoc . sco_permissions_check import can_handle_passwd
2021-07-03 16:19:42 +02:00
from app . scodoc . TrivialFormulator import TrivialFormulator , tf_error_message
2021-06-26 21:57:54 +02:00
from app . views import users_bp as bp
@bp.route ( " / " )
@bp.route ( " /index_html " )
2021-08-13 00:34:58 +02:00
@scodoc
2021-06-26 21:57:54 +02:00
@permission_required ( Permission . ScoUsersView )
2021-08-21 00:24:51 +02:00
@scodoc7func
def index_html ( REQUEST , all_depts = False , with_inactives = False , format = " html " ) :
2021-06-26 21:57:54 +02:00
return sco_users . index_html (
REQUEST = REQUEST ,
all_depts = all_depts ,
2021-06-27 12:11:39 +02:00
with_inactives = with_inactives ,
2021-06-26 21:57:54 +02:00
format = format ,
)
2021-06-27 12:11:39 +02:00
@bp.route ( " /user_info " )
2021-08-13 00:34:58 +02:00
@scodoc
2021-06-27 12:11:39 +02:00
@permission_required ( Permission . ScoUsersView )
2021-08-21 00:24:51 +02:00
@scodoc7func
2021-06-27 12:11:39 +02:00
def user_info ( user_name , format = " json " , REQUEST = None ) :
2021-08-22 13:24:36 +02:00
info = sco_users . user_info ( user_name )
2021-06-27 12:11:39 +02:00
return scu . sendResult ( REQUEST , info , name = " user " , format = format )
2021-06-28 10:45:00 +02:00
@bp.route ( " /create_user_form " , methods = [ " GET " , " POST " ] )
2021-08-13 00:34:58 +02:00
@scodoc
2021-06-28 10:45:00 +02:00
@permission_required ( Permission . ScoUsersAdmin )
2021-08-21 00:24:51 +02:00
@scodoc7func
2021-09-13 23:06:42 +02:00
def create_user_form ( REQUEST , user_name = None , edit = 0 , all_roles = 1 ) :
" form. création ou edition utilisateur "
2021-06-28 10:45:00 +02:00
auth_dept = current_user . dept
initvalues = { }
edit = int ( edit )
2021-09-13 23:06:42 +02:00
all_roles = int ( all_roles )
2021-07-29 16:31:15 +02:00
H = [ html_sco_header . sco_header ( bodyOnLoad = " init_tf_form( ' ' ) " ) ]
2021-07-29 10:19:00 +02:00
F = html_sco_header . sco_footer ( )
2021-06-28 10:45:00 +02:00
if edit :
if not user_name :
raise ValueError ( " missing argument: user_name " )
2021-07-03 16:19:42 +02:00
u = User . query . filter_by ( user_name = user_name ) . first ( )
if not u :
raise ScoValueError ( " utilisateur inexistant " )
initvalues = u . to_dict ( )
2021-06-28 10:45:00 +02:00
H . append ( " <h2>Modification de l ' utilisateur %s </h2> " % user_name )
else :
H . append ( " <h2>Création d ' un utilisateur</h2> " )
is_super_admin = False
if current_user . has_permission ( Permission . ScoSuperAdmin , g . scodoc_dept ) :
H . append ( """ <p class= " warning " >Vous êtes super administrateur !</p> """ )
is_super_admin = True
2021-09-13 23:06:42 +02:00
if all_roles :
# tous sauf SuperAdmin
standard_roles = [
r
for r in Role . query . all ( )
if r . permissions != Permission . ALL_PERMISSIONS [ 0 ]
]
else :
# Les rôles standards créés à l'initialisation de ScoDoc:
standard_roles = [
Role . get_named_role ( r ) for r in ( " Ens " , " Secr " , " Admin " , " RespPe " )
]
# Départements auxquels ont peut associer des rôles via ce dialogue:
2021-07-03 16:19:42 +02:00
# si SuperAdmin, tous les rôles standards dans tous les départements
# sinon, les départements dans lesquels l'utilisateur a le droit
2021-06-28 10:45:00 +02:00
if is_super_admin :
log ( " create_user_form called by %s (super admin) " % ( current_user . user_name , ) )
2021-08-13 09:31:49 +02:00
dept_ids = [ d . acronym for d in Departement . query . all ( ) ]
2021-06-28 10:45:00 +02:00
else :
2021-07-03 16:19:42 +02:00
# Si on n'est pas SuperAdmin, liste les départements dans lesquels on a la
# permission ScoUsersAdmin
dept_ids = sorted (
set (
[
x . dept
for x in UserRole . query . filter_by ( user = current_user )
if x . role . has_permission ( Permission . ScoUsersAdmin ) and x . dept
]
)
)
editable_roles_set = { ( r , dept ) for r in standard_roles for dept in dept_ids }
2021-06-28 10:45:00 +02:00
#
if not edit :
submitlabel = " Créer utilisateur "
orig_roles = set ( )
else :
submitlabel = " Modifier utilisateur "
2021-07-03 16:19:42 +02:00
if " roles_string " in initvalues :
initvalues [ " roles " ] = initvalues [ " roles_string " ] . split ( " , " )
else :
initvalues [ " roles " ] = [ ]
2021-07-27 16:55:50 +02:00
if " date_expiration " in initvalues :
2021-08-09 14:29:03 +02:00
initvalues [ " date_expiration " ] = (
u . date_expiration . strftime ( " %d / % m/ % Y " ) if u . date_expiration else " "
)
2021-07-27 16:55:50 +02:00
initvalues [ " status " ] = " " if u . active else " old "
2021-07-03 16:19:42 +02:00
orig_roles = { # set des roles existants avant édition
UserRole . role_dept_from_string ( role_dept )
for role_dept in initvalues [ " roles " ]
}
if not initvalues [ " active " ] :
editable_roles_set = set ( ) # can't change roles of a disabled user
editable_roles_strings = { r . name + " _ " + dept for ( r , dept ) in editable_roles_set }
orig_roles_strings = { r . name + " _ " + dept for ( r , dept ) in orig_roles }
2021-06-28 10:45:00 +02:00
# add existing user roles
2021-07-03 16:19:42 +02:00
displayed_roles = list ( editable_roles_set . union ( orig_roles ) )
displayed_roles . sort ( key = lambda x : ( x [ 1 ] , x [ 0 ] . name ) )
displayed_roles_strings = [ r . name + " _ " + dept for ( r , dept ) in displayed_roles ]
displayed_roles_labels = [
" {dept} : {r.name} " . format ( dept = dept , r = r ) for ( r , dept ) in displayed_roles
]
2021-06-28 10:45:00 +02:00
disabled_roles = { } # pour desactiver les roles que l'on ne peut pas editer
2021-07-03 16:19:42 +02:00
for i in range ( len ( displayed_roles_strings ) ) :
if displayed_roles_strings [ i ] not in editable_roles_strings :
2021-06-28 10:45:00 +02:00
disabled_roles [ i ] = True
descr = [
( " edit " , { " input_type " : " hidden " , " default " : edit } ) ,
( " nom " , { " title " : " Nom " , " size " : 20 , " allow_null " : False } ) ,
( " prenom " , { " title " : " Prénom " , " size " : 20 , " allow_null " : False } ) ,
]
2021-07-03 16:19:42 +02:00
if current_user . user_name != user_name :
# no one can change its own status
2021-06-28 10:45:00 +02:00
descr . append (
(
" status " ,
{
" title " : " Statut " ,
" input_type " : " radio " ,
" labels " : ( " actif " , " ancien " ) ,
" allowed_values " : ( " " , " old " ) ,
} ,
)
)
if not edit :
descr + = [
(
" user_name " ,
{
" title " : " Pseudo (login) " ,
" size " : 20 ,
" allow_null " : False ,
" explanation " : " nom utilisé pour la connexion. Doit être unique parmi tous les utilisateurs. " ,
} ,
) ,
(
2021-09-11 22:46:37 +02:00
" password " ,
2021-06-28 10:45:00 +02:00
{
" title " : " Mot de passe " ,
" input_type " : " password " ,
" size " : 14 ,
2021-08-28 16:01:41 +02:00
" allow_null " : True ,
" explanation " : " optionnel, l ' utilisateur pourra le saisir avec son mail " ,
2021-06-28 10:45:00 +02:00
} ,
) ,
(
2021-09-11 22:46:37 +02:00
" password2 " ,
2021-06-28 10:45:00 +02:00
{
" title " : " Confirmer mot de passe " ,
" input_type " : " password " ,
" size " : 14 ,
2021-08-28 16:01:41 +02:00
" allow_null " : True ,
2021-06-28 10:45:00 +02:00
} ,
) ,
]
else :
descr + = [
(
" user_name " ,
{ " input_type " : " hidden " , " default " : initvalues [ " user_name " ] } ,
) ,
2021-07-03 16:19:42 +02:00
( " user_name " , { " input_type " : " hidden " , " default " : initvalues [ " user_name " ] } ) ,
2021-06-28 10:45:00 +02:00
]
descr + = [
(
" email " ,
{
" title " : " e-mail " ,
" input_type " : " text " ,
2021-08-28 16:01:41 +02:00
" explanation " : " requis, doit fonctionner " ,
2021-06-28 10:45:00 +02:00
" size " : 20 ,
2021-08-28 16:01:41 +02:00
" allow_null " : False ,
2021-06-28 10:45:00 +02:00
} ,
)
]
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 " ,
{
" title " : " Département " ,
" 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) """ ,
} ,
)
)
can_choose_dept = True
else :
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 + = [
(
" date_expiration " ,
{
" title " : " Date d ' expiration " , # j/m/a
" input_type " : " date " ,
" explanation " : " j/m/a, laisser vide si pas de limite " ,
" size " : 9 ,
" allow_null " : True ,
} ,
) ,
(
" roles " ,
{
" title " : " Rôles " ,
" input_type " : " checkbox " ,
" vertical " : True ,
2021-07-03 16:19:42 +02:00
" labels " : displayed_roles_labels ,
" allowed_values " : displayed_roles_strings ,
2021-06-28 10:45:00 +02:00
" disabled_items " : disabled_roles ,
} ,
) ,
(
" force " ,
{
" title " : " Ignorer les avertissements " ,
" input_type " : " checkbox " ,
" explanation " : " passer outre les avertissements (homonymes, etc) " ,
" labels " : ( " " , ) ,
" allowed_values " : ( " 1 " , ) ,
} ,
) ,
]
2021-08-15 09:55:35 +02:00
if " tf_submitted " in REQUEST . form and not " roles " in REQUEST . form :
2021-06-28 10:45:00 +02:00
REQUEST . form [ " roles " ] = [ ]
2021-08-15 09:55:35 +02:00
if " tf_submitted " in REQUEST . form :
2021-06-28 10:45:00 +02:00
# Ajoute roles existants mais non modifiables (disabled dans le form)
REQUEST . form [ " roles " ] = list (
2021-07-03 16:19:42 +02:00
set ( REQUEST . form [ " roles " ] ) . union (
orig_roles_strings - editable_roles_strings
)
2021-06-28 10:45:00 +02:00
)
tf = TrivialFormulator (
REQUEST . URL0 ,
REQUEST . form ,
descr ,
initvalues = initvalues ,
submitlabel = submitlabel ,
cancelbutton = " Annuler " ,
)
if tf [ 0 ] == 0 :
return " \n " . join ( H ) + " \n " + tf [ 1 ] + F
elif tf [ 0 ] == - 1 :
2021-07-31 18:01:10 +02:00
return flask . redirect ( scu . UsersURL ( ) )
2021-06-28 10:45:00 +02:00
else :
vals = tf [ 2 ]
2021-07-03 16:19:42 +02:00
roles = set ( vals [ " roles " ] ) . intersection ( editable_roles_strings )
2021-07-09 13:45:10 +02:00
if " edit " in REQUEST . form :
2021-06-28 10:45:00 +02:00
edit = int ( REQUEST . form [ " edit " ] )
else :
edit = 0
try :
force = int ( vals [ " force " ] [ 0 ] )
2021-07-27 16:55:50 +02:00
except ( IndexError , ValueError , TypeError ) :
2021-06-28 10:45:00 +02:00
force = 0
if edit :
user_name = initvalues [ " user_name " ]
else :
user_name = vals [ " user_name " ]
# ce login existe ?
err = None
2021-07-03 16:19:42 +02:00
users = sco_users . _user_list ( user_name )
2021-06-28 10:45:00 +02:00
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
if err :
H . append ( tf_error_message ( """ Erreur: %s """ % err ) )
return " \n " . join ( H ) + " \n " + tf [ 1 ] + F
if not force :
2021-07-03 16:19:42 +02:00
ok , msg = sco_users . check_modif_user (
2021-06-28 10:45:00 +02:00
edit ,
user_name = user_name ,
nom = vals [ " nom " ] ,
prenom = vals [ " prenom " ] ,
email = vals [ " email " ] ,
roles = vals [ " roles " ] ,
)
if not ok :
H . append (
tf_error_message (
""" Attention: %s (vous pouvez forcer l ' opération en cochant " <em>Ignorer les avertissements</em> " en bas de page) """
% msg
)
)
return " \n " . join ( H ) + " \n " + tf [ 1 ] + F
2021-09-11 22:46:37 +02:00
if edit : # modif utilisateur (mais pas password ni user_name !)
2021-07-09 13:45:10 +02:00
if ( not can_choose_dept ) and " dept " in vals :
2021-06-28 10:45:00 +02:00
del vals [ " dept " ]
2021-09-11 22:46:37 +02:00
if " password " in vals :
del vals [ " passwordd " ]
2021-07-09 13:45:10 +02:00
if " date_modif_passwd " in vals :
2021-06-28 10:45:00 +02:00
del vals [ " date_modif_passwd " ]
2021-07-09 13:45:10 +02:00
if " user_name " in vals :
2021-06-28 10:45:00 +02:00
del vals [ " user_name " ]
2021-07-09 13:45:10 +02:00
if ( current_user . user_name == user_name ) and " status " in vals :
2021-06-28 10:45:00 +02:00
del vals [ " status " ] # no one can't change its own status
2021-07-27 16:55:50 +02:00
if " date_expiration " in vals :
try :
2021-08-22 07:47:41 +02:00
if vals [ " date_expiration " ] :
vals [ " date_expiration " ] = datetime . datetime . strptime (
vals [ " date_expiration " ] , " %d / % m/ % Y "
)
else :
vals [ " date_expiration " ] = None
2021-07-27 16:55:50 +02:00
except ValueError :
H . append ( tf_error_message ( " date expiration invalide " ) )
return " \n " . join ( H ) + " \n " + tf [ 1 ] + F
if " status " in vals :
vals [ " active " ] = vals [ " status " ] == " "
2021-06-28 10:45:00 +02:00
# traitement des roles: ne doit pas affecter les roles
# que l'on en controle pas:
2021-07-03 16:19:42 +02:00
for role in orig_roles_strings : # { "Ens_RT", "Secr_CJ", ... }
if role and not role in editable_roles_strings :
2021-06-28 10:45:00 +02:00
roles . add ( role )
2021-07-03 16:19:42 +02:00
vals [ " roles_string " ] = " , " . join ( roles )
2021-06-28 10:45:00 +02:00
# ok, edit
2021-07-03 16:19:42 +02:00
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 )
sco_users . user_edit ( user_name , vals )
2021-07-31 18:01:10 +02:00
return flask . redirect (
2021-07-03 16:19:42 +02:00
" user_info_page?user_name= %s &head_message=Utilisateur %s modifié "
2021-06-28 10:45:00 +02:00
% ( user_name , user_name )
)
else : # creation utilisateur
2021-08-22 00:17:47 +02:00
vals [ " roles_string " ] = " , " . join ( vals [ " roles " ] )
2021-06-28 10:45:00 +02:00
# check identifiant
if not re . match ( r " ^[a-zA-Z0-9@ \\ \ -_ \\ \ .]+$ " , vals [ " user_name " ] ) :
msg = tf_error_message (
" identifiant invalide (pas d ' accents ni de caractères spéciaux) "
)
return " \n " . join ( H ) + msg + " \n " + tf [ 1 ] + F
# check passwords
2021-09-11 22:46:37 +02:00
if vals [ " password " ] :
if vals [ " password " ] != vals [ " password2 " ] :
2021-08-28 16:01:41 +02:00
msg = tf_error_message (
""" Les deux mots de passes ne correspondent pas ! """
)
return " \n " . join ( H ) + msg + " \n " + tf [ 1 ] + F
2021-09-11 22:46:37 +02:00
if not sco_users . is_valid_password ( vals [ " password " ] ) :
2021-08-28 16:01:41 +02:00
msg = tf_error_message (
""" Mot de passe trop simple, recommencez ! """
)
return " \n " . join ( H ) + msg + " \n " + tf [ 1 ] + F
2021-06-28 10:45:00 +02:00
if not can_choose_dept :
vals [ " dept " ] = auth_dept
# ok, go
2021-07-03 16:19:42 +02:00
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 )
db . session . commit ( )
2021-07-31 18:01:10 +02:00
return flask . redirect (
2021-08-28 16:01:41 +02:00
url_for (
" users.user_info_page " ,
scodoc_dept = g . scodoc_dept ,
user_name = user_name ,
head_message = " Nouvel utilisateur créé " ,
)
2021-07-03 16:19:42 +02:00
)
2021-06-26 21:57:54 +02:00
2021-08-22 13:24:36 +02:00
@bp.route ( " /import_users_generate_excel_sample " )
@scodoc
@permission_required ( Permission . ScoUsersAdmin )
@scodoc7func
def import_users_generate_excel_sample ( REQUEST ) :
" une feuille excel pour importation utilisateurs "
data = sco_import_users . generate_excel_sample ( )
2021-09-18 01:30:47 +02:00
breakpoint ( )
return scu . send_file ( data , " ImportUtilisateurs " , scu . XLSX_SUFFIX , scu . XLSX_MIMETYPE , attached = True )
# return sco_excel.send_excel_file(REQUEST, data, "ImportUtilisateurs" + scu.XLSX_SUFFIX)
2021-08-22 13:24:36 +02:00
@bp.route ( " /import_users_form " , methods = [ " GET " , " POST " ] )
@scodoc
@permission_required ( Permission . ScoUsersAdmin )
@scodoc7func
def import_users_form ( REQUEST = None ) :
""" Import utilisateurs depuis feuille Excel """
head = html_sco_header . sco_header ( page_title = " Import utilisateurs " )
H = [
head ,
""" <h2>Téléchargement d ' une nouvelle liste d ' utilisateurs</h2>
< p style = " color: red " > A utiliser pour importer de < b > nouveaux < / b > utilisateurs ( enseignants ou secrétaires )
< / p >
< p >
L ' opération se déroule en deux étapes. Dans un premier temps,
vous téléchargez une feuille Excel type . Vous devez remplir
cette feuille , une ligne décrivant chaque utilisateur . Ensuite ,
vous indiquez le nom de votre fichier dans la case " Fichier Excel "
ci - dessous , et cliquez sur " Télécharger " pour envoyer au serveur
votre liste .
< / p >
""" ,
]
help = """ <p class= " help " >
Lors de la creation des utilisateurs , les opérations suivantes sont effectuées :
< / p >
< ol class = " help " >
< li > vérification des données ; < / li >
< li > génération d ' un mot de passe alétoire pour chaque utilisateur;</li>
< li > création de chaque utilisateur ; < / li >
< li > envoi à chaque utilisateur de son < b > mot de passe initial par mail < / b > . < / li >
< / ol > """
H . append (
""" <ol><li><a class= " stdlink " href= " import_users_generate_excel_sample " >
Obtenir la feuille excel à remplir < / a > < / li > < li > """
)
F = html_sco_header . sco_footer ( )
tf = TrivialFormulator (
REQUEST . URL0 ,
REQUEST . form ,
(
(
" xlsfile " ,
{ " title " : " Fichier Excel: " , " input_type " : " file " , " size " : 40 } ,
) ,
( " formsemestre_id " , { " input_type " : " hidden " } ) ,
) ,
submitlabel = " Télécharger " ,
)
if tf [ 0 ] == 0 :
return " \n " . join ( H ) + tf [ 1 ] + " </li></ol> " + help + F
elif tf [ 0 ] == - 1 :
2021-08-22 19:17:43 +02:00
return flask . redirect ( back_url )
2021-08-22 13:24:36 +02:00
else :
# IMPORT
2021-08-22 19:17:43 +02:00
ok , diag , nb_created = sco_import_users . import_excel_file ( tf [ 2 ] [ " xlsfile " ] )
H = [ html_sco_header . sco_header ( page_title = " Import utilisateurs " ) ]
H . append ( " <ul> " )
for d in diag :
H . append ( " <li> %s </li> " % d )
H . append ( " </ul> " )
2021-08-22 13:24:36 +02:00
if ok :
dest = url_for ( " users.index_html " , scodoc_dept = g . scodoc_dept )
2021-08-22 19:17:43 +02:00
H . append ( " <p>Ok, Import terminé ( %s utilisateurs créés)!</p> " % nb_created )
2021-08-22 13:24:36 +02:00
H . append ( ' <p><a class= " stdlink " href= " %s " >Continuer</a></p> ' % dest )
else :
dest = url_for ( " users.import_users_form " , scodoc_dept = g . scodoc_dept )
H . append ( " <p>Erreur, importation annulée !</p> " )
H . append ( ' <p><a class= " stdlink " href= " %s " >Continuer</a></p> ' % dest )
return " \n " . join ( H ) + html_sco_header . sco_footer ( )
2021-06-26 21:57:54 +02:00
2021-06-27 12:11:39 +02:00
@bp.route ( " /user_info_page " )
2021-08-13 00:34:58 +02:00
@scodoc
2021-06-28 10:45:00 +02:00
@permission_required ( Permission . ScoUsersView )
2021-08-21 00:24:51 +02:00
@scodoc7func
2021-08-22 00:17:47 +02:00
def user_info_page ( user_name ) :
return sco_users . user_info_page ( user_name = user_name )
2021-06-28 10:45:00 +02:00
@bp.route ( " /get_user_list_xml " )
2021-08-13 00:34:58 +02:00
@scodoc
2021-06-28 10:45:00 +02:00
@permission_required ( Permission . ScoView )
2021-08-21 00:24:51 +02:00
@scodoc7func
2021-07-09 13:45:10 +02:00
def get_user_list_xml ( dept = None , start = " " , limit = 25 , REQUEST = None ) :
2021-06-28 10:45:00 +02:00
""" Returns XML list of users with name (nomplogin) starting with start.
2021-09-03 18:17:43 +02:00
Used for forms auto - completion .
"""
# suggère seulement seulement les utilisateurs actifs:
2021-06-28 10:45:00 +02:00
userlist = sco_users . get_user_list ( dept = dept )
2021-07-12 11:54:04 +02:00
start = scu . suppress_accents ( start ) . lower ( )
2021-06-28 10:45:00 +02:00
# TODO : à refaire avec une requete SQL #py3
# (et en json)
userlist = [
user
for user in userlist
2021-08-21 00:24:51 +02:00
if scu . suppress_accents ( ( user . nom or " " ) . lower ( ) ) . startswith ( start )
2021-06-28 10:45:00 +02:00
]
if REQUEST :
REQUEST . RESPONSE . setHeader ( " content-type " , scu . XML_MIMETYPE )
2021-07-11 13:03:13 +02:00
doc = ElementTree . Element ( " results " )
2021-06-28 10:45:00 +02:00
for user in userlist [ : limit ] :
2021-07-12 23:34:18 +02:00
x_rs = ElementTree . Element ( " rs " , id = str ( user . id ) , info = " " )
2021-07-11 13:03:13 +02:00
x_rs . text = user . get_nomplogin ( )
doc . append ( x_rs )
2021-07-12 23:34:18 +02:00
return sco_xml . XML_HEADER + ElementTree . tostring ( doc ) . decode ( scu . SCO_ENCODING )
2021-07-01 18:54:07 +02:00
@bp.route ( " /form_change_password " )
2021-08-13 00:34:58 +02:00
@scodoc
2021-07-01 18:54:07 +02:00
@permission_required ( Permission . ScoView )
2021-08-21 00:24:51 +02:00
@scodoc7func
2021-07-01 18:54:07 +02:00
def form_change_password ( REQUEST , user_name = None ) :
""" Formulaire de changement mot de passe de l ' utilisateur user_name.
Un utilisateur peut toujours changer son propre mot de passe .
"""
if not user_name :
u = current_user
else :
u = User . query . filter_by ( user_name = user_name ) . first ( )
2021-07-29 16:31:15 +02:00
H = [ html_sco_header . sco_header ( user_check = False ) ]
2021-07-29 10:19:00 +02:00
F = html_sco_header . sco_footer ( )
2021-07-01 18:54:07 +02:00
# check access
if not can_handle_passwd ( u ) :
return (
" \n " . join ( H )
+ " <p>Vous n ' avez pas la permission de changer ce mot de passe</p> "
+ F
)
#
H . append (
""" <h2>Changement du mot de passe de <font color= " red " > %(nomplogin)s </font></h2>
< p >
< form action = " change_password " method = " post " > < table >
< tr > < td > Nouveau mot de passe : < / td > < td > < input type = " password " size = " 14 " name = " password " / > < / td > < / tr >
< tr > < td > Confirmation : < / td > < td > < input type = " password " size = " 14 " name = " password2 " / > < / td > < / tr >
< / table >
< input type = " hidden " value = " %(user_name)s " name = " user_name " >
< input type = " submit " value = " Changer " >
< / p >
2021-08-28 16:01:41 +02:00
< p class = " help " > Note : en ScoDoc 9 , les utilisateurs peuvent changer eux - même leur mot de passe
en indiquant l ' adresse mail associée à leur compte.
< / p >
2021-07-01 18:54:07 +02:00
"""
% { " nomplogin " : u . get_nomplogin ( ) , " user_name " : user_name }
)
return " \n " . join ( H ) + F
@bp.route ( " /change_password " , methods = [ " POST " ] )
2021-08-13 00:34:58 +02:00
@scodoc
2021-07-01 18:54:07 +02:00
@permission_required ( Permission . ScoView )
2021-08-21 00:24:51 +02:00
@scodoc7func
2021-07-01 18:54:07 +02:00
def change_password ( user_name , password , password2 , REQUEST ) :
" Change the password for user given by user_name "
u = User . query . filter_by ( user_name = user_name ) . first ( )
# Check access permission
if not can_handle_passwd ( u ) :
# access denied
log (
" change_password: access denied (authuser= %s , user_name= %s , ip= %s ) "
% ( REQUEST . AUTHENTICATED_USER , user_name , REQUEST . REMOTE_ADDR )
)
raise AccessDenied ( " vous n ' avez pas la permission de changer ce mot de passe " )
H = [ ]
2021-07-29 10:19:00 +02:00
F = html_sco_header . sco_footer ( )
2021-07-01 18:54:07 +02:00
# check password
if password != password2 :
H . append (
""" <p>Les deux mots de passes saisis sont différents !</p>
< p > < a href = " form_change_password?user_name= %s " class = " stdlink " > Recommencer < / a > < / p > """
% user_name
)
else :
if not sco_users . is_valid_password ( password ) :
H . append (
""" <p><b>ce mot de passe n \' est pas assez compliqué !</b><br/>(oui, il faut un mot de passe vraiment compliqué !)</p>
< p > < a href = " form_change_password?user_name= %s " class = " stdlink " > Recommencer < / a > < / p >
"""
% user_name
)
else :
# ok, strong password
db . session . add ( u )
u . set_password ( password )
db . session . commit ( )
#
# ici page simplifiee car on peut ne plus avoir
# le droit d'acceder aux feuilles de style
H . append (
" <h2>Changement effectué !</h2><p>Ne notez pas ce mot de passe, mais mémorisez le !</p><p>Rappel: il est <b>interdit</b> de communiquer son mot de passe à un tiers, même si c ' est un collègue de confiance !</p><p><b>Si vous n ' êtes pas administrateur, le système va vous redemander votre login et nouveau mot de passe au prochain accès.</b></p> "
)
return (
""" <?xml version= " 1.0 " encoding= " %s " ?>
< ! DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Transitional//EN " " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd " >
< html >
< head >
< title > Mot de passe changé < / title >
< meta http - equiv = " Content-Type " content = " text/html; charset= %s " / >
< body > < h1 > Mot de passe changé ! < / h1 >
"""
% ( scu . SCO_ENCODING , scu . SCO_ENCODING )
+ " \n " . join ( H )
+ ' <a href= " %s " class= " stdlink " >Continuer</a></body></html> '
% scu . ScoURL ( )
)
2021-07-29 16:31:15 +02:00
return html_sco_header . sco_header ( ) + " \n " . join ( H ) + F
2021-08-28 16:01:41 +02:00
@bp.route ( " /toggle_active_user/<user_name> " , methods = [ " GET " , " POST " ] )
@scodoc
@permission_required ( Permission . ScoUsersAdmin )
def toggle_active_user ( user_name : str = None ) :
""" Change active status of a user account """
u = User . query . filter_by ( user_name = user_name ) . first ( )
if not u :
raise ScoValueError ( " invalid user_name " )
form = DeactivateUserForm ( )
if (
request . method == " POST " and form . cancel . data
) : # if cancel button is clicked, the form.cancel.data will be True
# flash
return redirect ( url_for ( " users.index_html " , scodoc_dept = g . scodoc_dept ) )
if form . validate_on_submit ( ) :
u . active = not u . active
db . session . add ( u )
db . session . commit ( )
return redirect ( url_for ( " users.index_html " , scodoc_dept = g . scodoc_dept ) )
return render_template ( " auth/toogle_active_user.html " , form = form , u = u )