Files
racket-chatgpt-bootstrap/users.php
T
2026-05-25 13:47:46 +02:00

298 lines
11 KiB
PHP

<?php
/*
* users.php
*
* Admin user management.
*/
require_once __DIR__ . '/auth.php';
require_once __DIR__ . '/header.php';
require_once __DIR__ . '/languagestore.php';
require_once __DIR__ . '/usersettings.php';
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
ini_set('log_errors', '1');
error_reporting(E_ALL);
$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)
{
global $languageStore, $language;
return $languageStore->translate($key, $language, $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()
);
$languageStore->seedDefaults(array(
'app.title' => array('en' => 'Racket sandbox', 'nl' => 'Racket sandbox'),
'app.manage_prompts' => array('en' => 'Manage prompts', 'nl' => 'Prompts beheren'),
'app.user_management' => array('en' => 'User management', 'nl' => 'Gebruikersbeheer'),
'app.logout' => array('en' => 'Logout', 'nl' => 'Uitloggen'),
'app.language' => array('en' => 'Language', 'nl' => 'Taal'),
'app.logged_in_as' => array('en' => 'Logged in as:', 'nl' => 'Ingelogd als:'),
'app.admin' => array('en' => 'Admin', 'nl' => 'Admin'),
'app.enabled' => array('en' => 'Enabled', 'nl' => 'Ingeschakeld'),
'app.full_name' => array('en' => 'Full name', 'nl' => 'Volledige naam'),
'app.email' => array('en' => 'Email', 'nl' => 'E-mail'),
'app.password' => array('en' => 'Password', 'nl' => 'Wachtwoord'),
'app.new_password' => array('en' => 'New password', 'nl' => 'Nieuw wachtwoord'),
'app.created' => array('en' => 'Created', 'nl' => 'Gemaakt'),
'app.last_login' => array('en' => 'Last login', 'nl' => 'Laatste login'),
'app.actions' => array('en' => 'Actions', 'nl' => 'Acties'),
'app.create_user' => array('en' => 'Create user', 'nl' => 'Gebruiker aanmaken'),
'app.update_user' => array('en' => 'Update user', 'nl' => 'Gebruiker aanpassen'),
'app.change_password' => array('en' => 'Change password', 'nl' => 'Wachtwoord wijzigen'),
'app.delete_user' => array('en' => 'Delete user', 'nl' => 'Gebruiker verwijderen'),
'app.delete_user_confirm' => array('en' => 'Delete user', 'nl' => 'Gebruiker verwijderen'),
'app.cannot_delete_self' => array('en' => 'You cannot delete your own account.', 'nl' => 'Je kunt je eigen account niet verwijderen.'),
'app.cannot_disable_self' => array('en' => 'You cannot disable your own account.', 'nl' => 'Je kunt je eigen account niet uitschakelen.'),
'app.cannot_remove_own_admin' => array('en' => 'You cannot remove your own admin rights.', 'nl' => 'Je kunt je eigen adminrechten niet verwijderen.'),
'app.user_created' => array('en' => 'User created.', 'nl' => 'Gebruiker aangemaakt.'),
'app.user_updated' => array('en' => 'User updated.', 'nl' => 'Gebruiker aangepast.'),
'app.password_changed' => array('en' => 'Password changed.', 'nl' => 'Wachtwoord gewijzigd.'),
'app.user_deleted' => array('en' => 'User deleted.', 'nl' => 'Gebruiker verwijderd.'),
'app.back_to_sandbox' => array('en' => 'Back to Racket sandbox', 'nl' => 'Terug naar Racket sandbox'),
'app.configuration' => array('en' => 'Configuration', 'nl' => 'Configuratie'),
));
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');
?>
<!doctype html>
<html lang="<?= h($language) ?>">
<head>
<meta charset="utf-8">
<title><?= h(t('app.user_management', 'User management')) ?></title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<div class="page">
<?php
render_app_header(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,
));
?>
<main class="page-main dashboard-main">
<section class="panel">
<h2><?= h(t('app.create_user', 'Create user')) ?></h2>
<form method="post" action="/users?lang=<?= h($language) ?>" class="admin-form-grid">
<input type="hidden" name="action" value="create_user">
<label><?= h(t('app.full_name', 'Full name')) ?><br><input type="text" name="full_name" required></label>
<label><?= h(t('app.email', 'Email')) ?><br><input type="email" name="email" required></label>
<label><?= h(t('app.password', 'Password')) ?><br><input type="password" name="password" autocomplete="new-password" required></label>
<label><input type="checkbox" name="is_admin" value="1"> <?= h(t('app.admin', 'Admin')) ?></label>
<label><input type="checkbox" name="is_enabled" value="1" checked> <?= h(t('app.enabled', 'Enabled')) ?></label>
<button type="submit"><?= h(t('app.create_user', 'Create user')) ?></button>
</form>
</section>
<section class="panel">
<h2><?= h(t('app.user_management', 'User management')) ?></h2>
<table>
<thead>
<tr>
<th><?= h(t('app.full_name', 'Full name')) ?></th>
<th><?= h(t('app.email', 'Email')) ?></th>
<th><?= h(t('app.admin', 'Admin')) ?></th>
<th><?= h(t('app.enabled', 'Enabled')) ?></th>
<th><?= h(t('app.created', 'Created')) ?></th>
<th><?= h(t('app.last_login', 'Last login')) ?></th>
<th><?= h(t('app.actions', 'Actions')) ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($users as $managedUser): ?>
<tr>
<td colspan="7">
<form method="post" action="/users?lang=<?= h($language) ?>" class="user-row-form">
<input type="hidden" name="action" value="update_user">
<input type="hidden" name="user_id" value="<?= h($managedUser->id()) ?>">
<label><?= h(t('app.full_name', 'Full name')) ?><br><input type="text" name="full_name" value="<?= h($managedUser->fullName()) ?>" required></label>
<label><?= h(t('app.email', 'Email')) ?><br><input type="email" name="email" value="<?= h($managedUser->email()) ?>" required></label>
<label><input type="checkbox" name="is_admin" value="1" <?= $managedUser->isAdmin() ? 'checked' : '' ?>> <?= h(t('app.admin', 'Admin')) ?></label>
<label><input type="checkbox" name="is_enabled" value="1" <?= $managedUser->isEnabled() ? 'checked' : '' ?>> <?= h(t('app.enabled', 'Enabled')) ?></label>
<span><?= h(fmt_time($managedUser->createdAt())) ?></span>
<span><?= h(fmt_time($managedUser->lastLoginAt())) ?></span>
<button type="submit"><?= h(t('app.update_user', 'Update user')) ?></button>
</form>
<div class="user-row-actions">
<form method="post" action="/users?lang=<?= h($language) ?>">
<input type="hidden" name="action" value="set_password">
<input type="hidden" name="email" value="<?= h($managedUser->email()) ?>">
<label><?= h(t('app.new_password', 'New password')) ?><br><input type="password" name="password" autocomplete="new-password"></label>
<button type="submit"><?= h(t('app.change_password', 'Change password')) ?></button>
</form>
<?php if ($managedUser->id() !== $currentUser->id()): ?>
<form method="post" action="/users?lang=<?= h($language) ?>"
onsubmit="return confirm('<?= h(t('app.delete_user_confirm', 'Delete user')) ?> <?= h($managedUser->email()) ?>?');">
<input type="hidden" name="action" value="delete_user">
<input type="hidden" name="user_id" value="<?= h($managedUser->id()) ?>">
<button type="submit"><?= h(t('app.delete_user', 'Delete user')) ?></button>
</form>
<?php else: ?>
<p class="small"><?= h(t('app.cannot_delete_self', 'You cannot delete your own account.')) ?></p>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</section>
</main>
</div>
</body>
</html>