Files
proxmox_manager/templates/admin_users.html
2026-02-17 12:43:27 +01:00

412 lines
15 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Gestione Utenti - Proxmox Manager{% endblock %}
{% block extra_styles %}
<style>
.users-table-container {
overflow-x: auto;
}
.action-buttons {
display: flex;
gap: 0.5rem;
}
.action-buttons .btn {
padding: 0.5rem 0.75rem;
font-size: 0.85rem;
}
.modal-content {
max-width: 600px;
}
.vm-assignments {
background: #f8f9fa;
padding: 1rem;
border-radius: 5px;
margin-top: 1rem;
}
.vm-assignment-item {
background: white;
padding: 0.75rem;
border-radius: 5px;
margin-bottom: 0.5rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.badge {
padding: 0.25rem 0.5rem;
border-radius: 3px;
font-size: 0.85rem;
font-weight: 500;
}
.badge-active {
background: #d3f9d8;
color: #2b8a3e;
}
.badge-inactive {
background: #ffe3e3;
color: #c92a2a;
}
</style>
{% endblock %}
{% block content %}
<div class="card">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<h1 class="card-title">Gestione Utenti</h1>
<p style="color: #868e96;">Amministra utenti e assegnazioni VM</p>
</div>
<button class="btn btn-primary" onclick="showCreateUserModal()"> Nuovo Utente</button>
</div>
</div>
<div class="card">
<div id="usersTableContainer">
<div class="loading">
<div class="spinner"></div>
<p>Caricamento utenti...</p>
</div>
</div>
</div>
<!-- Modal Crea Utente -->
<div id="createUserModal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeModal('createUserModal')">&times;</span>
<h2>Crea Nuovo Utente</h2>
<form id="createUserForm" onsubmit="createUser(event)">
<div class="form-group">
<label for="newUsername">Username *</label>
<input type="text" id="newUsername" required>
</div>
<div class="form-group">
<label for="newEmail">Email *</label>
<input type="email" id="newEmail" required>
</div>
<div class="form-group">
<label for="newPassword">Password *</label>
<input type="password" id="newPassword" required>
</div>
<div class="form-group">
<label style="display: flex; align-items: center; gap: 0.5rem;">
<input type="checkbox" id="newIsAdmin" style="width: auto;">
Amministratore
</label>
</div>
<div style="display: flex; gap: 1rem; justify-content: flex-end;">
<button type="button" class="btn btn-secondary" onclick="closeModal('createUserModal')">Annulla</button>
<button type="submit" class="btn btn-primary">Crea Utente</button>
</div>
</form>
</div>
</div>
<!-- Modal Gestisci VM -->
<div id="manageVMsModal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeModal('manageVMsModal')">&times;</span>
<h2 id="manageVMsTitle">Gestisci VM</h2>
<div class="vm-assignments" id="currentVMsList">
<div class="loading">
<div class="spinner"></div>
<p>Caricamento VM...</p>
</div>
</div>
<h3 style="margin-top: 1.5rem;">Aggiungi Nuova VM</h3>
<form id="assignVMForm" onsubmit="assignVM(event)">
<input type="hidden" id="assignUserId">
<div class="form-group">
<label for="vmId">VM ID *</label>
<input type="number" id="vmId" required placeholder="es. 114">
</div>
<div class="form-group">
<label for="vmName">Nome VM</label>
<input type="text" id="vmName" placeholder="es. buslino-vm">
</div>
<div class="form-group">
<label for="vmNotes">Note</label>
<textarea id="vmNotes" rows="3" placeholder="Note opzionali sulla VM"></textarea>
</div>
<div style="display: flex; gap: 1rem; justify-content: flex-end;">
<button type="button" class="btn btn-secondary" onclick="closeModal('manageVMsModal')">Chiudi</button>
<button type="submit" class="btn btn-primary">Assegna VM</button>
</div>
</form>
</div>
</div>
<!-- Modal Imposta IP -->
<div id="setIPModal" class="modal">
<div class="modal-content" style="max-width: 500px;">
<span class="close" onclick="closeModal('setIPModal')">&times;</span>
<h2>Imposta Indirizzo IP</h2>
<p id="setIPVmName" style="color: var(--text-secondary); margin-bottom: 1rem;"></p>
<form id="setIPForm" onsubmit="updateVMIP(event)">
<input type="hidden" id="setIPVmId">
<div class="form-group">
<label for="vmIpAddress">Indirizzo IP</label>
<input type="text"
id="vmIpAddress"
placeholder="es. 192.168.1.100"
pattern="^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$">
<small style="color: var(--text-secondary); font-size: 0.85rem;">
Lascia vuoto per rimuovere l'IP
</small>
</div>
<div style="display: flex; gap: 1rem; justify-content: flex-end; margin-top: 1.5rem;">
<button type="button" class="btn btn-secondary" onclick="closeModal('setIPModal')">Annulla</button>
<button type="submit" class="btn btn-primary">Salva IP</button>
</div>
</form>
</div>
</div>
{% endblock %}
{% block extra_scripts %}
<script>
let currentUsers = [];
document.addEventListener('DOMContentLoaded', function() {
loadUsers();
});
async function loadUsers() {
const container = document.getElementById('usersTableContainer');
const result = await apiCall('/api/admin/users');
if (result.status === 'success') {
currentUsers = result.data;
container.innerHTML = `
<div class="users-table-container">
<table>
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Email</th>
<th>Ruolo</th>
<th>Ultimo Login</th>
<th>Stato</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
${currentUsers.map(user => `
<tr>
<td>${user.id}</td>
<td><strong>${user.username}</strong></td>
<td>${user.email}</td>
<td>
${user.is_admin ?
'<span class="badge-admin">ADMIN</span>' :
'<span>Utente</span>'}
</td>
<td>${user.last_login ? new Date(user.last_login).toLocaleString('it-IT') : 'Mai'}</td>
<td>
<span class="badge ${user.active ? 'badge-active' : 'badge-inactive'}">
${user.active ? 'Attivo' : 'Disattivo'}
</span>
</td>
<td>
<div class="action-buttons">
<button class="btn btn-primary" onclick="manageUserVMs(${user.id}, '${user.username}')">
🖥️ VM
</button>
${user.active ? `
<button class="btn btn-warning" onclick="toggleUserStatus(${user.id}, false, '${user.username}')">
🚫 Disattiva
</button>
` : `
<button class="btn btn-success" onclick="toggleUserStatus(${user.id}, true, '${user.username}')">
✅ Attiva
</button>
`}
</div>
</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
`;
} else {
container.innerHTML = `<div class="alert alert-error">${result.message}</div>`;
}
}
function showCreateUserModal() {
document.getElementById('createUserModal').style.display = 'block';
}
function closeModal(modalId) {
document.getElementById(modalId).style.display = 'none';
}
async function createUser(event) {
event.preventDefault();
const data = {
username: document.getElementById('newUsername').value,
email: document.getElementById('newEmail').value,
password: document.getElementById('newPassword').value,
is_admin: document.getElementById('newIsAdmin').checked
};
const result = await apiCall('/api/admin/user/create', 'POST', data);
if (result.status === 'success') {
showAlert('Utente creato con successo!', 'success');
closeModal('createUserModal');
document.getElementById('createUserForm').reset();
loadUsers();
} else {
showAlert('Errore: ' + result.message, 'error');
}
}
async function manageUserVMs(userId, username) {
document.getElementById('manageVMsTitle').textContent = `Gestisci VM - ${username}`;
document.getElementById('assignUserId').value = userId;
document.getElementById('manageVMsModal').style.display = 'block';
const vmsList = document.getElementById('currentVMsList');
vmsList.innerHTML = '<div class="loading"><div class="spinner"></div><p>Caricamento...</p></div>';
const result = await apiCall(`/api/admin/user/${userId}/vms`);
if (result.status === 'success') {
if (result.data.length === 0) {
vmsList.innerHTML = '<p style="text-align: center; color: #868e96;">Nessuna VM assegnata</p>';
} else {
vmsList.innerHTML = `
<h3>VM Assegnate</h3>
${result.data.map(vm => `
<div class="vm-assignment-item">
<div style="flex: 1;">
<strong>VM ${vm.vm_id}</strong> - ${vm.vm_name || 'N/A'}
${vm.notes ? `<br><small style="color: #868e96;">${vm.notes}</small>` : ''}
${vm.ip_address ? `<br><code style="font-size: 0.8rem; color: #58a6ff;">${vm.ip_address}</code>` : '<br><small style="color: #868e96;">Nessun IP impostato</small>'}
</div>
<div style="display: flex; gap: 8px;">
<button class="btn btn-secondary btn-sm" onclick="showSetIPModal(${vm.vm_id}, '${vm.vm_name || 'VM ' + vm.vm_id}', '${vm.ip_address || ''}')">
🌐 IP
</button>
<button class="btn btn-danger btn-sm" onclick="removeVM(${userId}, ${vm.vm_id}, '${username}')">
🗑️
</button>
</div>
</div>
`).join('')}
`;
}
} else {
vmsList.innerHTML = `<div class="alert alert-error">${result.message}</div>`;
}
}
async function assignVM(event) {
event.preventDefault();
const userId = document.getElementById('assignUserId').value;
const data = {
vm_id: parseInt(document.getElementById('vmId').value),
vm_name: document.getElementById('vmName').value,
notes: document.getElementById('vmNotes').value
};
const result = await apiCall(`/api/admin/user/${userId}/assign-vm`, 'POST', data);
if (result.status === 'success') {
showAlert('VM assegnata con successo!', 'success');
document.getElementById('assignVMForm').reset();
// Ricarica la lista delle VM
const username = document.getElementById('manageVMsTitle').textContent.split(' - ')[1];
manageUserVMs(userId, username);
} else {
showAlert('Errore: ' + result.message, 'error');
}
}
async function removeVM(userId, vmId, username) {
if (!confirm(`Vuoi rimuovere la VM ${vmId} da ${username}?`)) return;
const result = await apiCall(`/api/admin/user/${userId}/remove-vm/${vmId}`, 'DELETE');
if (result.status === 'success') {
showAlert('VM rimossa con successo!', 'success');
manageUserVMs(userId, username);
} else {
showAlert('Errore: ' + result.message, 'error');
}
}
async function toggleUserStatus(userId, active, username) {
const action = active ? 'attivare' : 'disattivare';
if (!confirm(`Vuoi davvero ${action} l'utente ${username}?`)) return;
const result = await apiCall(`/api/admin/user/${userId}/toggle-status`, 'POST', { active });
if (result.status === 'success') {
showAlert(result.message, 'success');
loadUsers();
} else {
showAlert('Errore: ' + result.message, 'error');
}
}
function showSetIPModal(vmId, vmName, currentIp) {
document.getElementById('setIPVmId').value = vmId;
document.getElementById('setIPVmName').textContent = `VM ${vmId} - ${vmName}`;
document.getElementById('vmIpAddress').value = currentIp || '';
document.getElementById('setIPModal').style.display = 'block';
}
async function updateVMIP(event) {
event.preventDefault();
const vmId = document.getElementById('setIPVmId').value;
const ipAddress = document.getElementById('vmIpAddress').value.trim();
const result = await apiCall(`/api/admin/vm/${vmId}/update-ip`, 'PUT', {
ip_address: ipAddress
});
if (result.status === 'success') {
showAlert('IP aggiornato con successo!', 'success');
closeModal('setIPModal');
// Ricarica la lista VM se il modal è aperto
const manageVMsModal = document.getElementById('manageVMsModal');
if (manageVMsModal.style.display === 'block') {
const userId = document.getElementById('assignUserId').value;
const username = document.getElementById('manageVMsTitle').textContent.split(' - ')[1];
manageUserVMs(userId, username);
}
} else {
showAlert('Errore: ' + result.message, 'error');
}
}
// Chiudi modal cliccando fuori
window.onclick = function(event) {
if (event.target.className === 'modal') {
event.target.style.display = 'none';
}
}
</script>
{% endblock %}