Add user management system with JWT authentication
- Database schema: users, permissions, client_access tables - Auth: JWT tokens with Argon2 password hashing - API: login, user CRUD, permission management - Dashboard: login required, admin Users tab - Auto-creates initial admin user on first run
This commit is contained in:
@@ -348,6 +348,7 @@
|
||||
<button class="tab" data-tab="access">Access</button>
|
||||
<button class="tab" data-tab="build">Build</button>
|
||||
<button class="tab" data-tab="settings">Settings</button>
|
||||
<button class="tab admin-only" data-tab="users" style="display: none;">Users</button>
|
||||
</nav>
|
||||
|
||||
<main class="content">
|
||||
@@ -510,6 +511,21 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Users Tab (Admin Only) -->
|
||||
<div class="tab-panel" id="users-panel">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<h2 class="card-title">User Management</h2>
|
||||
<p class="card-description">Manage user accounts and permissions</p>
|
||||
</div>
|
||||
</div>
|
||||
<p style="color: hsl(var(--muted-foreground));">
|
||||
<a href="/users" style="color: hsl(var(--primary));">Open User Management</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Chat Modal -->
|
||||
@@ -546,19 +562,59 @@
|
||||
});
|
||||
|
||||
// Check auth
|
||||
const token = localStorage.getItem("token");
|
||||
const user = JSON.parse(localStorage.getItem("user") || "null");
|
||||
const token = localStorage.getItem("guruconnect_token");
|
||||
const user = JSON.parse(localStorage.getItem("guruconnect_user") || "null");
|
||||
|
||||
if (!token) {
|
||||
document.getElementById("userInfo").textContent = "Demo Mode";
|
||||
} else if (user) {
|
||||
document.getElementById("userInfo").textContent = user.email || user.name || "Technician";
|
||||
// Verify authentication
|
||||
async function checkAuth() {
|
||||
if (!token) {
|
||||
window.location.href = "/login";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/auth/me", {
|
||||
headers: { "Authorization": `Bearer ${token}` }
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
localStorage.removeItem("guruconnect_token");
|
||||
localStorage.removeItem("guruconnect_user");
|
||||
window.location.href = "/login";
|
||||
return;
|
||||
}
|
||||
|
||||
const userData = await response.json();
|
||||
|
||||
// Update user display
|
||||
document.getElementById("userInfo").textContent = userData.username + " (" + userData.role + ")";
|
||||
|
||||
// Show admin-only elements
|
||||
if (userData.role === "admin") {
|
||||
document.querySelectorAll(".admin-only").forEach(el => {
|
||||
el.style.display = "";
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Auth check failed:", err);
|
||||
// Don't redirect on network error, just show what we have
|
||||
if (user) {
|
||||
document.getElementById("userInfo").textContent = user.username || "User";
|
||||
if (user.role === "admin") {
|
||||
document.querySelectorAll(".admin-only").forEach(el => {
|
||||
el.style.display = "";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkAuth();
|
||||
|
||||
// Logout
|
||||
document.getElementById("logoutBtn").addEventListener("click", () => {
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("user");
|
||||
localStorage.removeItem("guruconnect_token");
|
||||
localStorage.removeItem("guruconnect_user");
|
||||
window.location.href = "/login";
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user