mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Basic account management
This commit is contained in:
236
public/scripts/user.js
Normal file
236
public/scripts/user.js
Normal file
@ -0,0 +1,236 @@
|
||||
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<void>}
|
||||
*/
|
||||
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<void>}
|
||||
*/
|
||||
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<void>}
|
||||
*/
|
||||
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<void>}
|
||||
*/
|
||||
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();
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user