seperated user files and audit logs.

main
Steffen Pohle 2 weeks ago
parent e59c5cae4b
commit 5850b97c54

@ -4,65 +4,208 @@ if (session_status() === PHP_SESSION_NONE) {
session_start(); session_start();
} }
function ensureConfigDirectory() { require_once __DIR__ . '/default.php';
if (!is_dir(CONFIG_PATH)) {
if (!mkdir(CONFIG_PATH, 0755, true) && !is_dir(CONFIG_PATH)) { function getBrowserIdentifier() {
throw new RuntimeException('Unable to create config directory.'); $agent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
} if (preg_match('/(Edg|Chrome|Chromium|Firefox|Safari|Opera|MSIE|Trident)/i', $agent, $matches)) {
return trim($matches[1]);
} }
return 'unknown';
} }
function getConfigData() { function getRememberMeCookieName($username) {
ensureConfigDirectory(); return 'kai_remember_' . sanitizeUsername($username);
}
if (!file_exists(CONFIG_FILE)) { function createRememberMeToken($username) {
return ['defaultModel' => '', 'users' => []]; $browser = getBrowserIdentifier();
$randomValue = bin2hex(random_bytes(16));
$token = hash_hmac('sha256', $username . '|' . $browser . '|' . $randomValue, APP_SECRET);
return [
'token' => $token,
'browser' => $browser,
'createdAt' => time(),
'lastUsedAt' => time()
];
}
function setRememberMeCookie($username) {
$username = trim((string) $username);
if ($username === '') {
return false;
} }
$content = @file_get_contents(CONFIG_FILE); $tokenData = createRememberMeToken($username);
if ($content === false) { $config = getUserConfig($username);
return ['defaultModel' => '', 'users' => []]; $tokens = is_array($config['rememberMeTokens'] ?? null) ? $config['rememberMeTokens'] : [];
$tokens[] = $tokenData;
if (count($tokens) > 10) {
usort($tokens, function ($a, $b) {
return ($a['lastUsedAt'] ?? 0) <=> ($b['lastUsedAt'] ?? 0);
});
$tokens = array_slice($tokens, -10);
} }
$data = json_decode($content, true); $config['rememberMeTokens'] = $tokens;
if (!is_array($data)) { if (!saveUserConfigData($username, $config)) {
return ['defaultModel' => '', 'users' => []]; return false;
} }
if (!isset($data['users']) || !is_array($data['users'])) { $cookieName = getRememberMeCookieName($username);
$data['users'] = []; return setcookie($cookieName, $tokenData['token'], time() + 60 * 60 * 24 * 30, '/', '', false, true);
}
function clearRememberMeCookie($username) {
$username = trim((string) $username);
if ($username === '') {
return;
} }
return $data; $cookieName = getRememberMeCookieName($username);
setcookie($cookieName, '', time() - 3600, '/', '', false, true);
} }
function saveConfigData($config) { function tryRememberMeLogin() {
if (!empty($_SESSION['auth_user']['username'])) {
return true;
}
foreach ($_COOKIE as $cookieName => $cookieValue) {
if (strpos($cookieName, 'kai_remember_') !== 0) {
continue;
}
$username = sanitizeUsername(substr($cookieName, strlen('kai_remember_')));
if ($username === '') {
continue;
}
$user = findUserByUsername($username);
if ($user === null) {
continue;
}
$config = getUserConfig($username);
$tokens = is_array($config['rememberMeTokens'] ?? null) ? $config['rememberMeTokens'] : [];
$browser = getBrowserIdentifier();
foreach ($tokens as &$entry) {
if (($entry['token'] ?? '') !== $cookieValue) {
continue;
}
if (!empty($entry['browser']) && $entry['browser'] !== $browser) {
continue;
}
$entry['lastUsedAt'] = time();
$config['rememberMeTokens'] = $tokens;
saveUserConfigData($username, $config);
$_SESSION['auth_user'] = [
'username' => $user['username'],
'role' => $user['role'] ?? 'user'
];
return true;
}
}
return false;
}
function ensureConfigDirectory() {
if (!is_dir(USER_CONFIG_DIR)) {
if (!mkdir(USER_CONFIG_DIR, 0755, true) && !is_dir(USER_CONFIG_DIR)) {
throw new RuntimeException('Unable to create config directory.');
}
}
}
function sanitizeUsername($username) {
$username = trim((string) $username);
$username = preg_replace('/[^A-Za-z0-9._-]/', '', $username);
return $username !== '' ? $username : 'user';
}
function getUserConfigPath($username) {
return USER_CONFIG_DIR . '/' . sanitizeUsername($username) . '-config.php';
}
function getUserChatPath($username) {
return USER_CONFIG_DIR . '/' . sanitizeUsername($username) . '-chat.php';
}
function readUserConfig($username) {
$path = getUserConfigPath($username);
if (!file_exists($path)) {
return [];
}
$data = include $path;
return is_array($data) ? $data : [];
}
function writeUserConfig($username, $config) {
ensureConfigDirectory(); ensureConfigDirectory();
$data = getConfigData(); $username = trim((string) $username);
if (array_key_exists('defaultModel', $config)) { if ($username === '') {
$data['defaultModel'] = (string) $config['defaultModel']; return false;
} }
if (array_key_exists('users', $config)) { $data = is_array($config) ? $config : [];
$data['users'] = is_array($config['users']) ? $config['users'] : []; $data['username'] = $username;
$data['role'] = (string) ($data['role'] ?? 'user');
$data['email'] = (string) ($data['email'] ?? '');
$data['passwordHash'] = (string) ($data['passwordHash'] ?? '');
$data['defaultModel'] = (string) ($data['defaultModel'] ?? '');
$php = "<?php\n\nreturn " . var_export($data, true) . ";\n";
return file_put_contents(getUserConfigPath($username), $php) !== false;
}
function readUserChat($username) {
$path = getUserChatPath($username);
if (!file_exists($path)) {
return [];
} }
$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); $data = include $path;
return file_put_contents(CONFIG_FILE, $json) !== false; return is_array($data) ? $data : [];
} }
function readConfig() { function writeUserChat($username, $chats) {
$data = getConfigData(); ensureConfigDirectory();
return [ $username = trim((string) $username);
'defaultModel' => isset($data['defaultModel']) ? (string) $data['defaultModel'] : '', if ($username === '') {
'users' => isset($data['users']) && is_array($data['users']) ? $data['users'] : [] return false;
]; }
$php = "<?php\n\nreturn " . var_export(is_array($chats) ? $chats : [], true) . ";\n";
return file_put_contents(getUserChatPath($username), $php) !== false;
} }
function writeConfig($config) { function renameUserFiles($oldUsername, $newUsername) {
return saveConfigData($config); $oldUsername = trim((string) $oldUsername);
$newUsername = trim((string) $newUsername);
if ($oldUsername === '' || $newUsername === '' || $oldUsername === $newUsername) {
return;
}
$oldConfigPath = getUserConfigPath($oldUsername);
$newConfigPath = getUserConfigPath($newUsername);
if (file_exists($oldConfigPath) && !file_exists($newConfigPath)) {
@rename($oldConfigPath, $newConfigPath);
}
$oldChatPath = getUserChatPath($oldUsername);
$newChatPath = getUserChatPath($newUsername);
if (file_exists($oldChatPath) && !file_exists($newChatPath)) {
@rename($oldChatPath, $newChatPath);
}
} }
function hashPassword($password) { function hashPassword($password) {
@ -73,13 +216,92 @@ function verifyPassword($password, $hash) {
return password_verify($password, $hash); return password_verify($password, $hash);
} }
function getUserConfig($username) {
$username = trim((string) $username);
if ($username === '') {
return [];
}
return readUserConfig($username);
}
function saveUserConfigData($username, $config) {
return writeUserConfig($username, $config);
}
function loadUsers() { function loadUsers() {
$config = readConfig(); ensureConfigDirectory();
return $config['users'];
$files = glob(USER_CONFIG_DIR . '/*-config.php');
if ($files === false) {
return [];
}
$users = [];
foreach ($files as $file) {
$username = basename($file, '-config.php');
$user = readUserConfig($username);
if (!empty($user) && !empty($user['username'])) {
$users[] = $user;
}
}
usort($users, function ($a, $b) {
return strcmp(($a['username'] ?? ''), ($b['username'] ?? ''));
});
return $users;
} }
function saveUsers($users) { function saveUsers($users, $previousUsers = null) {
return writeConfig(['users' => $users]); ensureConfigDirectory();
$normalizedUsers = [];
foreach ($users as $index => $user) {
$entry = is_array($user) ? $user : [];
$username = trim((string) ($entry['username'] ?? ''));
if ($username === '') {
continue;
}
$entry['username'] = $username;
$entry['role'] = (string) ($entry['role'] ?? 'user');
$entry['email'] = (string) ($entry['email'] ?? '');
$entry['passwordHash'] = (string) ($entry['passwordHash'] ?? '');
$entry['defaultModel'] = (string) ($entry['defaultModel'] ?? '');
$normalizedUsers[] = $entry;
}
$previousUsers = is_array($previousUsers) ? $previousUsers : loadUsers();
foreach ($normalizedUsers as $index => $entry) {
$oldUsername = isset($previousUsers[$index]) ? trim((string) ($previousUsers[$index]['username'] ?? '')) : '';
$newUsername = trim((string) ($entry['username'] ?? ''));
if ($oldUsername !== '' && $oldUsername !== $newUsername) {
renameUserFiles($oldUsername, $newUsername);
}
if (!writeUserConfig($newUsername, $entry)) {
return false;
}
}
$currentUsernames = [];
foreach ($normalizedUsers as $entry) {
$currentUsernames[] = sanitizeUsername($entry['username']);
}
$files = glob(USER_CONFIG_DIR . '/*-config.php');
if ($files !== false) {
foreach ($files as $file) {
$name = basename($file, '-config.php');
if (!in_array($name, $currentUsernames, true)) {
@unlink(USER_CONFIG_DIR . '/' . $name . '-config.php');
@unlink(USER_CONFIG_DIR . '/' . $name . '-chat.php');
}
}
}
return true;
} }
function findUserByUsername($username) { function findUserByUsername($username) {
@ -132,9 +354,14 @@ function createUser($username, $password, $role = 'user', $email = '') {
'username' => $username, 'username' => $username,
'email' => $email, 'email' => $email,
'passwordHash' => hashPassword($password), 'passwordHash' => hashPassword($password),
'role' => $role 'role' => $role,
'defaultModel' => ''
]; ];
if (!writeUserChat($username, [])) {
return false;
}
return saveUsers($users); return saveUsers($users);
} }
@ -222,7 +449,16 @@ function getAuthenticatedUser() {
return null; return null;
} }
return $_SESSION['auth_user']; return findUserByUsername($_SESSION['auth_user']['username'] ?? '');
}
function getAuthenticatedUsername() {
$user = getAuthenticatedUser();
if ($user !== null) {
return (string) ($user['username'] ?? '');
}
return (string) ($_SESSION['auth_user']['username'] ?? '');
} }
function requireAuthentication() { function requireAuthentication() {
@ -243,5 +479,10 @@ function requireAdmin() {
} }
function logoutUser() { function logoutUser() {
$username = trim((string) ($_SESSION['auth_user']['username'] ?? ''));
unset($_SESSION['auth_user']); unset($_SESSION['auth_user']);
if ($username !== '') {
clearRememberMeCookie($username);
}
} }

@ -2,6 +2,35 @@
header('Content-Type: application/json'); header('Content-Type: application/json');
require_once __DIR__ . '/default.php'; require_once __DIR__ . '/default.php';
require_once __DIR__ . '/auth.php';
function appendChatAuditEntry($username, $chatMessages, $resultPayload, $ipAddress = null) {
ensureConfigDirectory();
$auditPath = USER_CONFIG_DIR . '/chat-requests.json';
$entries = [];
if (file_exists($auditPath)) {
$raw = file_get_contents($auditPath);
if ($raw !== false) {
$decoded = json_decode($raw, true);
if (is_array($decoded)) {
$entries = $decoded;
}
}
}
$entries[] = [
'timestamp' => date('c'),
'username' => (string) $username,
'ipAddress' => (string) ($ipAddress ?? ($_SERVER['REMOTE_ADDR'] ?? '')),
'chat' => is_array($chatMessages) ? $chatMessages : [$chatMessages],
'result' => $resultPayload
];
$payload = json_encode($entries, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
return $payload !== false && file_put_contents($auditPath, $payload . PHP_EOL) !== false;
}
// 1. Handle fetching available models // 1. Handle fetching available models
if (isset($_GET['action']) && $_GET['action'] === 'models') { if (isset($_GET['action']) && $_GET['action'] === 'models') {
@ -24,6 +53,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$model = $input['model'] ?? 'llama3'; $model = $input['model'] ?? 'llama3';
$messages = $input['messages'] ?? []; $messages = $input['messages'] ?? [];
$username = '';
if (!empty($_SESSION['auth_user']['username'])) {
$username = sanitizeUsername($_SESSION['auth_user']['username']);
}
$payload = json_encode([ $payload = json_encode([
'model' => $model, 'model' => $model,
@ -38,13 +71,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$response = curl_exec($ch); $response = curl_exec($ch);
$resultPayload = null;
if (curl_errno($ch)) { if (curl_errno($ch)) {
echo json_encode(['error' => 'Error communicating with remote Ollama: ' . curl_error($ch)]); $resultPayload = ['error' => 'Error communicating with remote Ollama: ' . curl_error($ch)];
echo json_encode($resultPayload);
} else { } else {
$decodedResponse = json_decode($response, true);
$resultPayload = $decodedResponse !== null ? $decodedResponse : $response;
echo $response; echo $response;
} }
curl_close($ch); curl_close($ch);
appendChatAuditEntry($username, $messages, $resultPayload, $_SERVER['REMOTE_ADDR'] ?? '');
exit; exit;
} }

@ -1,40 +1,4 @@
<?php <?php
header('Content-Type: application/json'); define('USER_CONFIG_DIR', '/var/lib/KaI/users');
require_once __DIR__ . '/default.php'; define('OLLAMA_URL', 'http://127.0.0.1:11434');
require_once __DIR__ . '/auth.php';
$action = $_GET['action'] ?? '';
switch ($action) {
case 'load':
echo json_encode(readConfig());
exit;
case 'save':
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['error' => 'POST required.']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
if (!is_array($input)) {
echo json_encode(['error' => 'Invalid JSON.']);
exit;
}
$config = readConfig();
$config['defaultModel'] = isset($input['defaultModel']) ? (string) $input['defaultModel'] : '';
if (!writeConfig($config)) {
echo json_encode(['error' => 'Unable to save config.']);
exit;
}
echo json_encode(['success' => true, 'defaultModel' => $config['defaultModel']]);
exit;
default:
echo json_encode(['error' => 'Unknown action.']);
exit;
}

@ -1,10 +1,9 @@
<?php <?php
define('OLLAMA_URL', 'http://127.0.0.1:11434'); require_once __DIR__ . '/config.php';
define('CONFIG_PATH', '/var/lib/KaI');
define('CONFIG_FILE', CONFIG_PATH . '/config.json');
define('CHAT_HISTORY_FILE', CONFIG_PATH . '/chat.history.data');
define('MAIL_FROM', getenv('MAIL_FROM') ?: 'noreply@kai.local'); define('MAIL_FROM', getenv('MAIL_FROM') ?: 'noreply@kai.local');
define('MAIL_FROM_NAME', getenv('MAIL_FROM_NAME') ?: 'KaI'); define('MAIL_FROM_NAME', getenv('MAIL_FROM_NAME') ?: 'KaI');
define('APP_BASE_URL', getenv('APP_BASE_URL') ?: 'http://127.0.0.1/KaI-OllamaChat'); define('APP_BASE_URL', getenv('APP_BASE_URL') ?: 'http://127.0.0.1/KaI-OllamaChat');
define('APP_SECRET', getenv('APP_SECRET') ?: 'change-this-secret');

@ -82,7 +82,7 @@ function appendMessage(role, text) {
async function loadConfig() { async function loadConfig() {
try { try {
const response = await fetch('config.php?action=load'); const response = await fetch('savechat.php?action=load-config');
const data = await response.json(); const data = await response.json();
return data.defaultModel || ''; return data.defaultModel || '';
} catch (err) { } catch (err) {
@ -93,7 +93,7 @@ async function loadConfig() {
async function saveConfig(defaultModel) { async function saveConfig(defaultModel) {
try { try {
await fetch('config.php?action=save', { await fetch('savechat.php?action=save-config', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ defaultModel }) body: JSON.stringify({ defaultModel })

@ -23,6 +23,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'username' => $user['username'], 'username' => $user['username'],
'role' => $user['role'] ?? 'user' 'role' => $user['role'] ?? 'user'
]; ];
if (!empty($_POST['remember'])) {
setRememberMeCookie($user['username']);
} else {
clearRememberMeCookie($user['username']);
}
header('Location: index.php'); header('Location: index.php');
exit; exit;
} }
@ -36,9 +43,7 @@ if (isLoggedIn()) {
exit; exit;
} }
if (!file_exists(CONFIG_FILE)) { ensureConfigDirectory();
ensureConfigDirectory();
}
if (empty(loadUsers())) { if (empty(loadUsers())) {
$created = createUser('admin', 'changeme', 'admin', 'admin@example.com'); $created = createUser('admin', 'changeme', 'admin', 'admin@example.com');
@ -75,6 +80,11 @@ if (empty(loadUsers())) {
<label for="password">Password</label> <label for="password">Password</label>
<input id="password" name="password" type="password" required> <input id="password" name="password" type="password" required>
<label style="font-weight:normal; margin-top:12px;">
<input type="checkbox" name="remember" value="1">
Remember me on this browser for 30 days
</label>
<button type="submit">Sign in</button> <button type="submit">Sign in</button>
</form> </form>
<?php if (!empty($errors)): ?> <?php if (!empty($errors)): ?>

@ -2,169 +2,118 @@
header('Content-Type: application/json'); header('Content-Type: application/json');
require_once __DIR__ . '/default.php'; require_once __DIR__ . '/default.php';
require_once __DIR__ . '/auth.php';
/*---------------------------------------------------------- requireAuthentication();
- Create storage file if necessary
----------------------------------------------------------*/
if (!file_exists(CHAT_HISTORY_FILE)) {
if (@file_put_contents(CHAT_HISTORY_FILE, '') === false) {
http_response_code(500);
echo json_encode([
'error' => 'Cannot create history file.'
]);
exit;
}
}
/*----------------------------------------------------------
- Helper
----------------------------------------------------------*/
function readChats() {
$result = [];
$fp = fopen(CHAT_HISTORY_FILE, 'c+');
if (!$fp) {
return [];
}
flock($fp, LOCK_SH);
while (($line = fgets($fp)) !== false) {
$line = trim($line);
if ($line === '') {
continue;
}
$obj = json_decode($line, true);
if (is_array($obj)) {
$result[] = $obj;
}
}
flock($fp, LOCK_UN); $username = getAuthenticatedUsername();
fclose($fp);
return $result;
}
function writeChats($chats) {
$fp = fopen(CHAT_HISTORY_FILE, 'w');
if (!$fp) {
return false;
}
flock($fp, LOCK_EX);
foreach ($chats as $chat) {
fwrite($fp, json_encode($chat, JSON_UNESCAPED_UNICODE) . PHP_EOL);
}
fflush($fp);
flock($fp, LOCK_UN);
fclose($fp);
return true;
}
function createTitle($messages) { function createTitle($messages) {
foreach ($messages as $msg) { foreach ($messages as $msg) {
if (($msg['role'] ?? '') === 'user') { if (($msg['role'] ?? '') === 'user') {
$title = trim($msg['content']); $title = trim($msg['content']);
if (mb_strlen($title) > 60) { if (mb_strlen($title) > 60) {
$title = mb_substr($title, 0, 60) . "..."; $title = mb_substr($title, 0, 60) . '...';
} }
return $title; return $title;
} }
} }
return "Untitled Chat"; return 'Untitled Chat';
} }
/*----------------------------------------------------------
- Action
----------------------------------------------------------*/
$action = $_GET['action'] ?? ''; $action = $_GET['action'] ?? '';
switch ($action) { switch ($action) {
/*------------------------------------------------------ case 'load-config':
- LIST $config = getUserConfig($username);
------------------------------------------------------*/ echo json_encode([
'defaultModel' => (string) ($config['defaultModel'] ?? '')
]);
exit;
case 'save-config':
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['error' => 'POST required.']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
if (!is_array($input)) {
echo json_encode(['error' => 'Invalid JSON.']);
exit;
}
$config = getUserConfig($username);
$config['defaultModel'] = isset($input['defaultModel']) ? (string) $input['defaultModel'] : '';
if (!saveUserConfigData($username, $config)) {
echo json_encode(['error' => 'Unable to save config.']);
exit;
}
echo json_encode(['success' => true, 'defaultModel' => $config['defaultModel']]);
exit;
case 'list': case 'list':
$chats = readChats(); $chats = readUserChat($username);
$list = []; $list = [];
foreach ($chats as $chat) { foreach ($chats as $chat) {
$list[] = [ $list[] = [
'id' => $chat['id'], 'id' => $chat['id'] ?? '',
'title' => $chat['title'], 'title' => $chat['title'] ?? 'Untitled Chat',
'created' => $chat['created'], 'created' => $chat['created'] ?? '',
'model' => $chat['model'] ?? '' 'model' => $chat['model'] ?? ''
]; ];
} }
usort($list, function($a, $b) { usort($list, function ($a, $b) {
return strcmp($b['created'], $a['created']); return strcmp($b['created'], $a['created']);
}); });
echo json_encode($list); echo json_encode($list);
exit; exit;
/*------------------------------------------------------
- LOAD
------------------------------------------------------*/
case 'load': case 'load':
$id = $_GET['id'] ?? ''; $id = $_GET['id'] ?? '';
if ($id == '') { if ($id === '') {
echo json_encode([ echo json_encode(['error' => 'Missing id.']);
'error' => 'Missing id.'
]);
exit; exit;
} }
$chats = readChats(); $chats = readUserChat($username);
foreach ($chats as $chat) { foreach ($chats as $chat) {
if ($chat['id'] === $id) { if (($chat['id'] ?? '') === $id) {
echo json_encode($chat); echo json_encode($chat);
exit; exit;
} }
} }
echo json_encode([ echo json_encode(['error' => 'Chat not found.']);
'error' => 'Chat not found.'
]);
exit; exit;
/*------------------------------------------------------
- SAVE
------------------------------------------------------*/
case 'save': case 'save':
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode([ echo json_encode(['error' => 'POST required.']);
'error' => 'POST required.'
]);
exit; exit;
} }
$input = json_decode(file_get_contents('php://input'), true); $input = json_decode(file_get_contents('php://input'), true);
if (!is_array($input)) { if (!is_array($input)) {
echo json_encode([ echo json_encode(['error' => 'Invalid JSON.']);
'error' => 'Invalid JSON.'
]);
exit; exit;
} }
$messages = $input['messages'] ?? []; $messages = $input['messages'] ?? [];
if (!is_array($messages) || count($messages) == 0) { if (!is_array($messages) || count($messages) === 0) {
echo json_encode([ echo json_encode(['error' => 'No messages.']);
'error' => 'No messages.'
]);
exit; exit;
} }
$id = $input['id'] ?? ''; $id = $input['id'] ?? '';
if ($id == '') { if ($id === '') {
$id = uniqid('', true); $id = uniqid('', true);
} }
$title = createTitle($messages); $title = createTitle($messages);
$model = $input['model'] ?? ''; $model = isset($input['model']) ? (string) $input['model'] : '';
$chat = [ $chat = [
'id' => $id, 'id' => $id,
'title' => $title, 'title' => $title,
@ -173,10 +122,10 @@ switch ($action) {
'messages' => $messages 'messages' => $messages
]; ];
$chats = readChats(); $chats = readUserChat($username);
$found = false; $found = false;
foreach ($chats as &$existing) { foreach ($chats as &$existing) {
if ($existing['id'] === $id) { if (($existing['id'] ?? '') === $id) {
$existing = $chat; $existing = $chat;
$found = true; $found = true;
break; break;
@ -187,10 +136,10 @@ switch ($action) {
$chats[] = $chat; $chats[] = $chat;
} }
if (!writeChats($chats)) { $config = getUserConfig($username);
echo json_encode([ $config['defaultModel'] = $model;
'error' => 'Unable to save.' if (!saveUserConfigData($username, $config) || !writeUserChat($username, $chats)) {
]); echo json_encode(['error' => 'Unable to save.']);
exit; exit;
} }
@ -201,40 +150,26 @@ switch ($action) {
]); ]);
exit; exit;
/*------------------------------------------------------
- DELETE
------------------------------------------------------*/
case 'delete': case 'delete':
$id = $_GET['id'] ?? ''; $id = $_GET['id'] ?? '';
if ($id === '') {
if ($id == '') { echo json_encode(['error' => 'Missing id.']);
echo json_encode([
'error' => 'Missing id.'
]);
exit; exit;
} }
$chats = readChats(); $chats = readUserChat($username);
$newChats = []; $newChats = [];
foreach ($chats as $chat) { foreach ($chats as $chat) {
if ($chat['id'] !== $id) { if (($chat['id'] ?? '') !== $id) {
$newChats[] = $chat; $newChats[] = $chat;
} }
} }
writeChats($newChats); writeUserChat($username, $newChats);
echo json_encode([ echo json_encode(['success' => true]);
'success' => true
]);
exit; exit;
/*------------------------------------------------------
- DEFAULT
------------------------------------------------------*/
default: default:
echo json_encode([ echo json_encode(['error' => 'Unknown action.']);
'error' => 'Unknown action.'
]);
exit; exit;
} }

@ -11,6 +11,7 @@ requireAuthentication();
requireAdmin(); requireAdmin();
$users = loadUsers(); $users = loadUsers();
$previousUsers = $users;
$errors = []; $errors = [];
$success = ''; $success = '';
@ -49,7 +50,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$users[$index]['passwordHash'] = hashPassword($password); $users[$index]['passwordHash'] = hashPassword($password);
} }
$users[$index]['role'] = $role; $users[$index]['role'] = $role;
if (saveUsers($users)) { if (saveUsers($users, $previousUsers)) {
$success = 'User updated successfully.'; $success = 'User updated successfully.';
} else { } else {
$errors[] = 'Unable to update user.'; $errors[] = 'Unable to update user.';
@ -62,7 +63,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($index >= 0 && isset($users[$index])) { if ($index >= 0 && isset($users[$index])) {
unset($users[$index]); unset($users[$index]);
$users = array_values($users); $users = array_values($users);
if (saveUsers($users)) { if (saveUsers($users, $previousUsers)) {
$success = 'User deleted successfully.'; $success = 'User deleted successfully.';
} else { } else {
$errors[] = 'Unable to delete user.'; $errors[] = 'Unable to delete user.';

Loading…
Cancel
Save