generated from jric11/baseProject
148 lines
9.6 KiB
PHP
148 lines
9.6 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
class Applications extends Base {
|
||
|
|
public function authorizeAdministration(): void {
|
||
|
|
$this->requireAdministrator();
|
||
|
|
}
|
||
|
|
private function requireAdministrator(): void {
|
||
|
|
$statement = $this->connect()->prepare('SELECT user_name, user_role, user_status FROM users WHERE user_serial = :user');
|
||
|
|
$statement->execute([':user' => (int) ($_SESSION[self::USER_SERIAL] ?? 0)]);
|
||
|
|
$user = $statement->fetch(PDO::FETCH_ASSOC);
|
||
|
|
$allowed = $user && $user['user_status'] === 'active' && in_array($user['user_role'], ['Administrator', 'System Administrator'], true);
|
||
|
|
if ($user && $user['user_status'] === 'active') {
|
||
|
|
foreach ($this->getSettings()->xpath('//SystemAdministrator') as $name) {
|
||
|
|
$allowed = $allowed || (string) $name === $user['user_name'];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!$allowed) {
|
||
|
|
http_response_code(403);
|
||
|
|
exit('Administrator access is required.');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public function dashboard(): void {
|
||
|
|
try {
|
||
|
|
$statement = $this->connect()->prepare('SELECT a.* FROM applications a JOIN user_applications ua ON ua.application_serial = a.application_serial WHERE ua.user_serial = :user AND a.application_active = 1 ORDER BY a.application_name');
|
||
|
|
$statement->execute([':user' => (int) $_SESSION[self::USER_SERIAL]]);
|
||
|
|
$xml = $this->getTableXML('applications', $statement);
|
||
|
|
} catch (PDOException $e) {
|
||
|
|
if ((int) ($e->errorInfo[1] ?? 0) !== 1146) { throw $e; }
|
||
|
|
$xml = new SimpleXMLElement('<applications/>');
|
||
|
|
$xml->addAttribute('setup_required', 'true');
|
||
|
|
}
|
||
|
|
$this->displayContent($this->applyXSL($xml, $this->getXSL('home')));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function manageAccess(): void {
|
||
|
|
$this->requireAdministrator();
|
||
|
|
$connection = $this->connect();
|
||
|
|
$userSerial = (int) (filter_input(INPUT_GET, 'user_serial', FILTER_VALIDATE_INT) ?: 0);
|
||
|
|
$xml = new SimpleXMLElement('<access/>');
|
||
|
|
$xml->addAttribute('selected_user', (string) $userSerial);
|
||
|
|
$xml->addAttribute('saved', filter_input(INPUT_GET, 'saved') === '1' ? 'true' : 'false');
|
||
|
|
$xml = $this->mergeXML($this->getTableXML('users', $connection->query('SELECT user_serial, user_name, user_status FROM users ORDER BY user_name')), $xml);
|
||
|
|
try {
|
||
|
|
$statement = $connection->prepare('SELECT a.*, CASE WHEN ua.user_serial IS NULL THEN 0 ELSE 1 END AS assigned FROM applications a LEFT JOIN user_applications ua ON ua.application_serial = a.application_serial AND ua.user_serial = :user ORDER BY a.application_name');
|
||
|
|
$statement->execute([':user' => $userSerial]);
|
||
|
|
} catch (PDOException $e) {
|
||
|
|
if ((int) ($e->errorInfo[1] ?? 0) !== 1146) { throw $e; }
|
||
|
|
$this->displayContent($this->applyXSL('<access setup_required="true"/>', $this->getXSL('applicationAccess')));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
$xml = $this->mergeXML($this->getTableXML('applications', $statement), $xml);
|
||
|
|
try {
|
||
|
|
$links = $connection->prepare('SELECT application_serial, local_user_serial FROM user_application_accounts WHERE user_serial = :user');
|
||
|
|
$links->execute([':user' => $userSerial]);
|
||
|
|
$xml = $this->mergeXML($this->getTableXML('account_links', $links), $xml);
|
||
|
|
} catch (PDOException $e) {
|
||
|
|
if ((int) ($e->errorInfo[1] ?? 0) !== 1146) { throw $e; }
|
||
|
|
}
|
||
|
|
$this->displayContent($this->applyXSL($xml, $this->getXSL('applicationAccess')));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function saveAccess(): void {
|
||
|
|
$this->requireAdministrator();
|
||
|
|
if (!$this->validAuthRequest()) { http_response_code(403); exit('Invalid request. Reload the application access page.'); }
|
||
|
|
$userSerial = filter_input(INPUT_POST, 'user_serial', FILTER_VALIDATE_INT) ?: 0;
|
||
|
|
$selected = filter_input(INPUT_POST, 'applications', FILTER_VALIDATE_INT, FILTER_REQUIRE_ARRAY);
|
||
|
|
$selected = $selected === null ? [] : $selected;
|
||
|
|
if (!is_array($selected) || in_array(false, $selected, true) || in_array(null, $selected, true)) {
|
||
|
|
http_response_code(422); exit('Invalid application selection.');
|
||
|
|
}
|
||
|
|
$selected = array_unique($selected);
|
||
|
|
$links = filter_input(INPUT_POST, 'local_users', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
|
||
|
|
if ($links !== null && !is_array($links)) { http_response_code(422); exit('Invalid account links.'); }
|
||
|
|
$linkedAccounts = [];
|
||
|
|
foreach ($links ?? [] as $application => $localUser) {
|
||
|
|
if (!ctype_digit((string) $application) || !is_string($localUser)) { http_response_code(422); exit('Invalid account link.'); }
|
||
|
|
if (trim($localUser) === '') { continue; }
|
||
|
|
$localUser = filter_var(trim($localUser), FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
|
||
|
|
if ($localUser === false) { http_response_code(422); exit('Account IDs must be positive whole numbers.'); }
|
||
|
|
$linkedAccounts[(int) $application] = $localUser;
|
||
|
|
}
|
||
|
|
$connection = $this->connect();
|
||
|
|
$connection->beginTransaction();
|
||
|
|
try {
|
||
|
|
$statement = $connection->prepare('SELECT user_serial FROM users WHERE user_serial = :user FOR UPDATE');
|
||
|
|
$statement->execute([':user' => $userSerial]);
|
||
|
|
if (!$statement->fetchColumn()) { $connection->rollBack(); http_response_code(422); exit('Select an existing user.'); }
|
||
|
|
$valid = array_map('intval', $connection->query('SELECT application_serial FROM applications')->fetchAll(PDO::FETCH_COLUMN));
|
||
|
|
if (array_diff($selected, $valid)) { $connection->rollBack(); http_response_code(422); exit('Invalid application selection.'); }
|
||
|
|
if (array_diff(array_keys($links ?? []), $valid)) { $connection->rollBack(); http_response_code(422); exit('Invalid application account link.'); }
|
||
|
|
if ($links !== null) {
|
||
|
|
$delete = $connection->prepare('DELETE FROM user_application_accounts WHERE user_serial = :user');
|
||
|
|
$delete->execute([':user' => $userSerial]);
|
||
|
|
$insert = $connection->prepare('INSERT INTO user_application_accounts (user_serial, application_serial, local_user_serial, linked_by) VALUES (:user, :application, :local, :actor)');
|
||
|
|
foreach ($linkedAccounts as $application => $localUser) {
|
||
|
|
$insert->execute([':user' => $userSerial, ':application' => $application, ':local' => $localUser, ':actor' => $_SESSION[self::USER_NAME]]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
$statement = $connection->prepare('DELETE FROM user_applications WHERE user_serial = :user');
|
||
|
|
$statement->execute([':user' => $userSerial]);
|
||
|
|
$statement = $connection->prepare('INSERT INTO user_applications (user_serial, application_serial, assigned_by) VALUES (:user, :application, :actor)');
|
||
|
|
foreach ($selected as $application) {
|
||
|
|
$statement->execute([':user' => $userSerial, ':application' => $application, ':actor' => $_SESSION[self::USER_NAME]]);
|
||
|
|
}
|
||
|
|
$journal = $connection->prepare('INSERT INTO journal (journal_origin, journal_ip, journal_entry) VALUES (:actor, :ip, :entry)');
|
||
|
|
$journal->execute([':actor' => $_SESSION[self::USER_NAME], ':ip' => $_SERVER['REMOTE_ADDR'] ?? '', ':entry' => 'Updated application access for user ' . $userSerial . ': ' . implode(', ', $selected) . ($links !== null ? '; account links: ' . json_encode($linkedAccounts) : '')]);
|
||
|
|
$connection->commit();
|
||
|
|
} catch (Throwable $e) {
|
||
|
|
if ($connection->inTransaction()) { $connection->rollBack(); }
|
||
|
|
if ($e instanceof PDOException && (int) ($e->errorInfo[1] ?? 0) === 1062) {
|
||
|
|
http_response_code(409);
|
||
|
|
exit('That application account is already linked to another DEC user. No changes were saved.');
|
||
|
|
}
|
||
|
|
throw $e;
|
||
|
|
}
|
||
|
|
header('Location: main.php?Xaction=Applications.manageAccess&user_serial=' . $userSerial . '&saved=1', true, 303);
|
||
|
|
exit();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setup(): void {
|
||
|
|
$this->requireAdministrator();
|
||
|
|
if (!$this->validAuthRequest()) { http_response_code(403); exit('Invalid setup request. Reload the page.'); }
|
||
|
|
$connection = $this->connect();
|
||
|
|
foreach (['001_application_access.sql', '002_application_account_links.sql'] as $migration) {
|
||
|
|
$sql = file_get_contents(__DIR__ . '/../migrations/' . $migration);
|
||
|
|
foreach (explode(';', $sql) as $statement) {
|
||
|
|
if (trim($statement) !== '') { $connection->exec($statement); }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
header('Location: main.php?Xaction=Applications.manageAccess', true, 303);
|
||
|
|
exit();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function launch(): void {
|
||
|
|
$application = filter_input(INPUT_GET, 'application_serial', FILTER_VALIDATE_INT) ?: 0;
|
||
|
|
$statement = $this->connect()->prepare('SELECT a.application_url FROM applications a JOIN user_applications ua ON ua.application_serial = a.application_serial WHERE a.application_serial = :application AND ua.user_serial = :user AND a.application_active = 1');
|
||
|
|
$statement->execute([':application' => $application, ':user' => (int) $_SESSION[self::USER_SERIAL]]);
|
||
|
|
$url = $statement->fetchColumn();
|
||
|
|
if (!$url) { http_response_code(403); exit('This application is not assigned to your account.'); }
|
||
|
|
if (!filter_var($url, FILTER_VALIDATE_URL) || !in_array(strtolower(parse_url($url, PHP_URL_SCHEME) ?: ''), ['http', 'https'], true) || preg_match('/[\r\n]/', $url)) {
|
||
|
|
http_response_code(500); exit('The application URL is invalid. Contact your administrator.');
|
||
|
|
}
|
||
|
|
header('Location: ' . $url, true, 303);
|
||
|
|
exit();
|
||
|
|
}
|
||
|
|
}
|