sso
This commit is contained in:
257
frontend/static/js/app.js
Normal file
257
frontend/static/js/app.js
Normal file
@@ -0,0 +1,257 @@
|
||||
const API_URL = ""; // Relative path since served by same origin
|
||||
|
||||
// State
|
||||
let token = localStorage.getItem("token");
|
||||
let currentUser = null;
|
||||
|
||||
// DOM Elements
|
||||
const loginPage = document.getElementById("login-page");
|
||||
const dashboardLayout = document.getElementById("dashboard-layout");
|
||||
const loginForm = document.getElementById("login-form");
|
||||
const loginError = document.getElementById("login-error");
|
||||
const logoutBtn = document.getElementById("logout-btn");
|
||||
const usersSection = document.getElementById("users-section");
|
||||
const appsSection = document.getElementById("apps-section");
|
||||
const usersTableBody = document.querySelector("#users-table tbody");
|
||||
const appsTableBody = document.querySelector("#apps-table tbody");
|
||||
|
||||
// Init
|
||||
function init() {
|
||||
if (token) {
|
||||
showDashboard();
|
||||
} else {
|
||||
showLogin();
|
||||
}
|
||||
}
|
||||
|
||||
// Navigation
|
||||
function showLogin() {
|
||||
loginPage.classList.remove("hidden");
|
||||
dashboardLayout.classList.add("hidden");
|
||||
}
|
||||
|
||||
function showDashboard() {
|
||||
loginPage.classList.add("hidden");
|
||||
dashboardLayout.classList.remove("hidden");
|
||||
loadUsers();
|
||||
}
|
||||
|
||||
function showSection(section) {
|
||||
if (section === 'users') {
|
||||
usersSection.classList.remove("hidden");
|
||||
appsSection.classList.add("hidden");
|
||||
loadUsers();
|
||||
} else {
|
||||
usersSection.classList.add("hidden");
|
||||
appsSection.classList.remove("hidden");
|
||||
loadApps();
|
||||
}
|
||||
}
|
||||
|
||||
// Auth
|
||||
loginForm.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const username = document.getElementById("username").value;
|
||||
const password = document.getElementById("password").value;
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append("username", username);
|
||||
formData.append("password", password);
|
||||
|
||||
const res = await fetch(`${API_URL}/token`, {
|
||||
method: "POST",
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error("Invalid credentials");
|
||||
|
||||
const data = await res.json();
|
||||
token = data.access_token;
|
||||
localStorage.setItem("token", token);
|
||||
loginError.classList.add("hidden");
|
||||
showDashboard();
|
||||
} catch (err) {
|
||||
loginError.textContent = err.message;
|
||||
loginError.classList.remove("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
logoutBtn.addEventListener("click", () => {
|
||||
token = null;
|
||||
localStorage.removeItem("token");
|
||||
showLogin();
|
||||
});
|
||||
|
||||
// API Helpers
|
||||
async function authFetch(url, options = {}) {
|
||||
const headers = {
|
||||
...options.headers,
|
||||
"Authorization": `Bearer ${token}`
|
||||
};
|
||||
|
||||
const res = await fetch(url, { ...options, headers });
|
||||
if (res.status === 401) {
|
||||
logoutBtn.click();
|
||||
throw new Error("Unauthorized");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Users
|
||||
async function loadUsers() {
|
||||
const res = await authFetch(`${API_URL}/users/`);
|
||||
const users = await res.json();
|
||||
usersTableBody.innerHTML = users.map(user => `
|
||||
<tr>
|
||||
<td>${user.id}</td>
|
||||
<td>${user.username}</td>
|
||||
<td>${user.email}</td>
|
||||
<td>${user.is_admin ? "Yes" : "No"}</td>
|
||||
<td>${user.is_active ? "Yes" : "No"}</td>
|
||||
<td>
|
||||
<button class="btn btn-secondary" onclick='editUser(${JSON.stringify(user)})'>Edit</button>
|
||||
<button class="btn btn-primary" onclick='assignAppModal(${user.id})'>Assign App</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join("");
|
||||
}
|
||||
|
||||
// Apps
|
||||
async function loadApps() {
|
||||
const res = await authFetch(`${API_URL}/apps/`);
|
||||
const apps = await res.json();
|
||||
appsTableBody.innerHTML = apps.map(app => `
|
||||
<tr>
|
||||
<td>${app.id}</td>
|
||||
<td>${app.name}</td>
|
||||
<td>${app.url}</td>
|
||||
<td><code>${app.api_key}</code></td>
|
||||
</tr>
|
||||
`).join("");
|
||||
}
|
||||
|
||||
// Modals
|
||||
function openModal(id) {
|
||||
document.getElementById(id).classList.remove("hidden");
|
||||
}
|
||||
|
||||
function closeModal(id) {
|
||||
document.getElementById(id).classList.add("hidden");
|
||||
}
|
||||
|
||||
// User Form
|
||||
const userForm = document.getElementById("user-form");
|
||||
userForm.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const id = document.getElementById("user-id").value;
|
||||
const username = document.getElementById("user-username").value;
|
||||
const email = document.getElementById("user-email").value;
|
||||
const password = document.getElementById("user-password").value;
|
||||
const isAdmin = document.getElementById("user-is-admin").checked;
|
||||
const isActive = document.getElementById("user-is-active").checked;
|
||||
|
||||
const data = { username, email, is_admin: isAdmin, is_active: isActive };
|
||||
if (password) data.password = password;
|
||||
|
||||
try {
|
||||
let res;
|
||||
if (id) {
|
||||
res = await authFetch(`${API_URL}/users/${id}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
} else {
|
||||
if (!password) return alert("Password required for new user");
|
||||
res = await authFetch(`${API_URL}/users/`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
const err = await res.json();
|
||||
throw new Error(err.detail);
|
||||
}
|
||||
|
||||
closeModal("user-modal");
|
||||
loadUsers();
|
||||
} catch (err) {
|
||||
alert(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
window.editUser = (user) => {
|
||||
document.getElementById("user-id").value = user.id;
|
||||
document.getElementById("user-username").value = user.username;
|
||||
document.getElementById("user-email").value = user.email;
|
||||
document.getElementById("user-password").value = "";
|
||||
document.getElementById("user-is-admin").checked = user.is_admin;
|
||||
document.getElementById("user-is-active").checked = user.is_active;
|
||||
openModal("user-modal");
|
||||
};
|
||||
|
||||
// App Form
|
||||
const appForm = document.getElementById("app-form");
|
||||
appForm.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const name = document.getElementById("app-name").value;
|
||||
const url = document.getElementById("app-url").value;
|
||||
|
||||
try {
|
||||
const res = await authFetch(`${API_URL}/apps/`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ name, url })
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const err = await res.json();
|
||||
throw new Error(err.detail);
|
||||
}
|
||||
|
||||
closeModal("app-modal");
|
||||
loadApps();
|
||||
} catch (err) {
|
||||
alert(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
// Assign App
|
||||
window.assignAppModal = async (userId) => {
|
||||
document.getElementById("assign-user-id").value = userId;
|
||||
|
||||
// Load apps for select
|
||||
const res = await authFetch(`${API_URL}/apps/`);
|
||||
const apps = await res.json();
|
||||
const select = document.getElementById("assign-app-select");
|
||||
select.innerHTML = '<option value="">Select Application</option>' +
|
||||
apps.map(app => `<option value="${app.id}">${app.name}</option>`).join("");
|
||||
|
||||
openModal("assign-modal");
|
||||
};
|
||||
|
||||
const assignForm = document.getElementById("assign-form");
|
||||
assignForm.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const userId = document.getElementById("assign-user-id").value;
|
||||
const appId = document.getElementById("assign-app-select").value;
|
||||
|
||||
try {
|
||||
const res = await authFetch(`${API_URL}/users/${userId}/assign/${appId}`, {
|
||||
method: "POST"
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error("Failed to assign");
|
||||
|
||||
closeModal("assign-modal");
|
||||
alert("Assigned successfully");
|
||||
} catch (err) {
|
||||
alert(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
// Start
|
||||
init();
|
||||
Reference in New Issue
Block a user