308 lines
12 KiB
JavaScript
308 lines
12 KiB
JavaScript
function showAuthModal() {
|
|
const el = document.getElementById("auth-modal");
|
|
if (el) el.classList.remove("hidden");
|
|
}
|
|
|
|
function hideAuthModal() {
|
|
const el = document.getElementById("auth-modal");
|
|
if (el) el.classList.add("hidden");
|
|
}
|
|
|
|
async function handleLogin(e) {
|
|
if (e && e.preventDefault) e.preventDefault();
|
|
|
|
const usernameInput = document.getElementById("auth-username-input");
|
|
const passwordInput = document.getElementById("auth-password-input");
|
|
const errorEl = document.getElementById("auth-error");
|
|
|
|
if (!usernameInput || !passwordInput) return;
|
|
|
|
const username = usernameInput.value.trim();
|
|
const password = passwordInput.value;
|
|
|
|
if (!username || !password) return;
|
|
|
|
if (errorEl) errorEl.classList.add("hidden");
|
|
|
|
try {
|
|
const res = await fetch("/api/v1/auth/login", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ username, password })
|
|
});
|
|
|
|
const data = await res.json();
|
|
|
|
if (res.status === 200) {
|
|
// Используем прямой строковый ключ, чтобы избежать ошибки ReferenceError
|
|
API_TOKEN = data.token;
|
|
CURRENT_USERNAME = data.username;
|
|
IS_ADMIN = data.is_admin;
|
|
IS_GUEST = false;
|
|
|
|
localStorage.setItem("scud_api_auth_token", data.token);
|
|
localStorage.setItem("scud_username", data.username);
|
|
localStorage.setItem("scud_is_admin", data.is_admin ? "true" : "false");
|
|
localStorage.removeItem("scud_is_guest");
|
|
|
|
hideAuthModal();
|
|
updateUIState();
|
|
|
|
if (typeof loadTasks === 'function') {
|
|
loadTasks();
|
|
}
|
|
} else {
|
|
if (errorEl) {
|
|
errorEl.innerText = data.detail || "Ошибка авторизации";
|
|
errorEl.classList.remove("hidden");
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error("[Auth Error]", err);
|
|
if (errorEl) {
|
|
errorEl.innerText = "Ошибка соединения с сервером";
|
|
errorEl.classList.remove("hidden");
|
|
}
|
|
}
|
|
}
|
|
|
|
function enableGuestMode() {
|
|
IS_GUEST = true;
|
|
API_TOKEN = "";
|
|
CURRENT_USERNAME = "Гость";
|
|
IS_ADMIN = false;
|
|
localStorage.setItem("scud_is_guest", "true");
|
|
hideAuthModal();
|
|
updateUIState();
|
|
}
|
|
|
|
function logout() {
|
|
localStorage.removeItem("scud_api_auth_token");
|
|
localStorage.removeItem("scud_username");
|
|
localStorage.removeItem("scud_is_admin");
|
|
localStorage.removeItem("scud_is_guest");
|
|
API_TOKEN = "";
|
|
CURRENT_USERNAME = "";
|
|
IS_ADMIN = false;
|
|
IS_GUEST = false;
|
|
showAuthModal();
|
|
}
|
|
|
|
function updateUIState() {
|
|
const tasksBtn = document.getElementById("tasks-drawer-btn");
|
|
const adminBtn = document.getElementById("admin-users-btn");
|
|
const changePwdBtn = document.getElementById("change-pwd-btn");
|
|
const guestBadge = document.getElementById("guest-badge");
|
|
const usernameBadge = document.getElementById("username-badge");
|
|
|
|
if (typeof IS_GUEST !== 'undefined' && IS_GUEST) {
|
|
if (tasksBtn) tasksBtn.classList.add("hidden");
|
|
if (adminBtn) adminBtn.classList.add("hidden");
|
|
if (changePwdBtn) changePwdBtn.classList.add("hidden");
|
|
if (guestBadge) guestBadge.classList.remove("hidden");
|
|
if (usernameBadge) usernameBadge.classList.add("hidden");
|
|
} else {
|
|
if (tasksBtn) tasksBtn.classList.remove("hidden");
|
|
if (changePwdBtn) changePwdBtn.classList.remove("hidden");
|
|
if (guestBadge) guestBadge.classList.add("hidden");
|
|
|
|
if (usernameBadge) {
|
|
usernameBadge.innerText = (typeof CURRENT_USERNAME !== 'undefined' && CURRENT_USERNAME) ? CURRENT_USERNAME : "User";
|
|
usernameBadge.classList.remove("hidden");
|
|
}
|
|
|
|
if (adminBtn) {
|
|
const isAdminUser = (typeof IS_ADMIN !== 'undefined' && IS_ADMIN) || (typeof CURRENT_USERNAME !== 'undefined' && CURRENT_USERNAME === "puh");
|
|
if (isAdminUser) {
|
|
adminBtn.classList.remove("hidden");
|
|
} else {
|
|
adminBtn.classList.add("hidden");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function openChangePasswordModal() {
|
|
const el = document.getElementById("change-pwd-modal");
|
|
if (el) el.classList.remove("hidden");
|
|
}
|
|
|
|
function closeChangePasswordModal() {
|
|
const el = document.getElementById("change-pwd-modal");
|
|
if (el) el.classList.add("hidden");
|
|
|
|
const err = document.getElementById("pwd-error");
|
|
const succ = document.getElementById("pwd-success");
|
|
if (err) err.classList.add("hidden");
|
|
if (succ) succ.classList.add("hidden");
|
|
|
|
document.getElementById("old-pwd-input").value = "";
|
|
document.getElementById("new-pwd-input").value = "";
|
|
const confirmInput = document.getElementById("confirm-pwd-input");
|
|
if (confirmInput) confirmInput.value = "";
|
|
}
|
|
|
|
async function handleChangePassword(e) {
|
|
if (e && e.preventDefault) e.preventDefault();
|
|
const old_password = document.getElementById("old-pwd-input").value;
|
|
const new_password = document.getElementById("new-pwd-input").value;
|
|
const confirmInput = document.getElementById("confirm-pwd-input");
|
|
const confirm_password = confirmInput ? confirmInput.value : new_password;
|
|
const errorEl = document.getElementById("pwd-error");
|
|
const successEl = document.getElementById("pwd-success");
|
|
|
|
if (errorEl) errorEl.classList.add("hidden");
|
|
if (successEl) successEl.classList.add("hidden");
|
|
|
|
if (new_password !== confirm_password) {
|
|
if (errorEl) {
|
|
errorEl.innerText = "Новые пароли не совпадают";
|
|
errorEl.classList.remove("hidden");
|
|
}
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const token = typeof API_TOKEN !== 'undefined' ? API_TOKEN : localStorage.getItem("scud_api_auth_token");
|
|
const res = await fetch("/api/v1/auth/change-password", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Authorization": "Bearer " + token
|
|
},
|
|
body: JSON.stringify({ old_password, new_password })
|
|
});
|
|
|
|
const data = await res.json();
|
|
|
|
if (res.status === 200) {
|
|
if (successEl) {
|
|
successEl.innerText = "Пароль успешно изменен!";
|
|
successEl.classList.remove("hidden");
|
|
}
|
|
setTimeout(closeChangePasswordModal, 1500);
|
|
} else {
|
|
if (errorEl) {
|
|
errorEl.innerText = data.detail || "Ошибка при смене пароля";
|
|
errorEl.classList.remove("hidden");
|
|
}
|
|
}
|
|
} catch (err) {
|
|
if (errorEl) {
|
|
errorEl.innerText = "Ошибка соединения с сервером";
|
|
errorEl.classList.remove("hidden");
|
|
}
|
|
}
|
|
}
|
|
|
|
function openAdminModal() {
|
|
const el = document.getElementById("admin-modal");
|
|
if (el) el.classList.remove("hidden");
|
|
loadUsersList();
|
|
}
|
|
|
|
function closeAdminModal() {
|
|
const el = document.getElementById("admin-modal");
|
|
if (el) el.classList.add("hidden");
|
|
}
|
|
|
|
async function loadUsersList() {
|
|
const listEl = document.getElementById("admin-users-list");
|
|
if (!listEl) return;
|
|
listEl.innerHTML = '<div class="text-xs text-slate-400 py-4 text-center">Загрузка пользователей...</div>';
|
|
|
|
try {
|
|
const token = typeof API_TOKEN !== 'undefined' ? API_TOKEN : localStorage.getItem("scud_api_auth_token");
|
|
const res = await fetch("/api/v1/admin/users", {
|
|
headers: { "Authorization": "Bearer " + token }
|
|
});
|
|
const users = await res.json();
|
|
|
|
if (res.status === 200) {
|
|
listEl.innerHTML = users.map(u => {
|
|
const adminTag = u.is_admin ? '<span class="ml-1.5 text-[9px] bg-indigo-100 text-indigo-700 px-1.5 py-0.5 rounded font-bold">ADMIN</span>' : '<span class="ml-1.5 text-[9px] bg-slate-100 text-slate-600 px-1.5 py-0.5 rounded">USER</span>';
|
|
const fullNameHtml = u.full_name ? `<div class="text-[11px] text-slate-500 font-normal">${u.full_name}</div>` : '';
|
|
const dateStr = u.created_at ? u.created_at.split(' ')[0] : '—';
|
|
const deleteBtn = u.username !== CURRENT_USERNAME ? `<button type="button" onclick="deleteUser(${u.id}, '${u.username}')" class="text-red-500 hover:text-red-700 p-1"><i class="fa-solid fa-trash-can"></i></button>` : '<span class="text-[10px] text-slate-400">Вы</span>';
|
|
|
|
return `
|
|
<div class="flex justify-between items-center bg-slate-50 border border-slate-200 p-2.5 rounded-xl text-xs">
|
|
<div>
|
|
<div class="flex items-center">
|
|
<span class="font-bold text-slate-800">${u.username}</span>
|
|
${adminTag}
|
|
</div>
|
|
${fullNameHtml}
|
|
<div class="text-[10px] text-slate-400 mt-0.5">Создан: ${dateStr}</div>
|
|
</div>
|
|
${deleteBtn}
|
|
</div>
|
|
`;
|
|
}).join("");
|
|
} else {
|
|
listEl.innerHTML = `<div class="text-xs text-red-500 py-2">${users.detail}</div>`;
|
|
}
|
|
} catch (err) {
|
|
listEl.innerHTML = '<div class="text-xs text-red-500 py-2">Ошибка загрузки пользователей</div>';
|
|
}
|
|
}
|
|
|
|
async function handleCreateUser(e) {
|
|
if (e && e.preventDefault) e.preventDefault();
|
|
const username = document.getElementById("new-user-name").value.trim();
|
|
const password = document.getElementById("new-user-pwd").value;
|
|
const fullNameInput = document.getElementById("new-user-fullname");
|
|
const full_name = fullNameInput ? fullNameInput.value.trim() : "";
|
|
const adminCheckbox = document.getElementById("new-user-is-admin");
|
|
const is_admin = adminCheckbox ? adminCheckbox.checked : false;
|
|
const msgEl = document.getElementById("admin-msg");
|
|
|
|
if (msgEl) msgEl.classList.add("hidden");
|
|
|
|
try {
|
|
const token = typeof API_TOKEN !== 'undefined' ? API_TOKEN : localStorage.getItem("scud_api_auth_token");
|
|
const res = await fetch("/api/v1/admin/users", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Authorization": "Bearer " + token
|
|
},
|
|
body: JSON.stringify({ username, password, full_name, is_admin })
|
|
});
|
|
|
|
const data = await res.json();
|
|
|
|
if (res.status === 200) {
|
|
document.getElementById("new-user-name").value = "";
|
|
document.getElementById("new-user-pwd").value = "";
|
|
if (fullNameInput) fullNameInput.value = "";
|
|
if (adminCheckbox) adminCheckbox.checked = false;
|
|
loadUsersList();
|
|
} else {
|
|
if (msgEl) {
|
|
msgEl.innerText = data.detail || "Ошибка";
|
|
msgEl.classList.remove("hidden");
|
|
}
|
|
}
|
|
} catch (err) {
|
|
if (msgEl) {
|
|
msgEl.innerText = "Ошибка связи с сервером";
|
|
msgEl.classList.remove("hidden");
|
|
}
|
|
}
|
|
}
|
|
|
|
async function deleteUser(userId, username) {
|
|
if (!confirm("Удалить пользователя " + username + "?")) return;
|
|
|
|
try {
|
|
const token = typeof API_TOKEN !== 'undefined' ? API_TOKEN : localStorage.getItem("scud_api_auth_token");
|
|
await fetch("/api/v1/admin/users/" + userId, {
|
|
method: "DELETE",
|
|
headers: { "Authorization": "Bearer " + token }
|
|
});
|
|
loadUsersList();
|
|
} catch (err) {
|
|
alert("Ошибка при удалении");
|
|
}
|
|
} |