import { callPopup, getRequestHeaders, renderTemplate } from '../script.js'; /** * @type {import('../../src/users.js').User} Logged in user */ export let currentUser = null; /** * Enable or disable user account controls in the UI. * @param {boolean} isEnabled User account controls enabled * @returns {Promise} */ export async function setUserControls(isEnabled) { if (!isEnabled) { $('#account_controls').hide(); return; } $('#account_controls').show(); await getCurrentUser(); } /** * Check if the current user is an admin. * @returns {boolean} True if the current user is an admin */ function isAdmin() { if (!currentUser) { return false; } return Boolean(currentUser.admin); } /** * Get the current user. * @returns {Promise} */ async function getCurrentUser() { try { const response = await fetch('/api/users/me', { headers: getRequestHeaders(), }); if (!response.ok) { throw new Error('Failed to get current user'); } currentUser = await response.json(); $('#admin_button').toggle(isAdmin()); } catch (error) { console.error('Error getting current user:', error); } } async function getUsers() { try { const response = await fetch('/api/users/get', { method: 'POST', headers: getRequestHeaders(), }); if (!response.ok) { throw new Error('Failed to get users'); } return response.json(); } catch (error) { console.error('Error getting users:', error); } } /** * Enable a user account. * @param {string} handle User handle * @param {function} callback Success callback * @returns {Promise} */ async function enableUser(handle, callback) { try { const response = await fetch('/api/users/enable', { method: 'POST', headers: getRequestHeaders(), body: JSON.stringify({ handle }), }); if (!response.ok) { const data = await response.json(); toastr.error(data.error || 'Unknown error', 'Failed to enable user'); throw new Error('Failed to enable user'); } callback(); } catch (error) { console.error('Error enabling user:', error); } } async function disableUser(handle, callback) { try { const response = await fetch('/api/users/disable', { method: 'POST', headers: getRequestHeaders(), body: JSON.stringify({ handle }), }); if (!response.ok) { const data = await response.json(); toastr.error(data?.error || 'Unknown error', 'Failed to disable user'); throw new Error('Failed to disable user'); } callback(); } catch (error) { console.error('Error disabling user:', error); } } /** * Create a new user. * @param {HTMLFormElement} form Form element */ async function createUser(form, callback) { const errors = []; const formData = new FormData(form); if (!formData.get('handle')) { errors.push('Handle is required'); } if (formData.get('password') !== formData.get('confirm')) { errors.push('Passwords do not match'); } if (errors.length) { toastr.error(errors.join(', '), 'Failed to create user'); return; } const body = {}; formData.forEach(function (value, key) { if (key === 'confirm') { return; } if (key.startsWith('_')) { key = key.substring(1); } body[key] = value; }); try { const response = await fetch('/api/users/create', { method: 'POST', headers: getRequestHeaders(), body: JSON.stringify(body), }); if (!response.ok) { const data = await response.json(); toastr.error(data.error || 'Unknown error', 'Failed to create user'); throw new Error('Failed to create user'); } form.reset(); callback(); } catch (error) { console.error('Error creating user:', error); } } async function openAdminPanel() { async function renderUsers() { const users = await getUsers(); template.find('.usersList').empty(); for (const user of users) { const userBlock = template.find('.userAccountTemplate .userAccount').clone(); userBlock.find('.userName').text(user.name); userBlock.find('.userHandle').text(user.handle); userBlock.find('.userStatus').text(user.enabled ? 'Enabled' : 'Disabled'); userBlock.find('.userRole').text(user.admin ? 'Admin' : 'User'); userBlock.find('.avatar img').attr('src', user.avatar); userBlock.find('.hasPassword').toggle(user.password); userBlock.find('.noPassword').toggle(!user.password); userBlock.find('.userCreated').text(new Date(user.created).toLocaleString()); userBlock.find('.userEnableButton').toggle(!user.enabled).on('click', () => enableUser(user.handle, renderUsers)); userBlock.find('.userDisableButton').toggle(user.enabled).on('click', () => disableUser(user.handle, renderUsers)); template.find('.usersList').append(userBlock); } } const template = $(renderTemplate('admin')); template.find('.adminNav > button').on('click', function () { const target = String($(this).data('target-tab')); template.find('.navTab').each(function () { $(this).toggle(this.classList.contains(target)); }); }); template.find('.userCreateForm').on('submit', function (event) { if (!(event.target instanceof HTMLFormElement)) { return; } event.preventDefault(); createUser(event.target, () => { template.find('.manageUsersButton').trigger('click'); renderUsers(); }); }); callPopup(template, 'text', '', { okButton: 'Close', wide: true, large: true, allowVerticalScrolling: true, allowHorizontalScrolling: false }); renderUsers(); } /** * Log out the current user. * @returns {Promise} */ async function logout() { await fetch('/api/users/logout', { method: 'POST', headers: getRequestHeaders(), }); window.location.reload(); } jQuery(() => { $('#logout_button').on('click', () => { logout(); }); $('#admin_button').on('click', () => { openAdminPanel(); }); });