document.addEventListener('DOMContentLoaded', () => {
const tableBody = document.querySelector('#users-table tbody');
const itemsCount = document.getElementById('items-count');
const refreshBtn = document.getElementById('refresh-btn');
const filterInput = document.getElementById('table-filter');
// Кнопки управления
const btnCreate = document.getElementById('btn-create');
const btnEdit = document.getElementById('btn-edit');
const btnDelete = document.getElementById('btn-delete');
// Элементы модального окна
const userModal = document.getElementById('user-modal');
const userForm = document.getElementById('user-form');
const modalTitle = document.getElementById('modal-title');
const btnModalCancel = document.getElementById('btn-modal-cancel');
let selectedUsername = null;
let selectedUserRow = null;
// Загрузка данных
async function loadUsers() {
try {
const response = await fetch('api/users.php');
if (!response.ok) throw new Error('Ошибка сервера');
const data = await response.json();
renderTable(data);
resetSelection();
} catch (error) {
alert('Не удалось обновить список пользователей');
}
}
function renderTable(users) {
tableBody.innerHTML = '';
users.forEach(user => {
const tr = document.createElement('tr');
tr.dataset.username = user.name;
tr.dataset.desc = user.desc;
const statusClass = user.status === 'Normal' ? 'status-normal' : 'status-deactivated';
tr.innerHTML = `
${escapeHtml(user.name)} |
${escapeHtml(user.email)} |
${escapeHtml(user.desc)} |
${escapeHtml(user.tfa)} |
${escapeHtml(user.status)} |
`;
// Логика выбора строки кликом
tr.addEventListener('click', () => {
if (selectedUserRow) selectedUserRow.classList.remove('selected-user');
if (selectedUsername === user.name) {
resetSelection();
} else {
selectedUsername = user.name;
selectedUserRow = tr;
tr.classList.add('selected-user');
btnEdit.disabled = false;
// Запрещаем удалять root-пользователя напрямую из UI ради безопасности
btnDelete.disabled = (user.name === 'root');
}
});
tableBody.appendChild(tr);
});
itemsCount.textContent = `${users.length} items`;
}
function resetSelection() {
selectedUsername = null;
selectedUserRow = null;
btnEdit.disabled = true;
btnDelete.disabled = true;
}
// Фильтрация таблицы
filterInput.addEventListener('input', (e) => {
const value = e.target.value.toLowerCase();
Array.from(tableBody.querySelectorAll('tr')).forEach(tr => {
const match = tr.textContent.toLowerCase().includes(value);
tr.style.display = match ? '' : 'none';
});
});
// Открытие модального окна создания
btnCreate.addEventListener('click', () => {
userForm.reset();
document.getElementById('form-action').value = 'create';
document.getElementById('username').disabled = false;
document.getElementById('password-group').style.display = 'block';
modalTitle.textContent = 'Create User';
userModal.classList.add('open');
});
// Открытие модального окна редактирования
btnEdit.addEventListener('click', () => {
if (!selectedUsername) return;
userForm.reset();
document.getElementById('form-action').value = 'update';
document.getElementById('old-username').value = selectedUsername;
const usernameInput = document.getElementById('username');
usernameInput.value = selectedUsername;
usernameInput.disabled = true; // Имя пользователя в Linux менять через useradd напрямую нельзя
document.getElementById('description').value = selectedUserRow.dataset.desc || '';
document.getElementById('password-group').style.display = 'block'; // Пароль заполнять по желанию
modalTitle.textContent = 'Edit User';
userModal.classList.add('open');
});
// Обработка кнопки удаления
btnDelete.addEventListener('click', async () => {
if (!selectedUsername) return;
if (confirm(`Вы уверены, что хотите удалить пользователя ${selectedUsername} вместе с домашней директорией?`)) {
await sendAction({ action: 'delete', username: selectedUsername });
}
});
// Закрытие модального окна
btnModalCancel.addEventListener('click', () => userModal.classList.remove('open'));
// Отправка формы (Создание / Изменение)
userForm.addEventListener('submit', async (e) => {
e.preventDefault();
const action = document.getElementById('form-action').value;
const payload = {
action: action,
username: document.getElementById('username').value,
description: document.getElementById('description').value,
password: document.getElementById('password').value,
old_username: document.getElementById('old-username').value
};
await sendAction(payload);
userModal.classList.remove('open');
});
async function sendAction(data) {
try {
const response = await fetch('api/users.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
loadUsers();
} else {
alert('Ошибка: ' + result.error);
}
} catch (error) {
alert('Ошибка сети при отправке запроса');
}
}
function escapeHtml(text) {
if (!text) return '';
return text.toString().replace(/&/g, "&").replace(//g, ">");
}
refreshBtn.addEventListener('click', loadUsers);
loadUsers();
// --- ЛОГИКА ВКЛАДКИ GROUP ---
const tabUser = document.getElementById('tab-user');
const tabGroup = document.getElementById('tab-group');
const tableHeader = document.querySelector('#users-table thead tr');
const groupModal = document.getElementById('group-modal');
const groupForm = document.getElementById('group-form');
const btnGroupCancel = document.getElementById('btn-group-cancel');
let currentTab = 'user'; // Храним активную вкладку ('user' или 'group')
let selectedGroupName = null;
// Переключение на вкладку User
tabUser.addEventListener('click', () => {
tabGroup.classList.remove('active');
tabUser.classList.add('active');
currentTab = 'user';
tableHeader.innerHTML = `
Name ▴ |
Email |
Description |
2FA Status |
Status |
`;
resetSelection();
loadUsers(); // Вызываем старую функцию загрузки пользователей
});
// Переключение на вкладку Group
tabGroup.addEventListener('click', () => {
tabUser.classList.remove('active');
tabGroup.classList.add('active');
currentTab = 'group';
tableHeader.innerHTML = `
Group Name ▴ |
GID |
Members (Users) |
Status |
`;
resetSelection();
loadGroups();
});
// Загрузка групп с бэкенда
async function loadGroups() {
try {
const response = await fetch('api/groups.php');
const groups = await response.json();
renderGroupsTable(groups);
} catch (error) {
alert('Ошибка загрузки групп');
}
}
function renderGroupsTable(groups) {
tableBody.innerHTML = '';
groups.forEach(group => {
const tr = document.createElement('tr');
tr.innerHTML = `
${escapeHtml(group.name)} |
${group.gid} |
${escapeHtml(group.users)} |
${group.status} |
`;
tr.addEventListener('click', () => {
if (selectedUserRow) selectedUserRow.classList.remove('selected-user');
if (selectedGroupName === group.name) {
selectedGroupName = null;
selectedUserRow = null;
btnDelete.disabled = true;
} else {
selectedGroupName = group.name;
selectedUserRow = tr;
tr.classList.add('selected-user');
btnEdit.disabled = true; // Для групп редактирование отключим
btnDelete.disabled = (group.name === 'root' || group.name === 'wheel');
}
});
tableBody.appendChild(tr);
});
itemsCount.textContent = `${groups.length} items`;
}
// Модифицируем общие кнопки под контекст активной вкладки
btnCreate.addEventListener('click', (e) => {
if (currentTab === 'group') {
e.stopPropagation(); // Останавливаем открытие модалки пользователей
groupForm.reset();
groupModal.classList.add('open');
}
});
btnDelete.addEventListener('click', async () => {
if (currentTab === 'group' && selectedGroupName) {
if (confirm(`Удалить группу ${selectedGroupName}?`)) {
await sendGroupAction({ action: 'delete', group_name: selectedGroupName });
}
}
});
btnGroupCancel.addEventListener('click', () => groupModal.classList.remove('open'));
groupForm.addEventListener('submit', async (e) => {
e.preventDefault();
await sendGroupAction({
action: 'create',
group_name: document.getElementById('group-name').value
});
groupModal.classList.remove('open');
});
async function sendGroupAction(data) {
try {
const response = await fetch('api/groups.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
loadGroups();
} else {
alert('Ошибка: ' + result.error);
}
} catch (error) {
alert('Ошибка сети при обработке группы');
}
}
// Модифицируем круглую кнопку обновления (↻)
refreshBtn.addEventListener('click', () => {
if (currentTab === 'group') loadGroups();
});
});