118 lines
3.1 KiB
JavaScript
118 lines
3.1 KiB
JavaScript
const $ = (id) => document.getElementById(id);
|
|
|
|
function log(msg) {
|
|
const el = $('log');
|
|
el.textContent = `[${new Date().toISOString()}] ${msg}\n` + el.textContent;
|
|
}
|
|
|
|
function getAuthHeader() {
|
|
const email = $('email').value.trim();
|
|
const pass = $('password').value;
|
|
const token = btoa(`${email}:${pass}`);
|
|
return `Basic ${token}`;
|
|
}
|
|
|
|
function apiBase() {
|
|
const base = $('apiBase').value.trim();
|
|
return base ? base.replace(/\/$/, '') : '';
|
|
}
|
|
|
|
async function apiFetch(path, options = {}) {
|
|
const url = apiBase() + path;
|
|
const headers = options.headers || {};
|
|
headers['Authorization'] = getAuthHeader();
|
|
headers['Content-Type'] = 'application/json';
|
|
const res = await fetch(url, { ...options, headers });
|
|
if (!res.ok) {
|
|
const text = await res.text();
|
|
throw new Error(`${res.status} ${res.statusText}: ${text}`);
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
async function loadUsers() {
|
|
const data = await apiFetch('/api/admin/users');
|
|
const list = data.data || [];
|
|
const tbody = $('userList');
|
|
tbody.innerHTML = '';
|
|
list.forEach((u) => {
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `
|
|
<td>${u.email}</td>
|
|
<td>${u.is_admin ? 'yes' : 'no'}</td>
|
|
<td>${u.created_at}</td>
|
|
<td><button data-id="${u.id}">Delete</button></td>
|
|
`;
|
|
tr.querySelector('button').addEventListener('click', () => deleteUser(u.id));
|
|
tbody.appendChild(tr);
|
|
});
|
|
log('Loaded users');
|
|
}
|
|
|
|
async function createUser() {
|
|
const email = $('newEmail').value.trim();
|
|
const password = $('newPassword').value;
|
|
const isAdmin = $('newIsAdmin').checked;
|
|
if (!email || !password) {
|
|
log('Email and password required');
|
|
return;
|
|
}
|
|
await apiFetch('/api/admin/users', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ email, password, isAdmin })
|
|
});
|
|
$('newEmail').value = '';
|
|
$('newPassword').value = '';
|
|
$('newIsAdmin').checked = false;
|
|
log('User created');
|
|
await loadUsers();
|
|
}
|
|
|
|
async function deleteUser(id) {
|
|
if (!confirm('Delete this user?')) return;
|
|
await apiFetch(`/api/admin/users/${id}`, { method: 'DELETE' });
|
|
log('User deleted');
|
|
await loadUsers();
|
|
}
|
|
|
|
function saveSettings() {
|
|
localStorage.setItem('cfdav_api_base', $('apiBase').value.trim());
|
|
localStorage.setItem('cfdav_email', $('email').value.trim());
|
|
}
|
|
|
|
function loadSettings() {
|
|
$('apiBase').value = localStorage.getItem('cfdav_api_base') || '';
|
|
$('email').value = localStorage.getItem('cfdav_email') || '';
|
|
}
|
|
|
|
function setLoggedIn(state) {
|
|
$('loginCard').classList.toggle('hidden', state);
|
|
$('app').classList.toggle('hidden', !state);
|
|
}
|
|
|
|
async function login() {
|
|
try {
|
|
saveSettings();
|
|
await loadUsers();
|
|
setLoggedIn(true);
|
|
log('Login success');
|
|
} catch (e) {
|
|
setLoggedIn(false);
|
|
log(`Login failed: ${e.message}`);
|
|
}
|
|
}
|
|
|
|
function logout() {
|
|
$('password').value = '';
|
|
setLoggedIn(false);
|
|
log('Logged out');
|
|
}
|
|
|
|
$('loginBtn').addEventListener('click', login);
|
|
$('refreshBtn').addEventListener('click', () => loadUsers().catch((e) => log(e.message)));
|
|
$('createBtn').addEventListener('click', () => createUser().catch((e) => log(e.message)));
|
|
$('logoutBtn').addEventListener('click', logout);
|
|
|
|
loadSettings();
|
|
setLoggedIn(false);
|