Modules: Dashboard, Serveurs, Campagnes, Planning, Specifiques, Settings, Users Stack: FastAPI + Jinja2 + HTMX + Alpine.js + TailwindCSS + PostgreSQL Features: Qualys sync, prereqs auto, planning annuel, server specifics, role-based access Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
111 lines
6.0 KiB
HTML
111 lines
6.0 KiB
HTML
{% extends 'base.html' %}
|
|
{% block title %}Utilisateurs{% endblock %}
|
|
{% block content %}
|
|
<h2 class="text-xl font-bold text-cyber-accent mb-6">Utilisateurs & Permissions</h2>
|
|
|
|
{% if saved %}
|
|
<div class="mb-4 p-3 rounded bg-green-900/30 text-cyber-green text-sm">
|
|
{% if saved == 'add' %}Utilisateur cree.{% elif saved == 'password' %}Mot de passe modifie.{% elif saved == 'toggle' %}Statut modifie.{% else %}Permissions sauvegardees.{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Liste utilisateurs -->
|
|
<div x-data="{ editing: '' }" class="space-y-3">
|
|
{% for ud in users_data %}
|
|
<div class="card overflow-hidden">
|
|
<div class="flex items-center justify-between p-4 cursor-pointer hover:bg-cyber-border/20" @click="editing = editing === '{{ ud.user.id }}' ? '' : '{{ ud.user.id }}'">
|
|
<div class="flex items-center gap-3">
|
|
<span class="font-bold {% if ud.user.is_active %}text-cyber-accent{% else %}text-gray-600 line-through{% endif %}">{{ ud.user.username }}</span>
|
|
<span class="text-sm text-gray-400">{{ ud.user.display_name }}</span>
|
|
<span class="badge {% if ud.user.role == 'admin' %}badge-red{% elif ud.user.role == 'coordinator' %}badge-yellow{% elif ud.user.role == 'operator' %}badge-blue{% else %}badge-gray{% endif %}">{{ ud.user.role }}</span>
|
|
<span class="badge {% if ud.user.is_active %}badge-green{% else %}badge-red{% endif %}">{{ 'Actif' if ud.user.is_active else 'Inactif' }}</span>
|
|
{% if ud.user.email %}<span class="text-xs text-gray-500">{{ ud.user.email }}</span>{% endif %}
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<!-- Permissions resumees -->
|
|
{% for m in modules %}
|
|
{% if ud.perms.get(m) %}
|
|
<span class="text-xs px-1 rounded {% if ud.perms[m] == 'admin' %}bg-red-900/30 text-cyber-red{% elif ud.perms[m] == 'edit' %}bg-blue-900/30 text-cyber-accent{% else %}bg-gray-800 text-gray-500{% endif %}">{{ m[:3] }}</span>
|
|
{% endif %}
|
|
{% endfor %}
|
|
<span class="text-gray-500 text-lg" x-text="editing === '{{ ud.user.id }}' ? '▼' : '▶'"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div x-show="editing === '{{ ud.user.id }}'" class="border-t border-cyber-border p-4 space-y-4">
|
|
<!-- Permissions par module -->
|
|
<form method="POST" action="/users/{{ ud.user.id }}/permissions">
|
|
<h4 class="text-xs text-cyber-accent font-bold uppercase mb-2">Permissions par module</h4>
|
|
<div class="grid grid-cols-6 gap-2">
|
|
{% for m in modules %}
|
|
<div>
|
|
<label class="text-xs text-gray-500 block mb-1">{{ m }}</label>
|
|
<select name="perm_{{ m }}" class="w-full text-xs py-1">
|
|
<option value="">-</option>
|
|
{% for l in levels %}
|
|
<option value="{{ l }}" {% if ud.perms.get(m) == l %}selected{% endif %}>{{ l }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
<button type="submit" class="btn-primary px-4 py-1 text-sm mt-2">Sauvegarder permissions</button>
|
|
</form>
|
|
|
|
<!-- Actions -->
|
|
<div class="flex gap-3 pt-2 border-t border-cyber-border">
|
|
<!-- Reset password -->
|
|
<form method="POST" action="/users/{{ ud.user.id }}/password" class="flex gap-2 items-center">
|
|
<input type="password" name="new_password" placeholder="Nouveau mot de passe" class="text-xs py-1 px-2 w-48">
|
|
<button type="submit" class="btn-sm bg-cyber-border text-cyber-accent">Changer MDP</button>
|
|
</form>
|
|
|
|
<!-- Activer/Desactiver -->
|
|
<form method="POST" action="/users/{{ ud.user.id }}/toggle">
|
|
<button type="submit" class="btn-sm {% if ud.user.is_active %}bg-red-900/30 text-cyber-red{% else %}bg-green-900/30 text-cyber-green{% endif %}">
|
|
{{ 'Desactiver' if ud.user.is_active else 'Activer' }}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<!-- Ajouter un utilisateur -->
|
|
<div class="card p-5 mt-6">
|
|
<h3 class="text-sm font-bold text-cyber-accent mb-3">Ajouter un utilisateur</h3>
|
|
<form method="POST" action="/users/add" class="space-y-3">
|
|
<div class="grid grid-cols-4 gap-3">
|
|
<div>
|
|
<label class="text-xs text-gray-500">Username</label>
|
|
<input type="text" name="new_username" required class="w-full">
|
|
</div>
|
|
<div>
|
|
<label class="text-xs text-gray-500">Nom complet</label>
|
|
<input type="text" name="new_display_name" required class="w-full">
|
|
</div>
|
|
<div>
|
|
<label class="text-xs text-gray-500">Email</label>
|
|
<input type="email" name="new_email" class="w-full">
|
|
</div>
|
|
<div>
|
|
<label class="text-xs text-gray-500">Role global</label>
|
|
<select name="new_role" class="w-full">
|
|
<option value="operator">operator</option>
|
|
<option value="coordinator">coordinator</option>
|
|
<option value="admin">admin</option>
|
|
<option value="viewer">viewer</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="w-64">
|
|
<label class="text-xs text-gray-500">Mot de passe</label>
|
|
<input type="password" name="new_password" required class="w-full">
|
|
</div>
|
|
<p class="text-xs text-gray-600">Les permissions par module seront pre-remplies selon le role choisi. Modifiables ensuite.</p>
|
|
<button type="submit" class="btn-primary px-4 py-2 text-sm">Creer</button>
|
|
</form>
|
|
</div>
|
|
{% endblock %}
|