# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # 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 # ############################################################################## """Import d'utilisateurs via fichier Excel """ from email.MIMEMultipart import ( # pylint: disable=no-name-in-module,import-error MIMEMultipart, ) from email.MIMEText import MIMEText # pylint: disable=no-name-in-module,import-error from email.MIMEBase import MIMEBase # pylint: disable=no-name-in-module,import-error from email.Header import Header # pylint: disable=no-name-in-module,import-error from email import Encoders # pylint: disable=no-name-in-module,import-error import notesdb as ndb import sco_utils as scu from notes_log import log from TrivialFormulator import TrivialFormulator, TF import sco_news import sco_excel from sco_exceptions import AccessDenied, ScoValueError, ScoException TITLES = ("user_name", "nom", "prenom", "email", "roles", "dept") def generate_excel_sample(): """generates an excel document suitable to import users""" style = sco_excel.Excel_MakeStyle(bold=True) titles = TITLES titlesStyles = [style] * len(titles) return sco_excel.Excel_SimpleTable( titles=titles, titlesStyles=titlesStyles, SheetName="Utilisateurs ScoDoc" ) def import_excel_file(datafile, REQUEST=None, context=None): "Create users from Excel file" authuser = REQUEST.AUTHENTICATED_USER auth_name = str(authuser) authuser_info = context._user_list(args={"user_name": auth_name}) zope_roles = authuser.getRolesInContext(context) if not authuser_info and not ("Manager" 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 = "" log("sco_import_users.import_excel_file by %s" % auth_name) exceldata = datafile.read() if not exceldata: raise ScoValueError("Ficher excel vide ou invalide") _, data = sco_excel.Excel_to_list(exceldata) if not data: # probably a bug raise ScoException("import_excel_file: empty file !") # 1- --- check title line fs = [scu.strlower(scu.stripquotes(s)) for s in data[0]] log("excel: fs='%s'\ndata=%s" % (str(fs), str(data))) # check cols cols = {}.fromkeys(TITLES) unknown = [] for tit in fs: if not cols.has_key(tit): unknown.append(tit) else: del cols[tit] if cols or unknown: raise ScoValueError( "colonnes incorrectes (on attend %d, et non %d)
(colonnes manquantes: %s, colonnes invalides: %s)" % (len(TITLES), len(fs), cols.keys(), unknown) ) # ok, same titles... U = [] for line in data[1:]: d = {} for i in range(len(fs)): d[fs[i]] = line[i] U.append(d) return import_users(U, auth_dept=auth_dept, context=context) def import_users(U, auth_dept="", context=None): """Import des utilisateurs: Pour chaque utilisateur à créer: - vérifier données - générer mot de passe aléatoire - créer utilisateur et mettre le mot de passe - envoyer mot de passe par mail En cas d'erreur: supprimer tous les utilisateurs que l'on vient de créer. """ created = [] # liste de uid créés try: for u in U: ok, msg = context._check_modif_user( 0, user_name=u["user_name"], nom=u["nom"], prenom=u["prenom"], email=u["email"], roles=u["roles"], ) if not ok: raise ScoValueError( "données invalides pour %s: %s" % (u["user_name"], msg) ) u["passwd"] = generate_password() # si auth_dept, crée tous les utilisateurs dans ce departement if auth_dept: u["dept"] = auth_dept # context.create_user(u.copy()) created.append(u["user_name"]) except: log("import_users: exception: deleting %s" % str(created)) # delete created users for user_name in created: context._user_delete(user_name) raise # re-raise exception for u in U: mail_password(u, context=context) return "ok" # --------- Génération du mot de passe initial ----------- # Adapté de http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440564 # Alphabet tres simple pour des mots de passe simples... import getpass, random, sha, string, md5, time, base64 ALPHABET = r"""ABCDEFGHIJKLMNPQRSTUVWXYZ123456789123456789AEIOU""" PASSLEN = 6 RNG = random.Random(time.time()) def generate_password(): """This function creates a pseudo random number generator object, seeded with the cryptographic hash of the passString. The contents of the character set is then shuffled and a selection of passLength words is made from this list. This selection is returned as the generated password.""" l = list(ALPHABET) # make this mutable so that we can shuffle the characters RNG.shuffle(l) # shuffle the character set # pick up only a subset from the available characters: return "".join(RNG.sample(l, PASSLEN)) def mail_password(u, context=None, reset=False): "Send password by email" if not u["email"]: return u["url"] = context.ScoURL() txt = ( """ Bonjour %(prenom)s %(nom)s, """ % u ) if reset: txt += ( """ votre mot de passe ScoDoc a été ré-initialisé. Le nouveau mot de passe est: %(passwd)s Votre nom d'utilisateur est %(user_name)s Vous devrez changer ce mot de passe lors de votre première connexion sur %(url)s """ % u ) else: txt += ( """ vous avez été déclaré comme utilisateur du logiciel de gestion de scolarité ScoDoc. Votre nom d'utilisateur est %(user_name)s Votre mot de passe est: %(passwd)s Le logiciel est accessible sur: %(url)s Vous êtes invité à changer ce mot de passe au plus vite (cliquez sur votre nom en haut à gauche de la page d'accueil). """ % u ) txt += ( """ ScoDoc est un logiciel libre développé à l'Université Paris 13 par Emmanuel Viennet. Pour plus d'informations sur ce logiciel, voir %s """ % scu.SCO_WEBSITE ) msg = MIMEMultipart() if reset: msg["Subject"] = Header("Mot de passe ScoDoc", scu.SCO_ENCODING) else: msg["Subject"] = Header("Votre accès ScoDoc", scu.SCO_ENCODING) msg["From"] = context.get_preference("email_from_addr") msg["To"] = u["email"] msg.epilogue = "" txt = MIMEText(txt, "plain", scu.SCO_ENCODING) msg.attach(txt) context.sendEmail(msg)