forked from ScoDoc/ScoDoc
Ajout commande pour changer le login d'un utilisateur
This commit is contained in:
parent
39873183a8
commit
8d50cd2a8e
@ -14,6 +14,15 @@ import cracklib # pylint: disable=import-error
|
|||||||
|
|
||||||
from flask import current_app, g
|
from flask import current_app, g
|
||||||
from flask_login import UserMixin, AnonymousUserMixin
|
from flask_login import UserMixin, AnonymousUserMixin
|
||||||
|
from sqlalchemy.exc import (
|
||||||
|
IntegrityError,
|
||||||
|
DataError,
|
||||||
|
DatabaseError,
|
||||||
|
OperationalError,
|
||||||
|
ProgrammingError,
|
||||||
|
StatementError,
|
||||||
|
InterfaceError,
|
||||||
|
)
|
||||||
|
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
|
|
||||||
@ -48,13 +57,13 @@ def is_valid_password(cleartxt) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def invalid_user_name(user_name: str) -> bool:
|
def is_valid_user_name(user_name: str) -> bool:
|
||||||
"Check that user_name (aka login) is invalid"
|
"Check that user_name (aka login) is valid"
|
||||||
return (
|
return (
|
||||||
not user_name
|
user_name
|
||||||
or (len(user_name) < 2)
|
and (len(user_name) >= 2)
|
||||||
or (len(user_name) >= USERNAME_STR_LEN)
|
and (len(user_name) < USERNAME_STR_LEN)
|
||||||
or not VALID_LOGIN_EXP.match(user_name)
|
and VALID_LOGIN_EXP.match(user_name)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -123,7 +132,7 @@ class User(UserMixin, ScoDocModel):
|
|||||||
# check login:
|
# check login:
|
||||||
if not "user_name" in kwargs:
|
if not "user_name" in kwargs:
|
||||||
raise ValueError("missing user_name argument")
|
raise ValueError("missing user_name argument")
|
||||||
if invalid_user_name(kwargs["user_name"]):
|
if not is_valid_user_name(kwargs["user_name"]):
|
||||||
raise ValueError(f"invalid user_name: {kwargs['user_name']}")
|
raise ValueError(f"invalid user_name: {kwargs['user_name']}")
|
||||||
kwargs["nom"] = kwargs.get("nom", "") or ""
|
kwargs["nom"] = kwargs.get("nom", "") or ""
|
||||||
kwargs["prenom"] = kwargs.get("prenom", "") or ""
|
kwargs["prenom"] = kwargs.get("prenom", "") or ""
|
||||||
@ -329,7 +338,8 @@ class User(UserMixin, ScoDocModel):
|
|||||||
if new_user:
|
if new_user:
|
||||||
if "user_name" in data:
|
if "user_name" in data:
|
||||||
# never change name of existing users
|
# never change name of existing users
|
||||||
if invalid_user_name(data["user_name"]):
|
# (see change_user_name method to do that)
|
||||||
|
if not is_valid_user_name(data["user_name"]):
|
||||||
raise ValueError(f"invalid user_name: {data['user_name']}")
|
raise ValueError(f"invalid user_name: {data['user_name']}")
|
||||||
self.user_name = data["user_name"]
|
self.user_name = data["user_name"]
|
||||||
if "password" in data:
|
if "password" in data:
|
||||||
@ -522,6 +532,64 @@ class User(UserMixin, ScoDocModel):
|
|||||||
|
|
||||||
# nomnoacc était le nom en minuscules sans accents (inutile)
|
# nomnoacc était le nom en minuscules sans accents (inutile)
|
||||||
|
|
||||||
|
def change_user_name(self, new_user_name: str):
|
||||||
|
"""Modify user name, update all relevant tables.
|
||||||
|
commit session.
|
||||||
|
"""
|
||||||
|
# Safety check
|
||||||
|
new_user_name = new_user_name.strip()
|
||||||
|
if (
|
||||||
|
not is_valid_user_name(new_user_name)
|
||||||
|
or User.query.filter_by(user_name=new_user_name).count() > 0
|
||||||
|
):
|
||||||
|
raise ValueError("invalid user_name")
|
||||||
|
# Le user_name est utilisé dans d'autres tables (sans être une clé)
|
||||||
|
# BulAppreciations.author
|
||||||
|
# EntrepriseHistorique.authenticated_user
|
||||||
|
# EtudAnnotation.author
|
||||||
|
# ScolarNews.authenticated_user
|
||||||
|
# Scolog.authenticated_user
|
||||||
|
from app.models import (
|
||||||
|
BulAppreciations,
|
||||||
|
EtudAnnotation,
|
||||||
|
ScolarNews,
|
||||||
|
Scolog,
|
||||||
|
)
|
||||||
|
from app.entreprises.models import EntrepriseHistorique
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Update all instances of EtudAnnotation
|
||||||
|
db.session.query(BulAppreciations).filter(
|
||||||
|
BulAppreciations.author == self.user_name
|
||||||
|
).update({BulAppreciations.author: new_user_name})
|
||||||
|
db.session.query(EntrepriseHistorique).filter(
|
||||||
|
EntrepriseHistorique.authenticated_user == self.user_name
|
||||||
|
).update({EntrepriseHistorique.authenticated_user: new_user_name})
|
||||||
|
db.session.query(EtudAnnotation).filter(
|
||||||
|
EtudAnnotation.author == self.user_name
|
||||||
|
).update({EtudAnnotation.author: new_user_name})
|
||||||
|
db.session.query(ScolarNews).filter(
|
||||||
|
ScolarNews.authenticated_user == self.user_name
|
||||||
|
).update({ScolarNews.authenticated_user: new_user_name})
|
||||||
|
db.session.query(Scolog).filter(
|
||||||
|
Scolog.authenticated_user == self.user_name
|
||||||
|
).update({Scolog.authenticated_user: new_user_name})
|
||||||
|
# And update ourself:
|
||||||
|
self.user_name = new_user_name
|
||||||
|
db.session.add(self)
|
||||||
|
db.session.commit()
|
||||||
|
except (
|
||||||
|
IntegrityError,
|
||||||
|
DataError,
|
||||||
|
DatabaseError,
|
||||||
|
OperationalError,
|
||||||
|
ProgrammingError,
|
||||||
|
StatementError,
|
||||||
|
InterfaceError,
|
||||||
|
) as exc:
|
||||||
|
db.session.rollback()
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
|
||||||
class AnonymousUser(AnonymousUserMixin):
|
class AnonymousUser(AnonymousUserMixin):
|
||||||
"Notre utilisateur anonyme"
|
"Notre utilisateur anonyme"
|
||||||
|
@ -18,7 +18,7 @@ from app.auth.forms import (
|
|||||||
ResetPasswordRequestForm,
|
ResetPasswordRequestForm,
|
||||||
UserCreationForm,
|
UserCreationForm,
|
||||||
)
|
)
|
||||||
from app.auth.models import Role, User, invalid_user_name
|
from app.auth.models import Role, User, is_valid_user_name
|
||||||
from app.auth.email import send_password_reset_email
|
from app.auth.email import send_password_reset_email
|
||||||
from app.decorators import admin_required
|
from app.decorators import admin_required
|
||||||
from app.forms.generic import SimpleConfirmationForm
|
from app.forms.generic import SimpleConfirmationForm
|
||||||
@ -35,10 +35,12 @@ def _login_form():
|
|||||||
form = LoginForm()
|
form = LoginForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
# note: ceci est la première requête SQL déclenchée par un utilisateur arrivant
|
# note: ceci est la première requête SQL déclenchée par un utilisateur arrivant
|
||||||
if invalid_user_name(form.user_name.data):
|
user = (
|
||||||
user = None
|
User.query.filter_by(user_name=form.user_name.data).first()
|
||||||
else:
|
if is_valid_user_name(form.user_name.data)
|
||||||
user = User.query.filter_by(user_name=form.user_name.data).first()
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
if user is None or not user.check_password(form.password.data):
|
if user is None or not user.check_password(form.password.data):
|
||||||
current_app.logger.info("login: invalid (%s)", form.user_name.data)
|
current_app.logger.info("login: invalid (%s)", form.user_name.data)
|
||||||
flash(_("Nom ou mot de passe invalide"))
|
flash(_("Nom ou mot de passe invalide"))
|
||||||
|
@ -151,7 +151,7 @@ class EntrepriseHistorique(db.Model):
|
|||||||
__tablename__ = "are_historique"
|
__tablename__ = "are_historique"
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
||||||
authenticated_user = db.Column(db.Text)
|
authenticated_user = db.Column(db.Text) # user_name login sans contrainte
|
||||||
entreprise_id = db.Column(db.Integer)
|
entreprise_id = db.Column(db.Integer)
|
||||||
object = db.Column(db.Text)
|
object = db.Column(db.Text)
|
||||||
object_id = db.Column(db.Integer)
|
object_id = db.Column(db.Integer)
|
||||||
|
@ -27,7 +27,7 @@ class Scolog(db.Model):
|
|||||||
method = db.Column(db.Text)
|
method = db.Column(db.Text)
|
||||||
msg = db.Column(db.Text)
|
msg = db.Column(db.Text)
|
||||||
etudid = db.Column(db.Integer) # sans contrainte pour garder logs après suppression
|
etudid = db.Column(db.Integer) # sans contrainte pour garder logs après suppression
|
||||||
authenticated_user = db.Column(db.Text) # login, sans contrainte
|
authenticated_user = db.Column(db.Text) # user_name login, sans contrainte
|
||||||
# zope_remote_addr suppressed
|
# zope_remote_addr suppressed
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -76,7 +76,9 @@ class ScolarNews(db.Model):
|
|||||||
date = db.Column(
|
date = db.Column(
|
||||||
db.DateTime(timezone=True), server_default=db.func.now(), index=True
|
db.DateTime(timezone=True), server_default=db.func.now(), index=True
|
||||||
)
|
)
|
||||||
authenticated_user = db.Column(db.Text, index=True) # login, sans contrainte
|
authenticated_user = db.Column(
|
||||||
|
db.Text, index=True
|
||||||
|
) # user_name login, sans contrainte
|
||||||
# type in 'INSCR', 'NOTES', 'FORM', 'SEM', 'MISC'
|
# type in 'INSCR', 'NOTES', 'FORM', 'SEM', 'MISC'
|
||||||
type = db.Column(db.String(SHORT_STR_LEN), index=True)
|
type = db.Column(db.String(SHORT_STR_LEN), index=True)
|
||||||
object = db.Column(
|
object = db.Column(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.6.979"
|
SCOVERSION = "9.6.980"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
12
scodoc.py
12
scodoc.py
@ -385,6 +385,18 @@ def user_role(username, dept_acronym=None, add_role_name=None, remove_role_name=
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
@app.cli.command()
|
||||||
|
@click.argument("user_name")
|
||||||
|
@click.argument("new_user_name")
|
||||||
|
def user_change_login(user_name, new_user_name):
|
||||||
|
"""Change user's login (user_name)"""
|
||||||
|
user: User = User.query.filter_by(user_name=user_name).first()
|
||||||
|
if not user:
|
||||||
|
sys.stderr.write(f"user_change_login: user {user_name} does not exists\n")
|
||||||
|
return 1
|
||||||
|
user.change_user_name(new_user_name)
|
||||||
|
|
||||||
|
|
||||||
def abort_if_false(ctx, param, value):
|
def abort_if_false(ctx, param, value):
|
||||||
if not value:
|
if not value:
|
||||||
ctx.abort()
|
ctx.abort()
|
||||||
|
@ -185,6 +185,7 @@ def anonymize_users(cursor):
|
|||||||
)
|
)
|
||||||
# Change les username: utilisés en référence externe
|
# Change les username: utilisés en référence externe
|
||||||
# dans diverses tables:
|
# dans diverses tables:
|
||||||
|
# NB: la méthode User.change_user_name fait la même chose
|
||||||
for table, field in (
|
for table, field in (
|
||||||
("etud_annotations", "author"),
|
("etud_annotations", "author"),
|
||||||
("scolog", "authenticated_user"),
|
("scolog", "authenticated_user"),
|
||||||
|
Loading…
Reference in New Issue
Block a user