2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2021-01-01 17:51:08 +01:00
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
2020-09-26 16:19:37 +02:00
#
# 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
#
##############################################################################
""" Gestion des utilisateurs (table SQL pour Zope User Folder)
"""
2021-02-03 22:00:41 +01:00
import string
import re
2020-09-26 16:19:37 +02:00
import time
2021-02-03 22:00:41 +01:00
import md5
import base64
import jaxml
2020-09-26 16:19:37 +02:00
2021-02-03 22:00:41 +01:00
from sco_zope import * # pylint: disable=unused-wildcard-import
2020-09-26 16:19:37 +02:00
# ---------------
2021-02-03 22:00:41 +01:00
import sco_utils as scu
import notesdb as ndb
2020-09-26 16:19:37 +02:00
from notes_log import log
from scolog import logdb
from scolars import format_prenom , format_nom
2021-02-03 22:00:41 +01:00
import sco_import_users
import sco_excel
from TrivialFormulator import TrivialFormulator , TF , tf_error_message
2020-09-26 16:19:37 +02:00
from gen_tables import GenTable
import scolars
import sco_cache
2021-01-16 14:02:18 +01:00
import sco_users
2021-02-03 22:00:41 +01:00
from sco_permissions import (
ScoEditAllEvals ,
ScoEditAllNotes ,
ScoImplement ,
ScoSuperAdmin ,
ScoUsersAdmin ,
ScoUsersView ,
ScoView ,
)
from sco_exceptions import (
AccessDenied ,
ScoException ,
ScoValueError ,
ScoInvalidDateError ,
ScoLockedFormError ,
ScoGenError ,
)
2020-09-26 16:19:37 +02:00
# ---------------
# cache global: chaque instance, repérée par son URL, a un cache
# qui est recréé à la demande
# On cache ici la liste des utilisateurs, pour une duree limitee
# (une minute).
CACHE_userlist = { }
# ---------------
class ZScoUsers (
ObjectManager , PropertyManager , RoleManager , Item , Persistent , Implicit
) :
" ZScousers object "
meta_type = " ZScoUsers "
security = ClassSecurityInfo ( )
# This is the list of the methods associated to 'tabs' in the ZMI
# Be aware that The first in the list is the one shown by default, so if
# the 'View' tab is the first, you will never see your tabs by cliquing
# on the object.
manage_options = (
( { " label " : " Contents " , " action " : " manage_main " } , )
+ PropertyManager . manage_options # add the 'Properties' tab
+ ( { " label " : " View " , " action " : " index_html " } , )
+ Item . manage_options # add the 'Undo' & 'Owner' tab
+ RoleManager . manage_options # add the 'Security' tab
)
# no permissions, only called from python
def __init__ ( self , id , title ) :
" initialise a new instance "
self . id = id
self . title = title
# Connexion to SQL database of users:
# Ugly but necessary during transition out of Zope:
_db_cnx_string = " dbname=SCOUSERS port=5432 "
security . declareProtected ( " Change DTML Documents " , " GetUsersDBConnexion " )
2021-02-03 22:00:41 +01:00
GetUsersDBConnexion = ndb . GetUsersDBConnexion
2020-09-26 16:19:37 +02:00
# --------------------------------------------------------------------
#
# Users (top level)
#
# --------------------------------------------------------------------
# used to view content of the object
security . declareProtected ( ScoUsersView , " index_html " )
def index_html ( self , REQUEST , all = 0 , with_olds = 0 , format = " html " ) :
" gestion utilisateurs... "
all = int ( all )
with_olds = int ( with_olds )
# Controle d'acces
authuser = REQUEST . AUTHENTICATED_USER
user_name = str ( authuser )
# log('user: %s roles: %s'%(user_name,authuser.getRolesInContext(self)))
user = self . _user_list ( args = { " user_name " : user_name } )
if not user :
zope_roles = authuser . getRolesInContext ( self )
if ( " Manager " in zope_roles ) or ( " manage " in zope_roles ) :
dept = " " # special case for zope admin
else :
raise AccessDenied ( " Vous n ' avez pas la permission de voir cette page " )
else :
dept = user [ 0 ] [ " dept " ]
H = [ self . sco_header ( REQUEST , page_title = " Gestion des utilisateurs " ) ]
H . append ( " <h2>Gestion des utilisateurs</h2> " )
if authuser . has_permission ( ScoUsersAdmin , self ) :
H . append (
' <p><a href= " create_user_form " class= " stdlink " >Ajouter un utilisateur</a> '
)
H . append (
' <a href= " import_users_form " class= " stdlink " >Importer des utilisateurs</a></p> '
)
if all :
checked = " checked "
else :
checked = " "
if with_olds :
olds_checked = " checked "
else :
olds_checked = " "
H . append (
""" <p><form name= " f " action= " %s " >
< input type = " checkbox " name = " all " value = " 1 " onchange = " document.f.submit(); " % s > Tous les départements < / input >
< input type = " checkbox " name = " with_olds " value = " 1 " onchange = " document.f.submit(); " % s > Avec anciens utilisateurs < / input >
< / form > < / p > """
% ( REQUEST . URL0 , checked , olds_checked )
)
L = self . list_users (
dept ,
all = all ,
with_olds = with_olds ,
format = format ,
REQUEST = REQUEST ,
with_links = authuser . has_permission ( ScoUsersAdmin , self ) ,
)
if format != " html " :
return L
H . append ( L )
F = self . sco_footer ( REQUEST )
return " \n " . join ( H ) + F
2021-02-03 22:00:41 +01:00
_userEditor = ndb . EditableTable (
2020-09-26 16:19:37 +02:00
" sco_users " ,
" user_id " ,
(
" user_id " ,
" user_name " ,
" passwd " ,
" roles " ,
" date_modif_passwd " ,
" nom " ,
" prenom " ,
" email " ,
" dept " ,
" passwd_temp " ,
" status " ,
" date_expiration " ,
) ,
output_formators = {
2021-02-03 22:00:41 +01:00
" date_modif_passwd " : ndb . DateISOtoDMY ,
" date_expiration " : ndb . DateISOtoDMY ,
2020-09-26 16:19:37 +02:00
} ,
input_formators = {
2021-02-03 22:00:41 +01:00
" date_modif_passwd " : ndb . DateDMYtoISO ,
" date_expiration " : ndb . DateDMYtoISO ,
2020-09-26 16:19:37 +02:00
} ,
sortkey = " nom " ,
filter_nulls = False ,
)
def _user_list ( self , * * kw ) :
# list info sur utilisateur(s)
cnx = self . GetUsersDBConnexion ( )
users = self . _userEditor . list ( cnx , * * kw )
for u in users :
if u [ " status " ] == " old " :
u [ " status_txt " ] = " (ancien) "
else :
u [ " status_txt " ] = " "
return users
def _user_edit ( self , user_name , vals ) :
# edit user
cnx = self . GetUsersDBConnexion ( )
vals [ " user_name " ] = user_name
self . _userEditor . edit ( cnx , vals )
self . get_userlist_cache ( ) . inval_cache ( ) # >
self . acl_users . cache_removeUser ( user_name ) # exUserFolder's caches
self . acl_users . xcache_removeUser ( user_name )
# Ensure that if status is "old", login is disabled
# note that operation is reversible without having to re-enter a password
# We change the roles (to avoid dealing with passwd hash, controled by exUserFolder)
u = self . _user_list ( args = { " user_name " : user_name } ) [ 0 ]
if u [ " status " ] == " old " and u [ " roles " ] and u [ " roles " ] [ 0 ] != " - " :
roles = [ " - " + r for r in u [ " roles " ] . split ( " , " ) ]
2021-02-03 22:00:41 +01:00
cursor = cnx . cursor ( cursor_factory = ndb . ScoDocCursor )
2020-09-26 16:19:37 +02:00
self . acl_users . scodoc_editUser ( cursor , user_name , roles = roles )
self . get_userlist_cache ( ) . inval_cache ( )
elif not u [ " status " ] and u [ " roles " ] and u [ " roles " ] [ 0 ] == " - " :
roles = [ r [ 1 : ] for r in u [ " roles " ] . split ( " , " ) if ( r and r [ 0 ] == " - " ) ]
2021-02-03 22:00:41 +01:00
cursor = cnx . cursor ( cursor_factory = ndb . ScoDocCursor )
2020-09-26 16:19:37 +02:00
self . acl_users . scodoc_editUser ( cursor , user_name , roles = roles )
self . get_userlist_cache ( ) . inval_cache ( )
def _user_delete ( self , user_name ) :
# delete user
cnx = self . GetUsersDBConnexion ( )
user_id = self . _user_list ( args = { " user_name " : user_name } ) [ 0 ] [ " user_id " ]
self . _userEditor . delete ( cnx , user_id )
self . get_userlist_cache ( ) . inval_cache ( ) # >
def _all_roles ( self ) :
" ensemble de tous les roles attribués ou attribuables "
roles = set ( self . DeptUsersRoles ( ) )
cnx = self . GetUsersDBConnexion ( )
L = self . _userEditor . list ( cnx , { } )
for l in L :
roles . update ( [ x . strip ( ) for x in l [ " roles " ] . split ( " , " ) ] )
return [ r for r in roles if r and r [ 0 ] != " - " ]
security . declareProtected ( ScoUsersAdmin , " user_info " )
def user_info ( self , user_name = None , user = None ) :
""" Donne infos sur l ' utilisateur (qui peut ne pas etre dans notre base).
2021-01-01 18:40:47 +01:00
Si user_name est specifie , interroge la BD . Sinon , user doit etre un dict .
2020-09-26 16:19:37 +02:00
"""
if user_name :
infos = self . _user_list ( args = { " user_name " : user_name } )
else :
infos = [ user . copy ( ) ]
user_name = user [ " user_name " ]
if not infos :
# special case: user is not in our database
return {
" user_name " : user_name ,
" nom " : user_name ,
" prenom " : " " ,
" email " : " " ,
" dept " : " " ,
" nomprenom " : user_name ,
" prenomnom " : user_name ,
" prenom_fmt " : " " ,
" nom_fmt " : user_name ,
" nomcomplet " : user_name ,
" nomplogin " : user_name ,
2021-02-03 22:00:41 +01:00
" nomnoacc " : scu . suppress_accents ( user_name ) ,
2020-09-26 16:19:37 +02:00
" passwd_temp " : 0 ,
" status " : " " ,
" date_expiration " : None ,
}
else :
info = infos [ 0 ]
# always conceal password !
del info [ " passwd " ] # always conceal password !
#
if info [ " prenom " ] :
p = format_prenom ( info [ " prenom " ] )
else :
p = " "
if info [ " nom " ] :
n = format_nom (
info [ " nom " ] , uppercase = False
) # strcapitalize(strlower(info['nom']))
else :
n = user_name
2021-02-03 22:00:41 +01:00
prenom_abbrv = scu . abbrev_prenom ( p )
2020-09-26 16:19:37 +02:00
# nomprenom est le nom capitalisé suivi de l'initiale du prénom
info [ " nomprenom " ] = ( n + " " + prenom_abbrv ) . strip ( )
# prenomnom est l'initiale du prénom suivie du nom
info [ " prenomnom " ] = ( prenom_abbrv + " " + n ) . strip ( )
# nom_fmt et prenom_fmt: minuscule capitalisé
info [ " nom_fmt " ] = n
info [ " prenom_fmt " ] = scolars . format_prenom ( p )
# nomcomplet est le prenom et le nom complets
info [ " nomcomplet " ] = info [ " prenom_fmt " ] + " " + info [ " nom_fmt " ]
# nomplogin est le nom en majuscules suivi du prénom et du login
# e.g. Dupont Pierre (dupont)
2021-02-03 22:00:41 +01:00
info [ " nomplogin " ] = " %s %s ( %s ) " % ( scu . strupper ( n ) , p , info [ " user_name " ] )
2020-09-26 16:19:37 +02:00
# nomnoacc est le nom en minuscules sans accents
2021-02-03 22:00:41 +01:00
info [ " nomnoacc " ] = scu . suppress_accents ( scu . strlower ( info [ " nom " ] ) )
2020-09-26 16:19:37 +02:00
return info
def _can_handle_passwd ( self , authuser , user_name , allow_admindepts = False ) :
""" true if authuser can see or change passwd of user_name.
If allow_admindepts , allow Admin from all depts ( so they can view users from other depts
and add roles to them ) .
authuser is a Zope user object . user_name is a string .
"""
# Is authuser a zope admin ?
zope_roles = authuser . getRolesInContext ( self )
if ( " Manager " in zope_roles ) or ( " manage " in zope_roles ) :
return True
# Anyone can change its own passwd (or see its informations)
if str ( authuser ) == user_name :
return True
# has permission ?
if not authuser . has_permission ( ScoUsersAdmin , self ) :
return False
# Ok, now check that authuser can manage users from this departement
# Get user info
user = self . _user_list ( args = { " user_name " : user_name } )
if not user :
return False # we don't have infos on this user !
# Get authuser info
auth_name = str ( authuser )
authuser_info = self . _user_list ( args = { " user_name " : auth_name } )
if not authuser_info :
return False # not admin, and not in out database
auth_dept = authuser_info [ 0 ] [ " dept " ]
if not auth_dept :
return True # if no dept, can access users from all depts !
if auth_dept == user [ 0 ] [ " dept " ] or allow_admindepts :
return True
else :
return False
def do_change_password ( self , user_name , password ) :
user = self . _user_list ( args = { " user_name " : user_name } )
2021-01-10 22:31:00 +01:00
assert len ( user ) == 1 , " database inconsistency: len(user)= %d " % len ( user )
2020-09-26 16:19:37 +02:00
# should not occur, already tested in _can_handle_passwd
cnx = self . GetUsersDBConnexion ( ) # en mode autocommit
2021-02-03 22:00:41 +01:00
cursor = cnx . cursor ( cursor_factory = ndb . ScoDocCursor )
2020-09-26 16:19:37 +02:00
cursor . execute (
" update sco_users set date_modif_passwd=now(), passwd_temp=0 where user_name= %(user_name)s " ,
{ " user_name " : user_name } ,
)
# Laisse le exUserFolder modifier les donnees:
self . acl_users . scodoc_editUser (
cursor , user_name , password = password , roles = [ user [ 0 ] [ " roles " ] ]
)
log ( " change_password: change ok for %s " % user_name )
self . get_userlist_cache ( ) . inval_cache ( ) # >
security . declareProtected ( ScoView , " change_password " )
def change_password ( self , user_name , password , password2 , REQUEST ) :
" change a password "
# ScoUsersAdmin: modif tous les passwd de SON DEPARTEMENT
# sauf si pas de dept (admin global)
H = [ ]
F = self . sco_footer ( REQUEST )
# Check access permission
if not self . _can_handle_passwd ( REQUEST . AUTHENTICATED_USER , user_name ) :
# access denied
log (
" change_password: access denied (authuser= %s , user_name= %s , ip= %s ) "
2021-01-10 22:31:00 +01:00
% ( REQUEST . AUTHENTICATED_USER , user_name , REQUEST . REMOTE_ADDR )
2020-09-26 16:19:37 +02:00
)
raise AccessDenied (
" vous n ' avez pas la permission de changer ce mot de passe "
)
# 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 :
2021-01-16 14:02:18 +01:00
if not sco_users . is_valid_password ( password ) :
2020-09-26 16:19:37 +02:00
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
# MD5 hash (now computed by exUserFolder)
# digest = md5.new()
# digest.update(password)
# digest = digest.digest()
# md5pwd = string.strip(base64.encodestring(digest))
#
self . do_change_password ( user_name , password )
#
# 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 >
"""
2021-02-03 22:00:41 +01:00
% ( scu . SCO_ENCODING , scu . SCO_ENCODING )
2020-09-26 16:19:37 +02:00
+ " \n " . join ( H )
+ ' <a href= " %s " class= " stdlink " >Continuer</a></body></html> '
% self . ScoURL ( )
)
return self . sco_header ( REQUEST ) + " \n " . join ( H ) + F
security . declareProtected ( ScoView , " form_change_password " )
def form_change_password ( self , REQUEST , user_name = None ) :
""" Formulaire changement mot de passe
Un utilisateur peut toujours changer son mot de passe """
authuser = REQUEST . AUTHENTICATED_USER
if not user_name :
user_name = str ( authuser )
H = [ self . sco_header ( REQUEST , user_check = False ) ]
F = self . sco_footer ( REQUEST )
# check access
if not self . _can_handle_passwd ( authuser , user_name ) :
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 " > %(user_name)s </font></h2>
< p >
< form action = " change_password " method = " post " action = " %(url)s " > < 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 >
< p > Vous pouvez aussi : < a class = " stdlink " href = " reset_password_form?user_name= %(user_name)s " > renvoyer un mot de passe aléatoire temporaire par mail à l ' utilisateur</a>
"""
% { " user_name " : user_name , " url " : REQUEST . URL0 }
)
return " \n " . join ( H ) + F
security . declareProtected ( ScoView , " userinfo " )
def userinfo ( self , user_name = None , REQUEST = None ) :
" display page of info about connected user "
authuser = REQUEST . AUTHENTICATED_USER
if not user_name :
user_name = str ( authuser )
# peut on divulguer ces infos ?
if not self . _can_handle_passwd (
REQUEST . AUTHENTICATED_USER , user_name , allow_admindepts = True
) :
raise AccessDenied ( " Vous n ' avez pas la permission de voir cette page " )
H = [ self . sco_header ( REQUEST , page_title = " Utilisateur %s " % user_name ) ]
F = self . sco_footer ( REQUEST )
H . append ( " <h2>Utilisateur: %s " % user_name )
info = self . _user_list ( args = { " user_name " : user_name } )
if info :
H . append ( " %(status_txt)s " % info [ 0 ] )
H . append ( " </h2> " )
if not info :
H . append (
" <p>L ' utilisateur ' %s ' n ' est pas défini dans ce module.</p> "
% user_name
)
if authuser . has_permission ( ScoEditAllNotes , self ) :
H . append ( " <p>(il peut modifier toutes les notes)</p> " )
if authuser . has_permission ( ScoEditAllEvals , self ) :
H . append ( " <p>(il peut modifier toutes les évaluations)</p> " )
if authuser . has_permission ( ScoImplement , self ) :
H . append ( " <p>(il peut creer des formations)</p> " )
else :
H . append (
""" <p>
< b > Login : < / b > % ( user_name ) s < br / >
< b > Nom : < / b > % ( nom ) s < br / >
< b > Prénom : < / b > % ( prenom ) s < br / >
< b > Mail : < / b > % ( email ) s < br / >
< b > Roles : < / b > % ( roles ) s < br / >
< b > Dept : < / b > % ( dept ) s < br / >
< b > Dernière modif mot de passe : < / b > % ( date_modif_passwd ) s < br / >
< b > Date d ' expiration:</b> %(date_expiration)s
< p > < ul >
< li > < a class = " stdlink " href = " form_change_password?user_name= %(user_name)s " > changer le mot de passe < / a > < / li > """
% info [ 0 ]
)
if authuser . has_permission ( ScoUsersAdmin , self ) :
H . append (
"""
< li > < a class = " stdlink " href = " create_user_form?user_name= %(user_name)s &edit=1 " > modifier / déactiver ce compte < / a > < / li >
< li > < a class = " stdlink " href = " delete_user_form?user_name= %(user_name)s " > supprimer cet utilisateur < / a > < em > ( à n ' utiliser qu ' en cas d ' erreur !)</em></li>
"""
% info [ 0 ]
)
H . append ( " </ul> " )
if str ( authuser ) == user_name :
H . append (
' <p><b>Se déconnecter: <a class= " stdlink " href= " acl_users/logout " >logout</a></b></p> '
)
# Liste des permissions
H . append (
' <div class= " permissions " ><p>Permission de cet utilisateur:</p><ul> '
)
permissions = self . ac_inherited_permissions ( 1 )
scoperms = [ p for p in permissions if p [ 0 ] [ : 3 ] == " Sco " ]
try :
thisuser = self . acl_users . getUser ( user_name )
except :
# expired from cache ? retry...
thisuser = self . acl_users . getUser ( user_name )
if not thisuser :
# Cas de figure incompris ? (bug IUT Amiens janvier 2014: login avec accent ?)
H . append (
" <li><em>impossible de retrouver les permissions de l ' utilisateur (contacter l ' administrateur)</em></li> "
)
else :
for p in scoperms :
2021-02-03 22:00:41 +01:00
permname , _ = p [ : 2 ]
2020-09-26 16:19:37 +02:00
if thisuser . has_permission ( permname , self ) :
b = " oui "
else :
b = " non "
H . append ( " <li> %s : %s </li> " % ( permname , b ) )
H . append ( " </ul></div> " )
if authuser . has_permission ( ScoUsersAdmin , self ) :
H . append (
' <p><a class= " stdlink " href= " %s /Users " >Liste de tous les utilisateurs</a></p> '
% self . ScoURL ( )
)
return " \n " . join ( H ) + F
security . declareProtected ( ScoUsersAdmin , " create_user_form " )
def create_user_form ( self , REQUEST , user_name = None , edit = 0 ) :
" form. creation ou edit utilisateur "
# Get authuser info
authuser = REQUEST . AUTHENTICATED_USER
auth_name = str ( authuser )
authuser_info = self . _user_list ( args = { " user_name " : auth_name } )
initvalues = { }
# Access control
zope_roles = authuser . getRolesInContext ( self )
if (
not authuser_info
and not ( " Manager " in zope_roles )
and not ( " manage " in zope_roles )
) :
# not admin, and not in database
raise AccessDenied ( " invalid user ( %s ) " % auth_name )
if authuser_info :
auth_dept = authuser_info [ 0 ] [ " dept " ]
else :
auth_dept = " "
#
edit = int ( edit )
H = [ self . sco_header ( REQUEST , bodyOnLoad = " init_tf_form( ' ' ) " ) ]
F = self . sco_footer ( REQUEST )
if edit :
if not user_name :
raise ValueError ( " missing argument: user_name " )
initvalues = self . _user_list ( args = { " user_name " : user_name } ) [ 0 ]
H . append ( " <h2>Modification de l ' utilisateur %s </h2> " % user_name )
else :
H . append ( " <h2>Création d ' un utilisateur</h2> " )
if authuser . has_permission ( ScoSuperAdmin , self ) :
H . append ( """ <p class= " warning " >Vous êtes super administrateur !</p> """ )
# Noms de roles pouvant etre attribues aux utilisateurs via ce dialogue
# si pas SuperAdmin, restreint aux rôles EnsX, SecrX, DeptX
#
if authuser . has_permission ( ScoSuperAdmin , self ) :
log ( " create_user_form called by %s (super admin) " % ( auth_name , ) )
editable_roles = set ( self . _all_roles ( ) )
else :
editable_roles = set ( self . DeptUsersRoles ( ) )
# log('create_user_form: editable_roles=%s' % editable_roles)
#
if not edit :
submitlabel = " Créer utilisateur "
orig_roles = set ( )
else :
submitlabel = " Modifier utilisateur "
initvalues [ " roles " ] = initvalues [ " roles " ] . split ( " , " ) or [ ]
orig_roles = set ( initvalues [ " roles " ] )
if initvalues [ " status " ] == " old " :
editable_roles = set ( ) # can't change roles of a disabled user
# add existing user roles
displayed_roles = list ( editable_roles . union ( orig_roles ) )
displayed_roles . sort ( )
disabled_roles = { } # pour desactiver les roles que l'on ne peut pas editer
for i in range ( len ( displayed_roles ) ) :
if displayed_roles [ i ] not in editable_roles :
disabled_roles [ i ] = True
# log('create_user_form: displayed_roles=%s' % displayed_roles)
descr = [
( " edit " , { " input_type " : " hidden " , " default " : edit } ) ,
( " nom " , { " title " : " Nom " , " size " : 20 , " allow_null " : False } ) ,
( " prenom " , { " title " : " Prénom " , " size " : 20 , " allow_null " : False } ) ,
]
if auth_name != user_name : # no one can't change its own status
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. " ,
} ,
) ,
(
" passwd " ,
{
" title " : " Mot de passe " ,
" input_type " : " password " ,
" size " : 14 ,
" allow_null " : False ,
} ,
) ,
(
" passwd2 " ,
{
" title " : " Confirmer mot de passe " ,
" input_type " : " password " ,
" size " : 14 ,
" allow_null " : False ,
} ,
) ,
]
else :
descr + = [
(
" user_name " ,
{ " input_type " : " hidden " , " default " : initvalues [ " user_name " ] } ,
) ,
( " user_id " , { " input_type " : " hidden " , " default " : initvalues [ " user_id " ] } ) ,
]
descr + = [
(
" email " ,
{
" title " : " e-mail " ,
" input_type " : " text " ,
" explanation " : " vivement recommandé: utilisé pour contacter l ' utilisateur " ,
" size " : 20 ,
" allow_null " : True ,
} ,
)
]
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 ,
" allowed_values " : displayed_roles ,
" disabled_items " : disabled_roles ,
} ,
) ,
(
" force " ,
{
" title " : " Ignorer les avertissements " ,
" input_type " : " checkbox " ,
" explanation " : " passer outre les avertissements (homonymes, etc) " ,
" labels " : ( " " , ) ,
" allowed_values " : ( " 1 " , ) ,
} ,
) ,
]
if " tf-submitted " in REQUEST . form and not " roles " in REQUEST . form :
REQUEST . form [ " roles " ] = [ ]
if " tf-submitted " in REQUEST . form :
# Ajoute roles existants mais non modifiables (disabled dans le form)
# orig_roles - editable_roles
REQUEST . form [ " roles " ] = list (
set ( REQUEST . form [ " roles " ] ) . union ( orig_roles - editable_roles )
)
tf = TrivialFormulator (
REQUEST . URL0 ,
REQUEST . form ,
descr ,
initvalues = initvalues ,
submitlabel = submitlabel ,
)
if tf [ 0 ] == 0 :
return " \n " . join ( H ) + " \n " + tf [ 1 ] + F
elif tf [ 0 ] == - 1 :
return REQUEST . RESPONSE . redirect ( REQUEST . URL1 )
else :
vals = tf [ 2 ]
roles = set ( vals [ " roles " ] ) . intersection ( editable_roles )
if REQUEST . form . has_key ( " edit " ) :
edit = int ( REQUEST . form [ " edit " ] )
else :
edit = 0
try :
force = int ( vals [ " force " ] [ 0 ] )
except :
force = 0
if edit :
user_name = initvalues [ " user_name " ]
else :
user_name = vals [ " user_name " ]
# ce login existe ?
err = None
users = self . _user_list ( args = { " user_name " : 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
if err :
H . append ( tf_error_message ( """ Erreur: %s """ % err ) )
return " \n " . join ( H ) + " \n " + tf [ 1 ] + F
if not force :
ok , msg = self . _check_modif_user (
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
if edit : # modif utilisateur (mais pas passwd)
if ( not can_choose_dept ) and vals . has_key ( " dept " ) :
del vals [ " dept " ]
if vals . has_key ( " passwd " ) :
del vals [ " passwd " ]
if vals . has_key ( " date_modif_passwd " ) :
del vals [ " date_modif_passwd " ]
if vals . has_key ( " user_name " ) :
del vals [ " user_name " ]
if ( auth_name == user_name ) and vals . has_key ( " status " ) :
del vals [ " status " ] # no one can't change its own status
# traitement des roles: ne doit pas affecter les roles
# que l'on en controle pas:
for role in orig_roles :
if role and not role in editable_roles :
roles . add ( role )
vals [ " roles " ] = " , " . join ( roles )
# ok, edit
log ( " sco_users: editing %s by %s " % ( user_name , auth_name ) )
# log('sco_users: previous_values=%s' % initvalues)
# log('sco_users: new_values=%s' % vals)
self . _user_edit ( user_name , vals )
return REQUEST . RESPONSE . redirect (
" userinfo?user_name= %s &head_message=Utilisateur %s modifié "
% ( user_name , user_name )
)
else : # creation utilisateur
vals [ " roles " ] = " , " . join ( vals [ " roles " ] )
# 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
if vals [ " passwd " ] != vals [ " passwd2 " ] :
msg = tf_error_message (
""" Les deux mots de passes ne correspondent pas ! """
)
return " \n " . join ( H ) + msg + " \n " + tf [ 1 ] + F
2021-01-16 14:02:18 +01:00
if not sco_users . is_valid_password ( vals [ " passwd " ] ) :
2020-09-26 16:19:37 +02:00
msg = tf_error_message (
""" Mot de passe trop simple, recommencez ! """
)
return " \n " . join ( H ) + msg + " \n " + tf [ 1 ] + F
if not can_choose_dept :
vals [ " dept " ] = auth_dept
# ok, go
log ( " sco_users: new_user %s by %s " % ( vals [ " user_name " ] , auth_name ) )
self . create_user ( vals , REQUEST = REQUEST )
def _check_modif_user (
self , edit , user_name = " " , nom = " " , prenom = " " , email = " " , roles = [ ]
) :
""" Vérifie que et utilisateur peut etre crée (edit=0) ou modifié (edit=1)
2021-01-01 18:40:47 +01:00
Cherche homonymes .
2020-09-26 16:19:37 +02:00
returns ( ok , msg )
- ok : si vrai , peut continuer avec ces parametres
( si ok est faux , l ' utilisateur peut quand même forcer la creation)
- msg : message warning a presenter l ' utilisateur
"""
if not user_name or not nom or not prenom :
return False , " champ requis vide "
if not email :
return False , " vous devriez indiquer le mail de l ' utilisateur créé ! "
# ce login existe ?
users = self . _user_list ( args = { " user_name " : user_name } )
if edit and not users : # safety net, le user_name ne devrait pas changer
return False , " identifiant %s inexistant " % user_name
if not edit and users :
return False , " identifiant %s déjà utilisé " % user_name
# Des noms/prénoms semblables existent ?
cnx = self . GetUsersDBConnexion ( )
2021-02-03 22:00:41 +01:00
cursor = cnx . cursor ( cursor_factory = ndb . ScoDocCursor )
2020-09-26 16:19:37 +02:00
cursor . execute (
" select * from sco_users where lower(nom) ~ %(nom)s and lower(prenom) ~ %(prenom)s ; " ,
{ " nom " : nom . lower ( ) . strip ( ) , " prenom " : prenom . lower ( ) . strip ( ) } ,
)
res = cursor . dictfetchall ( )
if edit :
minmatch = 1
else :
minmatch = 0
if len ( res ) > minmatch :
return (
False ,
" des utilisateurs proches existent: "
+ " , " . join (
[
" %s %s (pseudo= %s ) " % ( x [ " prenom " ] , x [ " nom " ] , x [ " user_name " ] )
for x in res
]
) ,
)
# Roles ?
if not roles and not ( edit and users [ 0 ] [ " status " ] == " old " ) :
# nb: si utilisateur desactivé (old), pas de role attribué
return False , " aucun rôle sélectionné, êtes vous sûr ? "
# ok
return True , " "
security . declareProtected ( ScoUsersAdmin , " import_users_form " )
def import_users_form ( self , REQUEST , user_name = None , edit = 0 ) :
""" Import utilisateurs depuis feuille Excel """
head = self . sco_header ( REQUEST , 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 = self . sco_footer ( REQUEST )
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 :
return REQUEST . RESPONSE . redirect ( REQUEST . URL1 )
else :
# IMPORT
diag = sco_import_users . import_excel_file (
tf [ 2 ] [ " xlsfile " ] , REQUEST = REQUEST , context = self
)
H = [ head ]
H . append ( " <p>Import excel: %s </p> " % diag )
H . append ( " <p>OK, import terminé !</p> " )
H . append ( ' <p><a class= " stdlink " href= " %s " >Continuer</a></p> ' % REQUEST . URL1 )
return " \n " . join ( H ) + help + F
security . declareProtected ( ScoUsersAdmin , " import_users_generate_excel_sample " )
def import_users_generate_excel_sample ( self , REQUEST ) :
" une feuille excel pour importation utilisateurs "
data = sco_import_users . generate_excel_sample ( )
return sco_excel . sendExcelFile ( REQUEST , data , " ImportUtilisateurs.xls " )
security . declareProtected ( ScoUsersAdmin , " create_user " )
def create_user ( self , args , REQUEST = None ) :
" creation utilisateur zope "
cnx = self . GetUsersDBConnexion ( )
2021-02-03 22:00:41 +01:00
cursor = cnx . cursor ( cursor_factory = ndb . ScoDocCursor )
2020-09-26 16:19:37 +02:00
passwd = args [ " passwd " ]
args [ " passwd " ] = " undefined "
if " passwd2 " in args :
del args [ " passwd2 " ]
log ( " create_user: args= %s " % args ) # log apres supr. du mot de passe !
2021-02-03 22:00:41 +01:00
_ = self . _userEditor . create ( cnx , args )
2020-09-26 16:19:37 +02:00
self . get_userlist_cache ( ) . inval_cache ( ) # >
# call exUserFolder to set passwd
roles = args [ " roles " ] . split ( " , " )
self . acl_users . scodoc_editUser (
cursor , args [ " user_name " ] , password = passwd , roles = roles
)
if REQUEST :
return REQUEST . RESPONSE . redirect ( REQUEST . URL1 )
security . declareProtected ( ScoUsersAdmin , " delete_user_form " )
def delete_user_form ( self , REQUEST , user_name , dialog_confirmed = False ) :
" delete user "
authuser = REQUEST . AUTHENTICATED_USER
if not self . _can_handle_passwd ( authuser , user_name ) :
return (
self . sco_header ( REQUEST , user_check = False )
+ " <p>Vous n ' avez pas la permission de supprimer cet utilisateur</p> "
+ self . sco_footer ( REQUEST )
)
r = self . _user_list ( args = { " user_name " : user_name } )
if len ( r ) != 1 :
return ScoValueError ( " utilisateur %s inexistant " % user_name )
if not dialog_confirmed :
return self . confirmDialog (
""" <h2>Confirmer la suppression de l \' utilisateur %s ?</h2>
< p class = " warning " > En général , il est déconseillé de supprimer un utilisateur , son
identité étant référencé dans les modules de formation . N ' utilisez
cette fonction qu ' en cas d ' erreur ( création de doublons , etc ) .
< / p >
"""
% user_name ,
dest_url = " " ,
REQUEST = REQUEST ,
cancel_url = REQUEST . URL1 ,
parameters = { " user_name " : user_name } ,
)
self . _user_delete ( user_name )
REQUEST . RESPONSE . redirect ( REQUEST . URL1 )
2021-01-10 22:31:00 +01:00
security . declareProtected ( ScoView , " list_users " )
2020-09-26 16:19:37 +02:00
def list_users (
self ,
dept ,
all = False , # tous les departements
with_olds = False , # inclue les anciens utilisateurs (status "old")
format = " html " ,
with_links = True ,
REQUEST = None ,
) :
" List users "
authuser = REQUEST . AUTHENTICATED_USER
if dept and not all :
r = self . get_userlist ( dept = dept , with_olds = with_olds )
comm = " dept. %s " % dept
else :
r = self . get_userlist ( with_olds = with_olds )
comm = " tous "
if with_olds :
comm + = " , avec anciens "
comm = " ( " + comm + " ) "
# -- Add some information and links:
for u in r :
# Can current user modify this user ?
can_modify = self . _can_handle_passwd (
authuser , u [ " user_name " ] , allow_admindepts = True
)
# Add links
if with_links and can_modify :
target = " userinfo?user_name= %(user_name)s " % u
u [ " _user_name_target " ] = target
u [ " _nom_target " ] = target
u [ " _prenom_target " ] = target
# Hide passwd modification date (depending on rights wrt user)
if not can_modify :
u [ " date_modif_passwd " ] = " (non visible) "
# Add spaces between roles to ease line wrap
if u [ " roles " ] :
u [ " roles " ] = " , " . join ( u [ " roles " ] . split ( " , " ) )
# Convert dates to ISO if XML output
if format == " xml " and u [ " date_modif_passwd " ] != " NA " :
2021-02-03 22:00:41 +01:00
u [ " date_modif_passwd " ] = ndb . DateDMYtoISO ( u [ " date_modif_passwd " ] ) or " "
2020-09-26 16:19:37 +02:00
# Convert date_expiration and date_modif_passwd to ISO to ease sorting
if u [ " date_expiration " ] :
2021-02-03 22:00:41 +01:00
u [ " date_expiration_iso " ] = ndb . DateDMYtoISO ( u [ " date_expiration " ] )
2020-09-26 16:19:37 +02:00
else :
u [ " date_expiration_iso " ] = " "
if u [ " date_modif_passwd " ] :
2021-02-03 22:00:41 +01:00
u [ " date_modif_passwd_iso " ] = ndb . DateDMYtoISO ( u [ " date_expiration " ] )
2020-09-26 16:19:37 +02:00
else :
u [ " date_modif_passwd_iso " ] = " "
title = " Utilisateurs définis dans ScoDoc "
tab = GenTable (
rows = r ,
columns_ids = (
" user_name " ,
" nom_fmt " ,
" prenom_fmt " ,
" email " ,
" dept " ,
" roles " ,
" date_expiration_iso " ,
" date_modif_passwd_iso " ,
" passwd_temp " ,
" status_txt " ,
) ,
titles = {
" user_name " : " Login " ,
" nom_fmt " : " Nom " ,
" prenom_fmt " : " Prénom " ,
" email " : " Mail " ,
" dept " : " Dept. " ,
" roles " : " Rôles " ,
" date_expiration_iso " : " Expiration " ,
" date_modif_passwd_iso " : " Modif. mot de passe " ,
" passwd_temp " : " Temp. " ,
" status_txt " : " Etat " ,
} ,
caption = title ,
page_title = " title " ,
html_title = """ <h2> %d utilisateurs %s </h2>
< p class = " help " > Cliquer sur un nom pour changer son mot de passe < / p > """
% ( len ( r ) , comm ) ,
html_class = " table_leftalign list_users " ,
html_with_td_classes = True ,
html_sortable = True ,
base_url = " %s ?all= %s " % ( REQUEST . URL0 , all ) ,
pdf_link = False , # table is too wide to fit in a paper page => disable pdf
preferences = self . get_preferences ( ) ,
)
return tab . make_page (
self , format = format , with_html_headers = False , REQUEST = REQUEST
)
def get_userlist_cache ( self ) :
url = self . ScoURL ( )
if CACHE_userlist . has_key ( url ) :
return CACHE_userlist [ url ]
else :
log ( " get_userlist_cache: new simpleCache " )
CACHE_userlist [ url ] = sco_cache . expiringCache ( max_validity = 60 )
return CACHE_userlist [ url ]
security . declareProtected ( ScoView , " get_userlist " )
def get_userlist ( self , dept = None , with_olds = False ) :
""" Returns list of users.
If dept , select users from this dept ,
else return all users .
"""
# on ne cache que la liste sans les "olds"
if with_olds :
r = None
else :
cache = self . get_userlist_cache ( )
r = cache . get ( dept )
if r != None :
return r
else :
args = { }
if not with_olds :
args [ " status " ] = None
if dept != None :
args [ " dept " ] = dept
r = self . _user_list ( args = args )
l = [ self . user_info ( user = user ) for user in r ]
if not with_olds :
cache . set ( dept , l )
return l
security . declareProtected ( ScoView , " get_userlist_xml " )
def get_userlist_xml ( self , dept = None , start = " " , limit = 25 , REQUEST = None ) :
""" Returns XML list of users with name (nomplogin) starting with start.
Used for forms auto - completion . """
userlist = self . get_userlist ( dept = dept )
2021-02-03 22:00:41 +01:00
start = scu . suppression_diacritics ( unicode ( start , " utf-8 " ) )
start = scu . strlower ( str ( start ) )
2020-09-26 16:19:37 +02:00
userlist = [ user for user in userlist if user [ " nomnoacc " ] . startswith ( start ) ]
if REQUEST :
2021-02-03 22:00:41 +01:00
REQUEST . RESPONSE . setHeader ( " content-type " , scu . XML_MIMETYPE )
doc = jaxml . XML_document ( encoding = scu . SCO_ENCODING )
2020-09-26 16:19:37 +02:00
doc . results ( )
for user in userlist [ : limit ] :
doc . _push ( )
doc . rs ( user [ " nomplogin " ] , id = user [ " user_id " ] , info = " " )
doc . _pop ( )
return repr ( doc )
security . declareProtected ( ScoView , " get_user_name_from_nomplogin " )
def get_user_name_from_nomplogin ( self , nomplogin ) :
2021-01-01 18:40:47 +01:00
""" Returns user_name (login) from nomplogin """
2020-09-26 16:19:37 +02:00
m = re . match ( r " .* \ ((.*) \ ) " , nomplogin . strip ( ) )
if m :
return m . group ( 1 )
else :
return None
security . declareProtected ( ScoView , " reset_password_form " )
def reset_password_form ( self , user_name = None , dialog_confirmed = False , REQUEST = None ) :
""" Form to reset a password """
if not dialog_confirmed :
return self . confirmDialog (
""" <h2>Ré-initialiser le mot de passe de %s ?</h2>
< p > Le mot de passe de % s va être choisi au hasard et lui être envoyé par mail .
Il devra ensuite se connecter et le changer .
< / p >
"""
% ( user_name , user_name ) ,
parameters = { " user_name " : user_name } ,
REQUEST = REQUEST ,
)
self . reset_password ( user_name = user_name , REQUEST = REQUEST )
return REQUEST . RESPONSE . redirect (
REQUEST . URL1
+ " ?head_message=mot %20d e % 20passe %20d e % 20 "
+ user_name
+ " %20r einitialise "
)
security . declareProtected ( ScoView , " reset_password " )
def reset_password ( self , user_name = None , REQUEST = None ) :
""" Reset a password:
- set user ' s passwd_temp to 1
- set roles to ' ScoReset '
- generate a random password and mail it
"""
authuser = REQUEST . AUTHENTICATED_USER
auth_name = str ( authuser )
if not user_name :
user_name = auth_name
# Access control
if not self . _can_handle_passwd ( authuser , user_name ) :
raise AccessDenied (
" vous n ' avez pas la permission de changer ce mot de passe "
)
log ( " reset_password: %s " % user_name )
# Check that user has valid mail
info = self . user_info ( user_name = user_name )
2021-02-03 22:00:41 +01:00
if not scu . is_valid_mail ( info [ " email " ] ) :
2020-09-26 16:19:37 +02:00
raise Exception ( " pas de mail valide associé à l ' utilisateur " )
# Generate random password
password = sco_import_users . generate_password ( )
self . do_change_password ( user_name , password )
# Flag it as temporary:
cnx = self . GetUsersDBConnexion ( )
2021-02-03 22:00:41 +01:00
cursor = cnx . cursor ( cursor_factory = ndb . ScoDocCursor )
2020-09-26 16:19:37 +02:00
ui = { " user_name " : user_name }
cursor . execute (
" update sco_users set passwd_temp=1 where user_name= ' %(user_name)s ' " % ui
)
# Send email
info [ " passwd " ] = password
sco_import_users . mail_password ( info , context = self , reset = True )
# --------------------------------------------------------------------
#
# Zope Product Administration
#
# --------------------------------------------------------------------
def manage_addZScoUsers (
self , id = " id_ZScousers " , title = " The Title for ZScoUsers Object " , REQUEST = None
) :
" Add a ZScoUsers instance to a folder. "
self . _setObject ( id , ZScoUsers ( id , title ) )
if REQUEST is not None :
return self . manage_main ( self , REQUEST )