feat: backend auth, admin panel, role-based routing
This commit is contained in:
146
frontend/admin/admin.js
Normal file
146
frontend/admin/admin.js
Normal file
@@ -0,0 +1,146 @@
|
||||
(() => {
|
||||
'use strict';
|
||||
|
||||
const token = localStorage.getItem('token');
|
||||
const role = localStorage.getItem('role');
|
||||
|
||||
if (!token || role !== 'ADMIN') {
|
||||
window.location.href = '/';
|
||||
return;
|
||||
}
|
||||
|
||||
const tbody = document.getElementById('users-tbody');
|
||||
const createForm = document.getElementById('create-form');
|
||||
const createAlert = document.getElementById('create-alert');
|
||||
const btnLogout = document.getElementById('btn-logout');
|
||||
|
||||
const ROLE_LABELS = {
|
||||
ADMIN: 'Администратор',
|
||||
TEACHER: 'Преподаватель',
|
||||
STUDENT: 'Студент',
|
||||
};
|
||||
|
||||
const ROLE_BADGE = {
|
||||
ADMIN: 'badge-admin',
|
||||
TEACHER: 'badge-teacher',
|
||||
STUDENT: 'badge-student',
|
||||
};
|
||||
|
||||
// ---- Load Users ----
|
||||
async function loadUsers() {
|
||||
try {
|
||||
const res = await fetch('/api/users', {
|
||||
headers: { 'Authorization': 'Bearer ' + token },
|
||||
});
|
||||
const users = await res.json();
|
||||
renderUsers(users);
|
||||
} catch (e) {
|
||||
tbody.innerHTML = '<tr><td colspan="4" class="loading-row">Ошибка загрузки</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderUsers(users) {
|
||||
if (!users.length) {
|
||||
tbody.innerHTML = '<tr><td colspan="4" class="loading-row">Нет пользователей</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
tbody.innerHTML = users.map(u => `
|
||||
<tr>
|
||||
<td>${u.id}</td>
|
||||
<td>${escapeHtml(u.username)}</td>
|
||||
<td><span class="badge ${ROLE_BADGE[u.role] || ''}">${ROLE_LABELS[u.role] || u.role}</span></td>
|
||||
<td><button class="btn-delete" data-id="${u.id}">Удалить</button></td>
|
||||
</tr>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = str;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// ---- Create User ----
|
||||
createForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
hideAlert();
|
||||
|
||||
const username = document.getElementById('new-username').value.trim();
|
||||
const password = document.getElementById('new-password').value;
|
||||
const role = document.getElementById('new-role').value;
|
||||
|
||||
if (!username || !password) {
|
||||
showAlert('Заполните все поля', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/users', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token,
|
||||
},
|
||||
body: JSON.stringify({ username, password, role }),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (res.ok) {
|
||||
showAlert(`Пользователь "${data.username}" создан`, 'success');
|
||||
createForm.reset();
|
||||
loadUsers();
|
||||
} else {
|
||||
showAlert(data.message || 'Ошибка создания', 'error');
|
||||
}
|
||||
} catch (e) {
|
||||
showAlert('Ошибка соединения', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
// ---- Delete User ----
|
||||
tbody.addEventListener('click', async (e) => {
|
||||
const btn = e.target.closest('.btn-delete');
|
||||
if (!btn) return;
|
||||
|
||||
const id = btn.dataset.id;
|
||||
if (!confirm('Удалить пользователя?')) return;
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/users/' + id, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Authorization': 'Bearer ' + token },
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
loadUsers();
|
||||
} else {
|
||||
alert('Ошибка удаления');
|
||||
}
|
||||
} catch (e) {
|
||||
alert('Ошибка соединения');
|
||||
}
|
||||
});
|
||||
|
||||
// ---- Logout ----
|
||||
btnLogout.addEventListener('click', () => {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('role');
|
||||
window.location.href = '/';
|
||||
});
|
||||
|
||||
// ---- Helpers ----
|
||||
function showAlert(msg, type) {
|
||||
createAlert.className = 'form-alert ' + type;
|
||||
createAlert.textContent = msg;
|
||||
}
|
||||
|
||||
function hideAlert() {
|
||||
createAlert.className = 'form-alert';
|
||||
createAlert.textContent = '';
|
||||
}
|
||||
|
||||
// Init
|
||||
loadUsers();
|
||||
})();
|
||||
Reference in New Issue
Block a user