/** * Admin Users Page * Manage users with LDAP-aware editing */ let currentUser = null; let users = []; let managers = []; document.addEventListener('DOMContentLoaded', async () => { currentUser = await api.requireAuth(); if (!currentUser) return; if (currentUser.role !== 'admin') { window.location.href = '/presence'; return; } await loadManagers(); await loadUsers(); setupEventListeners(); }); async function loadManagers() { const response = await api.get('/api/managers'); if (response && response.ok) { managers = await response.json(); } } async function loadUsers() { const response = await api.get('/api/users'); if (response && response.ok) { users = await response.json(); renderUsers(); } } function renderUsers(filter = '') { const tbody = document.getElementById('usersBody'); const filterLower = filter.toLowerCase(); let filtered = users; if (filter) { filtered = users.filter(u => (u.name || '').toLowerCase().includes(filterLower) || (u.email || '').toLowerCase().includes(filterLower) || (u.role || '').toLowerCase().includes(filterLower) || (u.manager_name || '').toLowerCase().includes(filterLower) ); } if (filtered.length === 0) { tbody.innerHTML = 'No users found'; return; } tbody.innerHTML = filtered.map(user => { const ldapBadge = user.is_ldap_user ? 'LDAP' : ''; const managerInfo = user.role === 'manager' ? `${user.managed_user_count || 0} users` : (user.manager_name || '-'); return ` ${user.name || '-'} ${ldapBadge} ${user.email} ${user.role} ${managerInfo} `; }).join(''); } function getRoleBadgeClass(role) { switch (role) { case 'admin': return 'danger'; case 'manager': return 'warning'; default: return 'secondary'; } } async function editUser(userId) { const user = users.find(u => u.id === userId); if (!user) return; // Populate form document.getElementById('userId').value = user.id; document.getElementById('editName').value = user.name || ''; document.getElementById('editEmail').value = user.email; document.getElementById('editRole').value = user.role; document.getElementById('editQuota').value = user.manager_parking_quota || 0; document.getElementById('editPrefix').value = user.manager_spot_prefix || ''; // Populate manager dropdown const managerSelect = document.getElementById('editManager'); managerSelect.innerHTML = ''; managers.forEach(m => { if (m.id !== userId) { // Can't be own manager const option = document.createElement('option'); option.value = m.id; option.textContent = m.name; if (m.id === user.manager_id) option.selected = true; managerSelect.appendChild(option); } }); // Handle LDAP restrictions const isLdap = user.is_ldap_user; const isLdapAdmin = user.is_ldap_admin; // LDAP notice document.getElementById('ldapNotice').style.display = isLdap ? 'block' : 'none'; // Name field - disabled for LDAP users const nameInput = document.getElementById('editName'); nameInput.disabled = isLdap; document.getElementById('nameHelp').style.display = isLdap ? 'block' : 'none'; // Role field - admin option disabled for LDAP admins (they can't be demoted) const roleSelect = document.getElementById('editRole'); roleSelect.disabled = isLdapAdmin; document.getElementById('roleHelp').style.display = isLdapAdmin ? 'block' : 'none'; // Manager group - show for all users (admins can also be assigned to a manager) document.getElementById('managerGroup').style.display = 'block'; // Manager fields - show only for managers document.getElementById('managerFields').style.display = user.role === 'manager' ? 'block' : 'none'; document.getElementById('userModalTitle').textContent = 'Edit User'; document.getElementById('userModal').style.display = 'flex'; } async function deleteUser(userId) { const user = users.find(u => u.id === userId); if (!user) return; if (!confirm(`Delete user "${user.name || user.email}"?`)) return; const response = await api.delete(`/api/users/${userId}`); if (response && response.ok) { utils.showMessage('User deleted', 'success'); await loadUsers(); } else { const error = await response.json(); utils.showMessage(error.detail || 'Failed to delete user', 'error'); } } function setupEventListeners() { // Search document.getElementById('searchInput').addEventListener('input', (e) => { renderUsers(e.target.value); }); // Role change - toggle manager fields (manager group always visible since any user can have a manager) document.getElementById('editRole').addEventListener('change', (e) => { const role = e.target.value; document.getElementById('managerFields').style.display = role === 'manager' ? 'block' : 'none'; // Manager group stays visible - any user (including admins) can have a manager assigned }); // Modal close document.getElementById('closeUserModal').addEventListener('click', () => { document.getElementById('userModal').style.display = 'none'; }); document.getElementById('cancelUser').addEventListener('click', () => { document.getElementById('userModal').style.display = 'none'; }); utils.setupModalClose('userModal'); // Form submit document.getElementById('userForm').addEventListener('submit', async (e) => { e.preventDefault(); const userId = document.getElementById('userId').value; const role = document.getElementById('editRole').value; const data = { role: role, manager_id: document.getElementById('editManager').value || null }; // Only include name if not disabled (LDAP users can't change name) const nameInput = document.getElementById('editName'); if (!nameInput.disabled) { data.name = nameInput.value; } // Manager-specific fields if (role === 'manager') { data.manager_parking_quota = parseInt(document.getElementById('editQuota').value) || 0; data.manager_spot_prefix = document.getElementById('editPrefix').value || null; } const response = await api.put(`/api/users/${userId}`, data); if (response && response.ok) { document.getElementById('userModal').style.display = 'none'; utils.showMessage('User updated', 'success'); await loadManagers(); // Reload in case role changed await loadUsers(); } else { const error = await response.json(); utils.showMessage(error.detail || 'Failed to update user', 'error'); } }); } // Make functions available globally for onclick handlers window.editUser = editUser; window.deleteUser = deleteUser;