Merge branch 'jmplace-change_email'

This commit is contained in:
Emmanuel Viennet 2021-10-17 11:20:27 +02:00
commit 29ec51c001
11 changed files with 238 additions and 136 deletions

View File

@ -33,7 +33,7 @@ token_auth = HTTPTokenAuth()
@basic_auth.verify_password
def verify_password(username, password):
user = User.query.filter_by(username=username).first()
user = User.query.filter_by(user_name=username).first()
if user and user.check_password(password):
return user

View File

@ -43,8 +43,11 @@ class UserCreationForm(FlaskForm):
class ResetPasswordRequestForm(FlaskForm):
email = StringField(_l("Email"), validators=[DataRequired(), Email()])
submit = SubmitField(_l("Valider ce mot de passe"))
email = StringField(
_l("Adresse email associée à votre compte ScoDoc:"),
validators=[DataRequired(), Email()],
)
submit = SubmitField(_l("Envoyer"))
class ResetPasswordForm(FlaskForm):

View File

@ -98,7 +98,9 @@ def reset_password_request():
current_app.logger.info(
"reset_password_request: for unkown user '{}'".format(form.email.data)
)
flash(_("Voir les instructions envoyées par mail"))
flash(
_("Voir les instructions envoyées par mail (pensez à regarder vos spams)")
)
return redirect(url_for("auth.login"))
return render_template(
"auth/reset_password_request.html", title=_("Reset Password"), form=form

View File

@ -32,6 +32,7 @@
import re
from flask import url_for, g, request
from flask.templating import render_template
from flask_login import current_user
@ -271,102 +272,6 @@ def user_info(user_name_or_id=None, user=None):
return info
def user_info_page(user_name=None):
"""Display page of info about given user.
If user_name not specified, user current_user
"""
from app.scodoc.sco_permissions_check import can_handle_passwd
# peut on divulguer ces infos ?
if not can_handle_passwd(current_user, allow_admindepts=True):
raise AccessDenied("Vous n'avez pas la permission de voir cette page")
dept = g.scodoc_dept
if not user_name:
user = current_user
else:
user = User.query.filter_by(user_name=user_name).first()
if not user:
raise ScoValueError("invalid user_name")
H = [
html_sco_header.sco_header(
page_title="Utilisateur %s" % user.user_name,
)
]
F = html_sco_header.sco_footer()
H.append("<h2>Utilisateur: %s" % user.user_name)
info = user.to_dict()
if info:
H.append(" (%(status_txt)s)" % info)
H.append("</h2>")
if not info:
H.append(
"<p>L' utilisateur '%s' n'est pas défini dans ce module.</p>" % user_name
)
if user.has_permission(Permission.ScoEditAllNotes, dept):
H.append("<p>(il peut modifier toutes les notes de %s)</p>" % dept)
if user.has_permission(Permission.ScoEditAllEvals, dept):
H.append("<p>(il peut modifier toutes les évaluations de %s)</p>" % dept)
if user.has_permission(Permission.ScoImplement, dept):
H.append("<p>(il peut creer des formations en %s)</p>" % dept)
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_string)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
)
if current_user.has_permission(Permission.ScoUsersAdmin, dept):
H.append(
f"""
<li><a class="stdlink" href="{url_for('users.create_user_form', scodoc_dept=g.scodoc_dept,
user_name=user.user_name, edit=1)}">modifier ce compte</a>
</li>
<li><a class="stdlink" href="{url_for('users.toggle_active_user', scodoc_dept=g.scodoc_dept,
user_name=user.user_name)
}">{"désactiver" if user.active else "activer"} ce compte</a>
</li>
"""
% info
)
H.append("</ul>")
if current_user.user_name == user_name:
H.append(
'<p><b>Se déconnecter: <a class="stdlink" href="%s">logout</a></b></p>'
% url_for("auth.logout")
)
# Liste des permissions
H.append(
'<div class="permissions"><p>Permissions de cet utilisateur dans le département %s:</p><ul>'
% dept
)
for p in Permission.description:
perm = getattr(Permission, p)
if user.has_permission(perm, dept):
b = "oui"
else:
b = "non"
H.append("<li>%s : %s</li>" % (Permission.description[p], b))
H.append("</ul></div>")
if current_user.has_permission(Permission.ScoUsersAdmin, dept):
H.append(
'<p><a class="stdlink" href="%s">Liste de tous les utilisateurs</a></p>'
% url_for("users.index_html", scodoc_dept=g.scodoc_dept)
)
return "\n".join(H) + F
def check_modif_user(
edit,
enforce_optionals=False,

View File

@ -0,0 +1,52 @@
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% macro render_field(field) %}
<tr style="">
<td class="wtf-field">{{ field.label }}</td>
<td class="wtf-field">{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</td>
</tr>
{% endmacro %}
{% block app_content %}
<h1>Modification du compte ScoDoc <tt>{{form.user_name.data}}</tt></h1>
<div class="help">
<p>Identifiez-vous avez votre mot de passe actuel</p>
<p>Vous pouvez changer le mot de passe et/ou l'adresse email.</p>
<p>Les champs vides ne seront pas changés.</p>
</div>
<form method=post>
{{ form.user_name }}
{{ form.csrf_token }}
<table class="tf"><tbody>
{{ render_field(form.old_password, size=14,
style="padding:1px; margin-left: 1em; margin-top: 4px;") }}
{{ render_field(form.new_password, size=14,
style="padding:1px; margin-left: 1em; margin-top: 12px;") }}
{{ render_field(form.bis_password, size=14,
style="padding:1px; margin-left: 1em; margin-top: 4px;") }}
{{ render_field(form.email, size=40,
style="padding:1px; margin-top: 12px;margin-bottom: 16px; margin-left: 1em;") }}
</tbody></table>
<input type="submit" value="Valider">
<input type="submit" name="cancel" value="Annuler" style="margin-left: 1em;>
</form>
{#<div class="row" style="margin-top: 30px;">#}
{#<div class="col-md-4">Votre identifiant: <b>{{user.user_name}}</b></div>#}
{#</div>#}
{##}
{#<div class="row" style="margin-top: 30px;">#}
{# <div class="col-md-4">#}
{# {{ wtf.quick_form(form) }}#}
{# </div>#}
{#</div>#}
{% endblock %}

View File

@ -2,7 +2,7 @@
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
<h1>Reset Password</h1>
<h1>Demande d'un nouveau mot de passe</h1>
<div class="row">
<div class="col-md-4">
{{ wtf.quick_form(form) }}

View File

@ -0,0 +1,67 @@
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
<h2>Utilisateur: {{user.user_name}} ({{'actif' if user.active else 'fermé'}})</h2>
<p>
<b>Login :</b> {{user.user_name}}<br/>
<b>Nom :</b> {{user.nom or ""}}<br/>
<b>Prénom :</b> {{user.prenom or ""}}<br/>
<b>Mail :</b> {{user.email}}<br/>
<b>Roles :</b> {{user.get_roles_string()}}<br/>
<b>Dept :</b> {{user.dept or ""}}<br/>
<b>Dernière modif mot de passe:</b>
{{user.date_modif_passwd.isoformat() if user.date_modif_passwd else ""}}<br/>
<b>Date d'expiration:</b>
{{user.date_expiration.isoformat() if user.date_expiration else "(sans limite)"}}
<p>
<ul>
<li><a class="stdlink" href="{{
url_for( 'users.form_change_password',
scodoc_dept=g.scodoc_dept, user_name=user.user_name)
}}">modifier le mot de passe ou l'adresse mail</a>
</li>
{% if current_user.has_permission(Permission.ScoUsersAdmin, dept) %}
<li><a class="stdlink" href="{{
url_for('users.create_user_form', scodoc_dept=g.scodoc_dept,
user_name=user.user_name, edit=1)
}}">modifier ce compte</a>
</li>
<li><a class="stdlink" href="{{
url_for('users.toggle_active_user', scodoc_dept=g.scodoc_dept,
user_name=user.user_name)
}}">{{"désactiver" if user.active else "activer"}} ce compte</a>
</li>
{% endif %}
</ul>
{% if current_user.id == user.id %}
<p><b>Se déconnecter:
<a class="stdlink" href="{{url_for('auth.logout')}}">logout</a>
</b></p>
{% endif %}
{# Liste des permissions #}
<div class="permissions">
<p>Permissions de cet utilisateur dans le département {dept}:</p>
<ul>
{% for p in Permission.description %}
<li>{{Permission.description[p]}} :
{{
"oui" if user.has_permission(Permission.get_by_name(p), dept) else "non"
}}
</li>
{% endfor %}
</ul>
</div>
{% if current_user.has_permission(Permission.ScoUsersAdmin, dept) %}
<p><a class="stdlink" href="
{{url_for('users.index_html', scodoc_dept=g.scodoc_dept)}}
">Liste de tous les utilisateurs</a></p>
{% endif %}
{% endblock %}

View File

@ -22,12 +22,19 @@
</button>
<a class="navbar-brand" href="{{ url_for('scodoc.index') }}">ScoDoc</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
{% if current_user.is_administrator() %}
<ul class="nav navbar-nav">
<li><a href="{{ url_for('scodoc.configuration') }}">configuration</a></li>
</ul>
{% if current_user.is_administrator() %}
<li><a href="{{ url_for('scodoc.configuration') }}">Configuration</a></li>
{% endif %}
{% if g.scodoc_dept %}
<li><a href="{{
url_for('scolar.index_html', scodoc_dept=g.scodoc_dept)
}}">Dept. {{ g.scodoc_dept }}</a></li>
{% endif %}
</ul>
<ul class="nav navbar-nav navbar-right">
{% if current_user.is_anonymous %}
<li><a href="{{ url_for('auth.login') }}">connexion</a></li>

View File

@ -5,7 +5,7 @@
cliquez sur ce lien
</a>.
</p>
<p>Vous pouvez aussi copier ce lien dans votre navigateur Web::</p>
<p>Vous pouvez aussi copier ce lien dans votre navigateur Web:</p>
<p>{{ url_for('auth.reset_password', token=token, _external=True) }}</p>
<p>Si vous n'avez pas demandé à réinitialiser votre mot de passe sur

View File

@ -38,10 +38,12 @@ import re
from xml.etree import ElementTree
import flask
from flask import g, url_for, request, current_app
from flask import g, url_for, request, current_app, flash
from flask import redirect, render_template
from flask_login import current_user
from wtforms import HiddenField, PasswordField, StringField, SubmitField
from wtforms.validators import DataRequired, Email, ValidationError, EqualTo
from app import db
from app.auth.forms import DeactivateUserForm
@ -69,6 +71,41 @@ 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
from flask_wtf import FlaskForm
_ = lambda x: x # sans babel
_l = _
class ChangePasswordForm(FlaskForm):
user_name = HiddenField()
old_password = PasswordField(_l("Ancien mot de passe"))
new_password = PasswordField(_l("Nouveau mot de passe"))
bis_password = PasswordField(
_l("Répéter"),
validators=[
EqualTo(
"new_password",
message="Les deux saisies sont " "différentes, recommencez",
),
],
)
email = StringField(_l("Email"), validators=[DataRequired(), Email()])
submit = SubmitField()
cancel = SubmitField("Annuler")
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user is not None and self.user_name.data != user.user_name:
raise ValidationError(_("Adresse e-mail invalide"))
def validate_new_password(self, new_password):
if new_password.data != "" and not is_valid_password(new_password.data):
raise ValidationError(f"Mot de passe trop simple, recommencez")
def validate_old_password(self, old_password):
if not current_user.check_password(old_password.data):
raise ValidationError("Mot de passe actuel incorrect, ré-essayez")
@bp.route("/")
@ -644,8 +681,31 @@ def import_users_form():
@scodoc
@permission_required(Permission.ScoUsersView)
@scodoc7func
def user_info_page(user_name):
return sco_users.user_info_page(user_name=user_name)
def user_info_page(user_name=None):
"""Display page of info about given user.
If user_name not specified, user current_user
"""
from app.scodoc.sco_permissions_check import can_handle_passwd
# peut on divulguer ces infos ?
if not can_handle_passwd(current_user, allow_admindepts=True):
raise AccessDenied("Vous n'avez pas la permission de voir cette page")
dept = g.scodoc_dept
if not user_name:
user = current_user
else:
user = User.query.filter_by(user_name=user_name).first()
if not user:
raise ScoValueError("invalid user_name")
return render_template(
"auth/user_info_page.html",
user=user,
title=f"Utilisateur {user.user_name}",
Permission=Permission,
dept=dept,
)
@bp.route("/get_user_list_xml")
@ -676,7 +736,7 @@ def get_user_list_xml(dept=None, start="", limit=25):
return scu.send_file(data, mime=scu.XML_MIMETYPE)
@bp.route("/form_change_password")
@bp.route("/form_change_password", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func
@ -685,36 +745,42 @@ def form_change_password(user_name=None):
Un utilisateur peut toujours changer son propre mot de passe.
"""
if not user_name:
u = current_user
user = current_user
else:
u = User.query.filter_by(user_name=user_name).first()
H = [html_sco_header.sco_header(user_check=False)]
F = html_sco_header.sco_footer()
user = User.query.filter_by(user_name=user_name).first()
# 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
if not can_handle_passwd(user):
return "\n".join(
[
html_sco_header.sco_header(user_check=False),
"<p>Vous n'avez pas la permission de changer ce mot de passe</p>",
html_sco_header.sco_footer(),
]
)
#
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>
<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>
"""
% {"nomplogin": u.get_nomplogin(), "user_name": user_name}
form = ChangePasswordForm(user_name=user.user_name, email=user.email)
destination = url_for(
"users.user_info_page",
scodoc_dept=g.scodoc_dept,
user_name=user_name,
)
if request.method == "POST" and form.cancel.data: # cancel button clicked
return redirect(destination)
if form.validate_on_submit():
messages = []
if form.new_password.data != "": # change password
user.set_password(form.new_password.data)
messages.append("Mot de passe modifié")
if form.email.data != user.email: # change email
user.email = form.email.data
messages.append("Adresse email modifiée")
db.session.commit()
flash("\n".join(messages))
return redirect(destination)
return render_template(
"auth/change_password.html", form=form, title="Modification compte ScoDoc"
)
return "\n".join(H) + F
@bp.route("/change_password", methods=["POST"])

View File

@ -1,7 +1,7 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
SCOVERSION = "9.0.53"
SCOVERSION = "9.0.54"
SCONAME = "ScoDoc"