diff --git a/app/static/js/user_form.js b/app/static/js/user_form.js new file mode 100644 index 00000000..5cbdf490 --- /dev/null +++ b/app/static/js/user_form.js @@ -0,0 +1,30 @@ + +function refresh() { + if ($("input[name='welcome:list']").is(":checked")) { + $("input[name='reset_password:list']").closest("tr").css("display", "table-row") + if ($("input[name='reset_password:list']").is(":checked")) { + $("#tf_password").closest('tr').css("display", "none"); + $("#tf_password2").closest('tr').css("display", "none"); + } else { + // Le mot de passe doit être saisi + $("#tf_password").closest('tr').css("display", "table-row"); + $("#tf_password2").closest('tr').css("display", "table-row"); + } + } else { + // Le mot de passe doit être saisi + $("input[name='reset_password:list']").closest("tr").css("display", "none") + $("#tf_password").closest('tr').css("display", "table-row"); + $("#tf_password2").closest('tr').css("display", "table-row"); + } +} + +$(function() { + $("input[name='welcome:list']").click(function() { + refresh(); + }) + $("input[name='reset_password:list']").click(function() { + refresh(); + }) + refresh(); +}) + diff --git a/app/templates/email/welcome.html b/app/templates/email/welcome.html new file mode 100644 index 00000000..7f2d6ad6 --- /dev/null +++ b/app/templates/email/welcome.html @@ -0,0 +1,16 @@ +

Bienvenue {{ user.prenom }} {{ user.nom }},

+

+ Votre accès à ScoDoc vient d'être validé. + votre identifiant de connexion est: {{ user.user_name }} + + {% if token %} + Pour initialiser votre mot de passe ScoDoc, + + cliquez sur ce lien + . +

+

Vous pouvez aussi copier ce lien dans votre navigateur Web:

+

{{ url_for('auth.reset_password', token=token, _external=True) }}

+ {% endif %} + +

A bientôt !

\ No newline at end of file diff --git a/app/templates/email/welcome.txt b/app/templates/email/welcome.txt new file mode 100644 index 00000000..b15bceae --- /dev/null +++ b/app/templates/email/welcome.txt @@ -0,0 +1,11 @@ +Bienvenue {{ user.prenom }} {{ user.nom }}, + +Votre accès à ScoDoc vient d'être validé. +Votre identifiant de connexion est: {{ user.user_name }} + +{% if token %} + Pour initialiser votre mot de passe ScoDoc, suivre le lien: + {{ url_for('auth.reset_password', token=token, _external=True) }} +{% endif %} + +

A bientôt !

\ No newline at end of file diff --git a/app/views/users.py b/app/views/users.py index cddcf195..430633d5 100644 --- a/app/views/users.py +++ b/app/views/users.py @@ -38,7 +38,7 @@ import re from xml.etree import ElementTree import flask -from flask import g, url_for, request +from flask import g, url_for, request, current_app from flask import redirect, render_template from flask_login import current_user @@ -49,6 +49,7 @@ from app.auth.models import Permission from app.auth.models import User from app.auth.models import Role from app.auth.models import UserRole +from app.email import send_email from app.models import Departement from app.decorators import ( @@ -63,6 +64,7 @@ from app.scodoc import sco_utils as scu from app.scodoc import sco_xml from app import log from app.scodoc.sco_exceptions import AccessDenied, ScoValueError +from app.scodoc.sco_import_users import generate_password from app.scodoc.sco_permissions_check import can_handle_passwd from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message from app.views import users_bp as bp @@ -100,7 +102,12 @@ def create_user_form(user_name=None, edit=0, all_roles=1): initvalues = {} edit = int(edit) all_roles = int(all_roles) - H = [html_sco_header.sco_header(bodyOnLoad="init_tf_form('')")] + H = [ + html_sco_header.sco_header( + bodyOnLoad="init_tf_form('')", + javascripts=["js/user_form.js"], + ) + ] F = html_sco_header.sco_footer() if edit: if not user_name: @@ -214,7 +221,32 @@ def create_user_form(user_name=None, edit=0, all_roles=1): "title": "Pseudo (login)", "size": 20, "allow_null": False, - "explanation": "nom utilisé pour la connexion. Doit être unique parmi tous les utilisateurs.", + "explanation": "nom utilisé pour la connexion. Doit être unique parmi tous les utilisateurs. " + "Lettres ou chiffres uniquement.", + }, + ), + ("formsemestre_id", {"input_type": "hidden"}), + ( + "welcome", + { + "title": "Message d'accueil", + "input_type": "checkbox", + "explanation": "Envoie un mail d'accueil à l'utilisateur.", + "labels": ("",), + "allowed_values": ("1",), + "default": "1", + }, + ), + ( + "reset_password", + { + "title": "réinit. mot de passe.", + "input_type": "checkbox", + "explanation": "ajoute la procédure de changement de mot de passe au mail d'accueil", + "labels": ("",), + "allowed_values": ("1",), + "default": "1", + "attributes": ["style='margin-left:20pt'"], }, ), ( @@ -387,7 +419,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1): nom=vals["nom"], prenom=vals["prenom"], email=vals["email"], - dept=vals["dept"], + dept=vals.get("dept", auth_dept), roles=vals["roles"], ) if not ok: @@ -444,18 +476,33 @@ def create_user_form(user_name=None, edit=0, all_roles=1): "identifiant invalide (pas d'accents ni de caractères spéciaux)" ) return "\n".join(H) + msg + "\n" + tf[1] + F + # Traitement initial (mode) : 3 cas + # A: envoi de welcome + procedure de reset + # B: envoi de welcome seulement (mot de passe saisie dans le formulaire) + # C: Aucun envoi (mot de pase saisi dans le formulaire) + if vals["welcome:list"] == "1": + if vals["reset_password:list"] == "1": + mode = "A" + else: + mode = "B" + else: + mode = "C" + # check passwords - if vals["password"]: - if vals["password"] != vals["password2"]: - msg = tf_error_message( - """Les deux mots de passes ne correspondent pas !""" - ) - return "\n".join(H) + msg + "\n" + tf[1] + F - if not sco_users.is_valid_password(vals["password"]): - msg = tf_error_message( - """Mot de passe trop simple, recommencez !""" - ) - return "\n".join(H) + msg + "\n" + tf[1] + F + if mode == "A": + vals["password"] = generate_password() + else: + if vals["password"]: + if vals["password"] != vals["password2"]: + msg = tf_error_message( + """Les deux mots de passes ne correspondent pas !""" + ) + return "\n".join(H) + msg + "\n" + tf[1] + F + if not sco_users.is_valid_password(vals["password"]): + 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 @@ -467,6 +514,22 @@ def create_user_form(user_name=None, edit=0, all_roles=1): u.from_dict(vals, new_user=True) db.session.add(u) db.session.commit() + # envoi éventuel d'un message + if mode == "A" or mode == "B": + if mode == "A": + token = u.get_reset_password_token() + else: + token = None + send_email( + "[ScoDoc] Réinitialisation de votre mot de passe", + sender=current_app.config["ADMINS"][0], + recipients=[u.email], + text_body=render_template("email/welcome.txt", user=u, token=token), + html_body=render_template( + "email/welcome.html", user=u, token=token + ), + ) + return flask.redirect( url_for( "users.user_info_page",