patchcenter/app/templates/users.html
Admin MPCZ 8479d7280e Users/Contacts: workflow profils + LDAP + sync iTop + etat aligne
- Users: 4 profils (admin/coordinator/operator/viewer) remplacent la matrix
- /users/add: picker contacts iTop (plus de creation libre)
- /me/change-password: flow force_password_change
- LDAP: service + section settings + option login
- Sync iTop contacts: filtre par teams (SecOps/iPOP/Externe/DSI/Admin DSI)
- Auto-desactivation users si contact inactif
- etat: alignement sur enum iTop (production/implementation/stock/obsolete)
- Menu: Contacts dans Administration, Serveurs en groupe repliable
- Audit bases: demo/prod via JWT mode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:50:43 +02:00

134 lines
7.3 KiB
HTML

{% extends 'base.html' %}
{% block title %}Utilisateurs{% endblock %}
{% block content %}
<div class="flex justify-between items-center mb-4">
<div>
<h2 class="text-xl font-bold text-cyber-accent">Utilisateurs</h2>
<p class="text-xs text-gray-500 mt-1">Gestion des comptes et profils — les utilisateurs proviennent des contacts iTop synchronisés</p>
</div>
{% if can_edit_users %}
<a href="/users/add" class="btn-primary px-4 py-2 text-sm">+ Ajouter un utilisateur{% if available_count %} <span class="text-xs opacity-70">({{ available_count }} contact{{ 's' if available_count > 1 else '' }} disponible{{ 's' if available_count > 1 else '' }})</span>{% endif %}</a>
{% endif %}
</div>
{% if msg %}
<div class="mb-3 p-2 rounded text-sm {% if 'forbidden' in msg or 'error' in msg or 'cant' in msg or 'invalid' in msg or 'required' in msg %}bg-red-900/30 text-cyber-red{% else %}bg-green-900/30 text-cyber-green{% endif %}">
{% if msg == 'added' %}Utilisateur ajouté.
{% elif msg == 'exists' %}Cet utilisateur existe déjà.
{% elif msg == 'role_changed' %}Profil modifié.
{% elif msg == 'toggled' %}Statut modifié.
{% elif msg == 'password_changed' %}Mot de passe modifié.
{% elif msg == 'auth_changed' %}Méthode d'auth modifiée.
{% elif msg == 'deleted' %}Utilisateur supprimé.
{% elif msg == 'cant_self' %}Impossible sur votre propre compte.
{% elif msg == 'cant_demote_self' %}Vous ne pouvez pas vous rétrograder.
{% elif msg == 'cant_delete_admin' %}Le compte admin local ne peut pas être supprimé.
{% elif msg == 'forbidden' %}Permission refusée.
{% elif msg == 'invalid_role' %}Profil invalide.
{% elif msg == 'contact_required' %}Sélectionner un contact.
{% else %}{{ msg }}{% endif %}
</div>
{% endif %}
<!-- Legende des profils -->
<div class="card p-4 mb-4">
<h3 class="text-sm font-bold text-cyber-accent mb-2">Profils</h3>
<div class="grid grid-cols-1 md:grid-cols-4 gap-3 text-xs">
{% for r in roles %}
<div>
<div class="font-bold text-cyber-accent">{{ profile_labels[r] }}</div>
<div class="text-gray-400 mt-1">{{ profile_descriptions[r] }}</div>
</div>
{% endfor %}
</div>
</div>
<!-- Tableau users -->
<div class="card overflow-hidden">
<table class="w-full table-cyber text-xs">
<thead><tr>
<th class="p-2 text-left">Utilisateur</th>
<th class="p-2">Profil</th>
<th class="p-2">Auth</th>
<th class="p-2">Team iTop</th>
<th class="p-2">Email</th>
<th class="p-2">Statut</th>
<th class="p-2">Dernier login</th>
<th class="p-2">Actions</th>
</tr></thead>
<tbody>
{% for u in users %}
<tr class="border-t border-cyber-border/30 {% if not u.is_active %}opacity-50{% endif %}">
<td class="p-2">
<div class="font-mono font-bold">{{ u.username }}</div>
<div class="text-gray-400">{{ u.display_name or '' }}</div>
{% if u.force_password_change %}<div class="text-cyber-yellow" style="font-size:9px">Doit changer mdp</div>{% endif %}
</td>
<td class="p-2 text-center">
{% if can_edit_users %}
<form method="POST" action="/users/{{ u.id }}/role" style="display:inline">
<select name="role" onchange="this.form.submit()" class="text-xs py-1 px-2">
{% for r in roles %}
<option value="{{ r }}" {% if u.role == r %}selected{% endif %}>{{ profile_labels[r] }}</option>
{% endfor %}
</select>
</form>
{% else %}
<span class="badge badge-blue">{{ profile_labels[u.role] or u.role }}</span>
{% endif %}
</td>
<td class="p-2 text-center">
{% if can_edit_users %}
<form method="POST" action="/users/{{ u.id }}/auth_type" style="display:inline">
<select name="auth_type" onchange="this.form.submit()" class="text-xs py-1 px-2">
<option value="local" {% if u.auth_type == 'local' %}selected{% endif %}>Local</option>
<option value="ldap" {% if u.auth_type == 'ldap' %}selected{% endif %}>LDAP</option>
</select>
</form>
{% else %}
<span class="badge {% if u.auth_type == 'ldap' %}badge-blue{% else %}badge-gray{% endif %}">{{ u.auth_type }}</span>
{% endif %}
</td>
<td class="p-2 text-center text-gray-400">
{% if u.contact_team %}<span class="badge badge-gray">{{ u.contact_team }}</span>{% else %}<span class="text-gray-600"></span>{% endif %}
</td>
<td class="p-2 text-gray-400">{{ u.email or '—' }}</td>
<td class="p-2 text-center">
<span class="badge {% if u.is_active %}badge-green{% else %}badge-red{% endif %}">{{ 'Actif' if u.is_active else 'Inactif' }}</span>
</td>
<td class="p-2 text-center text-gray-400" style="font-size:10px">{% if u.last_login %}{{ u.last_login.strftime('%Y-%m-%d %H:%M') }}{% else %}—{% endif %}</td>
<td class="p-2 text-center">
{% if can_edit_users %}
<form method="POST" action="/users/{{ u.id }}/toggle" style="display:inline">
<button type="submit" class="text-xs {% if u.is_active %}text-cyber-yellow{% else %}text-cyber-green{% endif %} hover:underline">{{ 'Désactiver' if u.is_active else 'Activer' }}</button>
</form>
<button onclick="document.getElementById('pw-{{ u.id }}').style.display='table-row'" class="text-xs text-gray-400 hover:text-cyber-accent ml-2">Mdp</button>
{% if can_admin_users and u.username != 'admin' %}
<form method="POST" action="/users/{{ u.id }}/delete" style="display:inline" onsubmit="return confirm('Supprimer {{ u.username }} ?')">
<button type="submit" class="text-xs text-cyber-red hover:underline ml-2">Supprimer</button>
</form>
{% endif %}
{% endif %}
</td>
</tr>
{% if can_edit_users %}
<tr id="pw-{{ u.id }}" style="display:none" class="bg-cyber-border/20">
<td colspan="8" class="p-3">
<form method="POST" action="/users/{{ u.id }}/password" class="flex gap-2 items-center">
<label class="text-xs text-gray-400">Nouveau mot de passe pour <b>{{ u.username }}</b> :</label>
<input type="password" name="new_password" required minlength="6" class="text-xs py-1 px-2 flex-1">
<label class="text-xs text-gray-400 flex items-center gap-1">
<input type="checkbox" name="force_change" checked> Doit changer au 1er login
</label>
<button type="submit" class="btn-primary px-3 py-1 text-xs">Enregistrer</button>
<button type="button" onclick="document.getElementById('pw-{{ u.id }}').style.display='none'" class="text-xs text-gray-500">Annuler</button>
</form>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}