Table utilisateurs: affiche date approx. de dernière connexion même si pas SuperAdmin. Option éclater rôles.

This commit is contained in:
Emmanuel Viennet 2024-09-05 18:13:04 +02:00
parent bed5cc2c0c
commit 415e37ab67
2 changed files with 85 additions and 35 deletions

View File

@ -29,6 +29,7 @@
""" """
# Anciennement ZScoUsers.py, fonctions de gestion des données réécrites avec flask/SQLAlchemy # Anciennement ZScoUsers.py, fonctions de gestion des données réécrites avec flask/SQLAlchemy
import datetime
import re import re
from flask import url_for, g, render_template, request from flask import url_for, g, render_template, request
@ -47,7 +48,11 @@ from app.scodoc.sco_exceptions import ScoValueError
def index_html( def index_html(
all_depts=False, having_role_name: str = "", with_inactives=False, fmt="html" all_depts=False,
having_role_name: str = "",
with_inactives=False,
detail_roles=False,
fmt="html",
): ):
"gestion utilisateurs..." "gestion utilisateurs..."
all_depts = int(all_depts) all_depts = int(all_depts)
@ -73,14 +78,6 @@ def index_html(
"""   Pour importer des utilisateurs en masse (via fichier xlsx) """   Pour importer des utilisateurs en masse (via fichier xlsx)
contactez votre administrateur scodoc.""" contactez votre administrateur scodoc."""
) )
if all_depts:
checked = "checked"
else:
checked = ""
if with_inactives:
olds_checked = "checked"
else:
olds_checked = ""
menu_roles = "\n".join( menu_roles = "\n".join(
f"""<option value="{r.name}" { f"""<option value="{r.name}" {
@ -92,9 +89,11 @@ def index_html(
f""" f"""
<form name="f" action="{request.base_url}" method="get"> <form name="f" action="{request.base_url}" method="get">
<input type="checkbox" name="all_depts" value="1" onchange="document.f.submit();" <input type="checkbox" name="all_depts" value="1" onchange="document.f.submit();"
{checked}>Tous les départements</input> {"checked" if all_depts else ""}>Tous les départements</input>
<input type="checkbox" name="with_inactives" value="1" onchange="document.f.submit();" <input type="checkbox" name="with_inactives" value="1" onchange="document.f.submit();"
{olds_checked}>Avec anciens utilisateurs</input> {"checked" if with_inactives else ""}>Avec anciens utilisateurs</input>
<input type="checkbox" name="detail_roles" value="1" onchange="document.f.submit();"
{"checked" if detail_roles else ""}>Sépare les rôles</input>
<label for="having_role_name" style="margin-left:16px;">Filtrer par rôle:</label> <label for="having_role_name" style="margin-left:16px;">Filtrer par rôle:</label>
<select id="having_role_name" name="having_role_name" onchange="document.f.submit();"> <select id="having_role_name" name="having_role_name" onchange="document.f.submit();">
@ -119,6 +118,7 @@ def index_html(
having_role=having_role, having_role=having_role,
with_inactives=with_inactives, with_inactives=with_inactives,
with_links=current_user.has_permission(Permission.UsersAdmin, g.scodoc_dept), with_links=current_user.has_permission(Permission.UsersAdmin, g.scodoc_dept),
detail_roles=detail_roles,
) )
if fmt != "html": if fmt != "html":
return content return content
@ -137,10 +137,12 @@ def list_users(
having_role: Role = None, having_role: Role = None,
with_inactives=False, with_inactives=False,
with_links=True, with_links=True,
detail_roles=False,
): ):
"""List users, returns a table in the specified format. """List users, returns a table in the specified format.
Si with_inactives, inclut les anciens utilisateurs (status "old"). Si with_inactives, inclut les anciens utilisateurs (status "old").
Si having_role, ne liste que les utilisateurs ayant ce rôle. Si having_role, ne liste que les utilisateurs ayant ce rôle.
Si detail_roles, affiche les rôles dans des colonnes séparées.
""" """
from app.scodoc.sco_permissions_check import can_handle_passwd from app.scodoc.sco_permissions_check import can_handle_passwd
@ -179,9 +181,24 @@ def list_users(
d["non_migre"] = ( d["non_migre"] = (
"NON MIGRÉ" if u.passwd_temp or u.password_scodoc7 else "ok" "NON MIGRÉ" if u.passwd_temp or u.password_scodoc7 else "ok"
) )
if not current_user.is_administrator():
# si non super-admin, ne donne pas la date exacte de derniere connexion
d["last_seen"] = _approximate_date(u.last_seen)
else: else:
d["date_modif_passwd"] = "(non visible)" d["date_modif_passwd"] = "(non visible)"
d["non_migre"] = "" d["non_migre"] = ""
if detail_roles:
d["roles_set"] = {
f"{r.role.name or ''}_{r.dept or ''}" for r in u.user_roles
}
if detail_roles:
roles_set = set()
for d in rows:
roles_set.update(d["roles_set"])
roles_columns = sorted(roles_set)
for d in rows:
d.update({r: "X" if r in d["roles_set"] else "" for r in roles_columns})
columns_ids = [ columns_ids = [
"user_name", "user_name",
@ -206,31 +223,39 @@ def list_users(
"cas_allow_scodoc_login", "cas_allow_scodoc_login",
"cas_last_login", "cas_last_login",
] ]
columns_ids += ["email_institutionnel", "edt_id"] elif can_modify:
# Si l'utilisateur est admin local (can_modify) mais pas super admin,
# indique une date de dernière connexion approchée (mois, année)
columns_ids.append("last_seen")
columns_ids += ["email_institutionnel", "edt_id"]
title = "Utilisateurs définis dans ScoDoc" title = "Utilisateurs définis dans ScoDoc"
titles = {
"user_name": "Login",
"nom_fmt": "Nom",
"prenom_fmt": "Prénom",
"email": "Mail",
"email_institutionnel": "Mail institutionnel (opt.)",
"dept": "Dept.",
"roles_string": "Rôles",
"date_expiration": "Expiration",
"date_modif_passwd": "Modif. mot de passe",
"last_seen": "Dernière cnx.",
"non_migre": "Non migré (!)",
"status_txt": "Etat",
"cas_id": "Id CAS",
"cas_allow_login": "CAS autorisé",
"cas_allow_scodoc_login": "Cnx sans CAS",
"cas_last_login": "Dernier login CAS",
"edt_id": "Identifiant emploi du temps",
}
if detail_roles:
columns_ids += roles_columns
titles.update({r: r for r in roles_columns})
tab = GenTable( tab = GenTable(
rows=rows, rows=rows,
columns_ids=columns_ids, columns_ids=columns_ids,
titles={ titles=titles,
"user_name": "Login",
"nom_fmt": "Nom",
"prenom_fmt": "Prénom",
"email": "Mail",
"email_institutionnel": "Mail institutionnel (opt.)",
"dept": "Dept.",
"roles_string": "Rôles",
"date_expiration": "Expiration",
"date_modif_passwd": "Modif. mot de passe",
"last_seen": "Dernière cnx.",
"non_migre": "Non migré (!)",
"status_txt": "Etat",
"cas_id": "Id CAS",
"cas_allow_login": "CAS autorisé",
"cas_allow_scodoc_login": "Cnx sans CAS",
"cas_last_login": "Dernier login CAS",
"edt_id": "Identifiant emploi du temps",
},
caption=title, caption=title,
page_title="title", page_title="title",
html_title=f"""<h2>{len(rows)} utilisateurs {comm}</h2> html_title=f"""<h2>{len(rows)} utilisateurs {comm}</h2>
@ -247,6 +272,28 @@ def list_users(
return tab.make_page(fmt=fmt, with_html_headers=False) return tab.make_page(fmt=fmt, with_html_headers=False)
def _approximate_date(date: datetime.datetime) -> str:
if not date:
return "jamais vu"
now = datetime.datetime.now()
# Calculate the difference in years and months
delta_years = now.year - date.year
delta_months = now.month - date.month
if delta_years == 0 and delta_months == 0:
return "ce mois"
if delta_years == 0 or (delta_years == 1 and delta_months < 0):
return "cette année"
if delta_years == 1:
return "l'an dernier"
if delta_years == 2:
return "il y a 2 ans"
return "pas vu depuis très lontemps"
def get_users_count(dept=None) -> int: def get_users_count(dept=None) -> int:
"""Nombre de comptes utilisateurs, tout état confondu, dans ce dept """Nombre de comptes utilisateurs, tout état confondu, dans ce dept
(ou dans tous si None)""" (ou dans tous si None)"""

View File

@ -135,13 +135,16 @@ class Mode(IntEnum):
@bp.route("/index_html", alias=True) @bp.route("/index_html", alias=True)
@scodoc @scodoc
@permission_required(Permission.UsersView) @permission_required(Permission.UsersView)
@scodoc7func def index_html():
def index_html(
all_depts=False, having_role_name: str = "", with_inactives=False, fmt="html"
):
"Page accueil utilisateur: tableau avec liste des comptes" "Page accueil utilisateur: tableau avec liste des comptes"
all_depts = scu.to_bool(request.args.get("all_depts", False))
detail_roles = scu.to_bool(request.args.get("detail_roles", False))
fmt = request.args.get("fmt", "html")
having_role_name = request.args.get("having_role_name", "")
with_inactives = scu.to_bool(request.args.get("with_inactives", False))
return sco_users.index_html( return sco_users.index_html(
all_depts=all_depts, all_depts=all_depts,
detail_roles=detail_roles,
having_role_name=having_role_name, having_role_name=having_role_name,
with_inactives=with_inactives, with_inactives=with_inactives,
fmt=fmt, fmt=fmt,