475765e31f
Add an explicit template renderer with HTML views and partials for the app, bootstrap, package, and catalog pages. Move shared reporting setup into config/reporting.php and relocate stylesheet assets under css/.
230 lines
8.0 KiB
PHP
230 lines
8.0 KiB
PHP
<?php
|
|
/*
|
|
* users.php
|
|
*
|
|
* Admin user management.
|
|
*/
|
|
|
|
require_once __DIR__ . '/private/auth.php';
|
|
require_once __DIR__ . '/private/header.php';
|
|
require_once __DIR__ . '/private/languagestore.php';
|
|
require_once __DIR__ . '/private/usersettings.php';
|
|
require_once __DIR__ . '/private/viewdata.php';
|
|
|
|
require_once __DIR__ . '/config/reporting.php';
|
|
|
|
$DB_FILE = __DIR__ . '/data/racket-sandbox.sqlite';
|
|
|
|
$auth = new RacketSandboxAuth($DB_FILE);
|
|
$languageStore = new LanguageStore($DB_FILE);
|
|
$userSettings = new UserSettingsStore($DB_FILE);
|
|
$currentUser = $auth->requireAdminHtml();
|
|
|
|
$message = '';
|
|
$error = '';
|
|
|
|
function h($s)
|
|
{
|
|
return htmlspecialchars((string)$s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
|
}
|
|
|
|
function t($key, $fallback = null, $values = array())
|
|
{
|
|
global $languageStore, $language;
|
|
|
|
return $languageStore->translateFormat($key, $language, $values, $fallback);
|
|
}
|
|
|
|
function post_value($name, $default = '')
|
|
{
|
|
return $_POST[$name] ?? $default;
|
|
}
|
|
|
|
function post_bool($name)
|
|
{
|
|
return isset($_POST[$name]) && $_POST[$name] === '1';
|
|
}
|
|
|
|
function resolve_user_language($userSettings, $userId, $allowedLanguages)
|
|
{
|
|
$language = isset($_GET['lang'])
|
|
? (string)$_GET['lang']
|
|
: (string)$userSettings->get($userId, 'language', 'en');
|
|
|
|
if (!in_array($language, $allowedLanguages, true)) {
|
|
$language = 'en';
|
|
}
|
|
|
|
$userSettings->set($userId, 'language', $language);
|
|
|
|
return $language;
|
|
}
|
|
|
|
function fmt_time($ts)
|
|
{
|
|
if ($ts === null) {
|
|
return '-';
|
|
}
|
|
|
|
return date('Y-m-d H:i:s', (int)$ts);
|
|
}
|
|
|
|
$language = resolve_user_language(
|
|
$userSettings,
|
|
$currentUser->id(),
|
|
$languageStore->supportedLanguages()
|
|
);
|
|
|
|
seed_template_translations($languageStore, 'users.html');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$action = post_value('action');
|
|
|
|
try {
|
|
if ($action === 'logout') {
|
|
$auth->logout();
|
|
header('Location: /login.php');
|
|
exit;
|
|
} elseif ($action === 'create_user') {
|
|
$auth->createUser(
|
|
post_value('email'),
|
|
post_value('full_name'),
|
|
post_value('password'),
|
|
post_bool('is_admin'),
|
|
post_bool('is_enabled')
|
|
);
|
|
$message = t('app.user_created', 'User created.');
|
|
} elseif ($action === 'update_user') {
|
|
$userId = (int)post_value('user_id');
|
|
$isAdmin = post_bool('is_admin');
|
|
$isEnabled = post_bool('is_enabled');
|
|
|
|
if ($userId === $currentUser->id() && !$isAdmin) {
|
|
throw new Exception(t('app.cannot_remove_own_admin', 'You cannot remove your own admin rights.'));
|
|
}
|
|
|
|
if ($userId === $currentUser->id() && !$isEnabled) {
|
|
throw new Exception(t('app.cannot_disable_self', 'You cannot disable your own account.'));
|
|
}
|
|
|
|
$auth->updateUser($userId, post_value('email'), post_value('full_name'));
|
|
$auth->setAdmin($userId, $isAdmin);
|
|
$auth->setEnabled($userId, $isEnabled);
|
|
$message = t('app.user_updated', 'User updated.');
|
|
} elseif ($action === 'set_password') {
|
|
$auth->setPassword(post_value('email'), post_value('password'));
|
|
$message = t('app.password_changed', 'Password changed.');
|
|
} elseif ($action === 'delete_user') {
|
|
$userId = (int)post_value('user_id');
|
|
|
|
if ($userId === $currentUser->id()) {
|
|
throw new Exception(t('app.cannot_delete_self', 'You cannot delete your own account.'));
|
|
}
|
|
|
|
$auth->deleteUser($userId);
|
|
$message = t('app.user_deleted', 'User deleted.');
|
|
}
|
|
} catch (Throwable $e) {
|
|
$error = $e->getMessage();
|
|
}
|
|
}
|
|
|
|
$users = $auth->listUsers();
|
|
$headerLanguages = array();
|
|
|
|
foreach ($languageStore->supportedLanguages() as $lang) {
|
|
$headerLanguages[$lang] = $languageStore->languageLabel($lang);
|
|
}
|
|
|
|
header('Content-Type: text/html; charset=utf-8');
|
|
$userRowsHtml = '';
|
|
|
|
foreach ($users as $managedUser) {
|
|
if ($managedUser->id() !== $currentUser->id()) {
|
|
$deleteHtml = RacketSandboxTemplate::renderFile('partials/user-delete-form.html', array(
|
|
'language_url' => rawurlencode($language),
|
|
'confirm_json' => json_encode(t('app.delete_user_confirm', 'Delete user {{email}}?', array(
|
|
'email' => $managedUser->email(),
|
|
)), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT),
|
|
'email' => $managedUser->email(),
|
|
'user_id' => $managedUser->id(),
|
|
'delete_user_label' => t('app.delete_user', 'Delete user'),
|
|
));
|
|
} else {
|
|
$deleteHtml = RacketSandboxTemplate::renderFile('partials/user-self-note.html', array(
|
|
'cannot_delete_self' => t('app.cannot_delete_self', 'You cannot delete your own account.'),
|
|
));
|
|
}
|
|
|
|
$userRowsHtml .= RacketSandboxTemplate::renderFile('partials/user-row.html', array(
|
|
'language_url' => rawurlencode($language),
|
|
'user_id' => $managedUser->id(),
|
|
'full_name_label' => t('app.full_name', 'Full name'),
|
|
'full_name' => $managedUser->fullName(),
|
|
'email_label' => t('app.email', 'Email'),
|
|
'email' => $managedUser->email(),
|
|
'admin_label' => t('app.admin', 'Admin'),
|
|
'enabled_label' => t('app.enabled', 'Enabled'),
|
|
'is_admin_checked' => $managedUser->isAdmin() ? ' checked' : '',
|
|
'is_enabled_checked' => $managedUser->isEnabled() ? ' checked' : '',
|
|
'created_at' => fmt_time($managedUser->createdAt()),
|
|
'last_login_at' => fmt_time($managedUser->lastLoginAt()),
|
|
'update_user_label' => t('app.update_user', 'Update user'),
|
|
'new_password_label' => t('app.new_password', 'New password'),
|
|
'change_password_label' => t('app.change_password', 'Change password'),
|
|
'delete_html' => $deleteHtml,
|
|
)) . "\n";
|
|
}
|
|
|
|
$headerHtml = app_header_html(array(
|
|
'title' => t('app.user_management', 'User management'),
|
|
'nav_items' => array(
|
|
array('label' => t('app.back_to_sandbox', 'Back to Racket sandbox'), 'url' => '/?lang=' . rawurlencode($language)),
|
|
array(
|
|
'label' => t('app.manage_prompts', 'Manage prompts'),
|
|
'url' => '/prompts?lang=' . rawurlencode($language),
|
|
'separator_before' => true,
|
|
),
|
|
array(
|
|
'label' => t('app.user_management', 'User management'),
|
|
'url' => '/users?lang=' . rawurlencode($language),
|
|
'active' => true,
|
|
'separator_before' => true,
|
|
),
|
|
array(
|
|
'label' => t('app.configuration', 'Configuration'),
|
|
'url' => '/admin-config?lang=' . rawurlencode($language),
|
|
'separator_before' => true,
|
|
),
|
|
),
|
|
'user' => $currentUser,
|
|
'user_prefix' => t('app.logged_in_as', 'Logged in as:'),
|
|
'admin_label' => t('app.admin', 'Admin'),
|
|
'language_label' => t('app.language', 'Language'),
|
|
'language' => $language,
|
|
'languages' => $headerLanguages,
|
|
'language_action' => '/users',
|
|
'logout_action' => '/users?lang=' . rawurlencode($language),
|
|
'logout_label' => t('app.logout', 'Logout'),
|
|
'message' => $message,
|
|
'error' => $error,
|
|
));
|
|
|
|
echo RacketSandboxTemplate::renderFile('users.html', array(
|
|
'language' => $language,
|
|
'language_url' => rawurlencode($language),
|
|
'title' => t('app.user_management', 'User management'),
|
|
'header_html' => $headerHtml,
|
|
'create_user_label' => t('app.create_user', 'Create user'),
|
|
'full_name_label' => t('app.full_name', 'Full name'),
|
|
'email_label' => t('app.email', 'Email'),
|
|
'password_label' => t('app.password', 'Password'),
|
|
'admin_label' => t('app.admin', 'Admin'),
|
|
'enabled_label' => t('app.enabled', 'Enabled'),
|
|
'user_management_label' => t('app.user_management', 'User management'),
|
|
'created_label' => t('app.created', 'Created'),
|
|
'last_login_label' => t('app.last_login', 'Last login'),
|
|
'actions_label' => t('app.actions', 'Actions'),
|
|
'user_rows_html' => $userRowsHtml,
|
|
));
|