Module tasks + knowledgecenter_update aus Kundenprojekt übernehmen (bereinigt)
Beide Module wurden aus einem anderen Kundenprojekt kopiert und bereinigt:
Knowledgecenter:
- Bild-Cache (1.985 Dateien) geleert, Ordnerstruktur mit .gitkeep behalten
- Files-Gallery-Lizenzschlüssel entfernt (config.php)
- Kundenspezifische Kategorien gelöscht: Teil I/II/III QM-Struktur,
nummerierte QM-Kapitel, Gremien (Präsidium/Finanzausschuss/Landesausschuss),
Sitzungsservice-Serie, Protokoll-Abteilungen, Testeinträge
- 56 generische Kategorien bleiben (Downloads, Onboarding, Personalthemen …)
Tasks:
- Alle Betriebsdaten gelöscht (114 Tasks, 914 Submissions, 579 Assignments)
- Task-Definitionen und Verlinkungen geleert
- Kategoriestruktur bleibt (Allgemein, IT, Personal, Buchhaltung …)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 09:20:02 +02:00
|
|
|
<?php
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
require_once __DIR__ . '/lib/Logger.php';
|
|
|
|
|
|
|
|
|
|
if (!function_exists('task_cert_bootstrap_output_warning')) {
|
|
|
|
|
function task_cert_bootstrap_output_warning(string $message): void
|
|
|
|
|
{
|
|
|
|
|
if (PHP_SAPI === 'cli') {
|
|
|
|
|
fwrite(STDERR, $message . PHP_EOL);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$safeMessage = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
|
|
|
|
|
$requestUri = (string) ($_SERVER['REQUEST_URI'] ?? '');
|
|
|
|
|
$accept = (string) ($_SERVER['HTTP_ACCEPT'] ?? '');
|
|
|
|
|
$isAjax = strtolower((string) ($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '')) === 'xmlhttprequest';
|
|
|
|
|
|
|
|
|
|
$expectsJson = (
|
|
|
|
|
strpos($requestUri, '/endpoints/') !== false
|
|
|
|
|
|| strpos($accept, 'application/json') !== false
|
|
|
|
|
|| $isAjax
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if ($expectsJson) {
|
|
|
|
|
if (!headers_sent()) {
|
|
|
|
|
http_response_code(500);
|
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo json_encode([
|
|
|
|
|
'success' => false,
|
|
|
|
|
'error' => $message,
|
|
|
|
|
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!headers_sent()) {
|
|
|
|
|
http_response_code(500);
|
|
|
|
|
header('Content-Type: text/html; charset=utf-8');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo '<div class="task-cert"><div class="task-cert-error">' . $safeMessage . '</div></div>';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!function_exists('task_cert_bootstrap_truthy')) {
|
|
|
|
|
function task_cert_bootstrap_truthy(string $value): bool
|
|
|
|
|
{
|
|
|
|
|
return in_array(strtolower(trim($value)), ['1', 'true', 'yes', 'on', 'always'], true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!function_exists('task_cert_is_endpoint_request')) {
|
|
|
|
|
function task_cert_is_endpoint_request(): bool
|
|
|
|
|
{
|
|
|
|
|
$uri = strtolower((string) ($_SERVER['REQUEST_URI'] ?? ''));
|
|
|
|
|
$scriptName = strtolower((string) ($_SERVER['SCRIPT_NAME'] ?? ''));
|
|
|
|
|
$scriptFilename = strtolower((string) ($_SERVER['SCRIPT_FILENAME'] ?? ''));
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
strpos($uri, '/endpoints/') !== false
|
|
|
|
|
|| strpos($scriptName, '/endpoints/') !== false
|
|
|
|
|
|| strpos($scriptFilename, '/endpoints/') !== false
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!function_exists('task_cert_has_monolith_context')) {
|
|
|
|
|
function task_cert_has_monolith_context(): bool
|
|
|
|
|
{
|
|
|
|
|
return (
|
|
|
|
|
is_array($GLOBALS['site'] ?? null)
|
|
|
|
|
&& is_array($GLOBALS['language'] ?? null)
|
|
|
|
|
&& (
|
|
|
|
|
is_array($GLOBALS['main_contact'] ?? null)
|
|
|
|
|
|| isset($_SESSION['login_id'])
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!function_exists('task_cert_bootstrap_context_fallback')) {
|
|
|
|
|
function task_cert_bootstrap_context_fallback(): void
|
|
|
|
|
{
|
|
|
|
|
if (!is_array($GLOBALS['site'] ?? null)) {
|
|
|
|
|
$GLOBALS['site'] = [];
|
|
|
|
|
}
|
|
|
|
|
if (!is_array($GLOBALS['language'] ?? null)) {
|
|
|
|
|
$GLOBALS['language'] = [];
|
|
|
|
|
}
|
|
|
|
|
if (!is_array($GLOBALS['main_contact'] ?? null)) {
|
|
|
|
|
$GLOBALS['main_contact'] = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$uri = (string) ($_SERVER['REQUEST_URI'] ?? '');
|
|
|
|
|
$path = parse_url($uri, PHP_URL_PATH);
|
|
|
|
|
$segments = array_values(array_filter(explode('/', trim((string) $path, '/')), static function (string $segment): bool {
|
|
|
|
|
return $segment !== '';
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
$siteCode = '';
|
|
|
|
|
$languageCode = '';
|
|
|
|
|
if (!task_cert_is_endpoint_request()) {
|
|
|
|
|
if (isset($segments[0])) {
|
|
|
|
|
$siteCode = strtolower((string) (preg_replace('/[^a-z0-9_-]/i', '', $segments[0]) ?? ''));
|
|
|
|
|
}
|
|
|
|
|
if (isset($segments[1])) {
|
|
|
|
|
$languageCode = strtolower((string) (preg_replace('/[^a-z0-9_-]/i', '', $segments[1]) ?? ''));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (($GLOBALS['site']['code'] ?? '') === '') {
|
|
|
|
|
$GLOBALS['site']['code'] = $siteCode !== '' ? $siteCode : 'intranet';
|
|
|
|
|
}
|
|
|
|
|
if (($GLOBALS['language']['code'] ?? '') === '') {
|
|
|
|
|
$GLOBALS['language']['code'] = $languageCode !== '' ? $languageCode : 'de';
|
|
|
|
|
}
|
|
|
|
|
if (!isset($GLOBALS['site']['id'])) {
|
|
|
|
|
$GLOBALS['site']['id'] = 0;
|
|
|
|
|
}
|
|
|
|
|
if (!isset($GLOBALS['language']['id'])) {
|
|
|
|
|
$GLOBALS['language']['id'] = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$loginId = (int) ($_SESSION['login_id'] ?? ($_SESSION['main_contact_id'] ?? ($_SESSION['contact_id'] ?? 0)));
|
|
|
|
|
if ((int) ($GLOBALS['main_contact']['id'] ?? 0) <= 0 && isset($_SESSION['main_contact']) && is_array($_SESSION['main_contact'])) {
|
|
|
|
|
$GLOBALS['main_contact'] = $_SESSION['main_contact'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$conn = $GLOBALS['mysql_con'] ?? null;
|
|
|
|
|
if ($loginId > 0 && (int) ($GLOBALS['main_contact']['id'] ?? 0) <= 0 && $conn instanceof mysqli) {
|
|
|
|
|
try {
|
|
|
|
|
$stmt = $conn->prepare('SELECT * FROM main_contact WHERE id = ? LIMIT 1');
|
|
|
|
|
if ($stmt instanceof mysqli_stmt) {
|
|
|
|
|
$stmt->bind_param('i', $loginId);
|
|
|
|
|
$stmt->execute();
|
|
|
|
|
$result = $stmt->get_result();
|
|
|
|
|
if ($result instanceof mysqli_result) {
|
|
|
|
|
$row = $result->fetch_assoc();
|
|
|
|
|
if (is_array($row)) {
|
|
|
|
|
$GLOBALS['main_contact'] = $row;
|
|
|
|
|
}
|
|
|
|
|
$result->free();
|
|
|
|
|
}
|
|
|
|
|
$stmt->close();
|
|
|
|
|
}
|
|
|
|
|
} catch (Throwable $throwable) {
|
|
|
|
|
TaskCertLogger::warning('Fallback context: could not load main_contact', [
|
|
|
|
|
'login_id' => $loginId,
|
|
|
|
|
'exception' => $throwable,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((int) ($GLOBALS['main_contact']['id'] ?? 0) > 0 && !isset($_SESSION['main_contact'])) {
|
|
|
|
|
$_SESSION['main_contact'] = $GLOBALS['main_contact'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!defined('TASK_CERT_BOOTSTRAPPED')) {
|
|
|
|
|
define('TASK_CERT_BOOTSTRAPPED', true);
|
|
|
|
|
|
|
|
|
|
$taskCertModuleDir = __DIR__;
|
|
|
|
|
$rootCandidates = [
|
|
|
|
|
dirname(dirname($taskCertModuleDir)),
|
|
|
|
|
dirname($taskCertModuleDir),
|
|
|
|
|
$taskCertModuleDir,
|
|
|
|
|
];
|
|
|
|
|
$rootDir = $rootCandidates[0];
|
|
|
|
|
foreach ($rootCandidates as $candidate) {
|
|
|
|
|
if (
|
|
|
|
|
file_exists($candidate . '/mysyde/frontend/frontend_functions.inc.php') ||
|
|
|
|
|
file_exists($candidate . '/vendor/autoload.php') ||
|
|
|
|
|
is_dir($candidate . '/config')
|
|
|
|
|
) {
|
|
|
|
|
$rootDir = $candidate;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!defined('TASK_CERT_USERDATA_DIR')) {
|
|
|
|
|
define('TASK_CERT_USERDATA_DIR', $rootDir . '/userdata');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$autoloadFile = $rootDir . '/vendor/autoload.php';
|
|
|
|
|
if (file_exists($autoloadFile)) {
|
|
|
|
|
require_once $autoloadFile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$frontendFunctions = $rootDir . '/mysyde/frontend/frontend_functions.inc.php';
|
|
|
|
|
if (file_exists($frontendFunctions)) {
|
|
|
|
|
require_once $frontendFunctions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$commonFunctions = $rootDir . '/mysyde/common/common_functions.inc.php';
|
|
|
|
|
if (file_exists($commonFunctions)) {
|
|
|
|
|
require_once $commonFunctions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$intranetFunctionCandidates = [
|
|
|
|
|
$rootDir . '/mysyde/intranet/intranet_functions.inc.php',
|
|
|
|
|
$rootDir . '/mysyde/frontend/intranet_functions.inc.php',
|
|
|
|
|
$rootDir . '/intranet_functions.inc.php',
|
|
|
|
|
];
|
|
|
|
|
foreach ($intranetFunctionCandidates as $intranetFunctions) {
|
|
|
|
|
if (file_exists($intranetFunctions)) {
|
|
|
|
|
require_once $intranetFunctions;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$envDir = $rootDir . '/config';
|
|
|
|
|
$envFile = $envDir . '/.env';
|
|
|
|
|
if (is_dir($envDir) && file_exists($envFile) && class_exists('\Dotenv\Dotenv')) {
|
|
|
|
|
$dotenv = new \Dotenv\Dotenv($envDir);
|
|
|
|
|
$dotenv->load();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$connEnv = null;
|
|
|
|
|
if (function_exists('local_environment')) {
|
|
|
|
|
$connEnv = local_environment()
|
|
|
|
|
? $rootDir . '/mysyde/dc.config.php'
|
|
|
|
|
: $rootDir . '/mysyde/dc-server.config.php';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($connEnv !== null && file_exists($connEnv)) {
|
|
|
|
|
require_once $connEnv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$startIncPath = $rootDir . '/mysyde/frontend/start.inc.php';
|
|
|
|
|
$startIncMode = strtolower(trim((string) (getenv('TASK_CERT_BOOTSTRAP_START_INC') ?: ($_ENV['TASK_CERT_BOOTSTRAP_START_INC'] ?? 'auto'))));
|
|
|
|
|
$shouldLoadStartInc = false;
|
|
|
|
|
|
|
|
|
|
if ($startIncMode === 'always' || task_cert_bootstrap_truthy($startIncMode)) {
|
|
|
|
|
$shouldLoadStartInc = true;
|
|
|
|
|
} elseif (in_array($startIncMode, ['never', '0', 'false', 'off'], true)) {
|
|
|
|
|
$shouldLoadStartInc = false;
|
|
|
|
|
} else {
|
|
|
|
|
// Auto mode: include start.inc for view-like requests, skip for direct endpoint calls.
|
|
|
|
|
$shouldLoadStartInc = !task_cert_is_endpoint_request();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!task_cert_has_monolith_context() && $shouldLoadStartInc && file_exists($startIncPath)) {
|
|
|
|
|
try {
|
|
|
|
|
require_once $startIncPath;
|
|
|
|
|
TaskCertLogger::info('Monolith start.inc included', [
|
|
|
|
|
'path' => $startIncPath,
|
|
|
|
|
'mode' => $startIncMode,
|
|
|
|
|
'request_uri' => (string) ($_SERVER['REQUEST_URI'] ?? ''),
|
|
|
|
|
]);
|
|
|
|
|
} catch (Throwable $throwable) {
|
|
|
|
|
TaskCertLogger::warning('Monolith start.inc include failed, continuing with fallback', [
|
|
|
|
|
'path' => $startIncPath,
|
|
|
|
|
'mode' => $startIncMode,
|
|
|
|
|
'exception' => $throwable,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (session_status() === PHP_SESSION_NONE) {
|
2026-06-22 13:56:17 +02:00
|
|
|
// Endpoint-Requests überspringen start.inc.php (kein session_name-Setup durch den Monolith).
|
|
|
|
|
// Cookie-Detection stellt sicher, dass wir dieselbe Session wie der Monolith verwenden
|
|
|
|
|
// (Monolith setzt den Session-Namen auf "sid{site_code}", z.B. "sidawo").
|
|
|
|
|
if (session_name() === 'PHPSESSID') {
|
|
|
|
|
foreach (array_keys($_COOKIE) as $_tc_sn) {
|
|
|
|
|
if (strncmp($_tc_sn, 'sid', 3) === 0) {
|
|
|
|
|
session_name($_tc_sn);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unset($_tc_sn);
|
|
|
|
|
}
|
Module tasks + knowledgecenter_update aus Kundenprojekt übernehmen (bereinigt)
Beide Module wurden aus einem anderen Kundenprojekt kopiert und bereinigt:
Knowledgecenter:
- Bild-Cache (1.985 Dateien) geleert, Ordnerstruktur mit .gitkeep behalten
- Files-Gallery-Lizenzschlüssel entfernt (config.php)
- Kundenspezifische Kategorien gelöscht: Teil I/II/III QM-Struktur,
nummerierte QM-Kapitel, Gremien (Präsidium/Finanzausschuss/Landesausschuss),
Sitzungsservice-Serie, Protokoll-Abteilungen, Testeinträge
- 56 generische Kategorien bleiben (Downloads, Onboarding, Personalthemen …)
Tasks:
- Alle Betriebsdaten gelöscht (114 Tasks, 914 Submissions, 579 Assignments)
- Task-Definitionen und Verlinkungen geleert
- Kategoriestruktur bleibt (Allgemein, IT, Personal, Buchhaltung …)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 09:20:02 +02:00
|
|
|
session_start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$dbConnectError = '';
|
|
|
|
|
if (!isset($GLOBALS['mysql_con']) || !($GLOBALS['mysql_con'] instanceof mysqli)) {
|
|
|
|
|
if (function_exists('db_connect')) {
|
|
|
|
|
try {
|
|
|
|
|
db_connect();
|
|
|
|
|
} catch (Throwable $throwable) {
|
|
|
|
|
$dbConnectError = $throwable->getMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isset($GLOBALS['mysql_con']) || !($GLOBALS['mysql_con'] instanceof mysqli)) {
|
|
|
|
|
mysqli_report(MYSQLI_REPORT_OFF);
|
|
|
|
|
$mysqlCon = @mysqli_connect(
|
|
|
|
|
getenv('MAIN_MYSQL_DB_HOST') ?: '127.0.0.1',
|
|
|
|
|
getenv('MAIN_MYSQL_DB_USER') ?: '',
|
|
|
|
|
getenv('MAIN_MYSQL_DB_PASS') ?: '',
|
|
|
|
|
getenv('MAIN_MYSQL_DB_SCHEMA') ?: '',
|
|
|
|
|
(int) (getenv('MAIN_MYSQL_DB_PORT') ?: 3306)
|
|
|
|
|
);
|
|
|
|
|
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
|
|
|
|
|
|
|
|
|
|
if ($mysqlCon) {
|
|
|
|
|
mysqli_set_charset($mysqlCon, 'utf8mb4');
|
|
|
|
|
$GLOBALS['mysql_con'] = $mysqlCon;
|
|
|
|
|
} else {
|
|
|
|
|
$driverError = mysqli_connect_error();
|
|
|
|
|
$errorParts = [];
|
|
|
|
|
|
|
|
|
|
if ($dbConnectError !== '') {
|
|
|
|
|
$errorParts[] = 'Legacy-Connector: ' . $dbConnectError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($driverError !== '') {
|
|
|
|
|
$errorParts[] = 'mysqli: ' . $driverError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$details = $errorParts !== [] ? ' Details: ' . implode(' | ', $errorParts) : '';
|
|
|
|
|
$message = 'task_cert: Datenbankverbindung konnte nicht aufgebaut werden.' . $details;
|
|
|
|
|
|
|
|
|
|
$GLOBALS['task_cert_bootstrap_warning'] = $message;
|
|
|
|
|
TaskCertLogger::error('Bootstrap DB connection failed', [
|
|
|
|
|
'message' => $message,
|
|
|
|
|
'db_connect_error' => $dbConnectError,
|
|
|
|
|
'mysqli_error' => $driverError,
|
|
|
|
|
]);
|
|
|
|
|
task_cert_bootstrap_output_warning($message);
|
|
|
|
|
exit(PHP_SAPI === 'cli' ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!task_cert_has_monolith_context()) {
|
|
|
|
|
task_cert_bootstrap_context_fallback();
|
|
|
|
|
TaskCertLogger::info('Monolith context fallback applied', [
|
|
|
|
|
'site_code' => (string) ($GLOBALS['site']['code'] ?? ''),
|
|
|
|
|
'language_code' => (string) ($GLOBALS['language']['code'] ?? ''),
|
|
|
|
|
'contact_id' => (int) ($GLOBALS['main_contact']['id'] ?? 0),
|
|
|
|
|
'request_uri' => (string) ($_SERVER['REQUEST_URI'] ?? ''),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require_once __DIR__ . '/lib/Db.php';
|
|
|
|
|
require_once __DIR__ . '/lib/AuthContext.php';
|
|
|
|
|
require_once __DIR__ . '/lib/Request.php';
|
|
|
|
|
require_once __DIR__ . '/lib/Response.php';
|
|
|
|
|
require_once __DIR__ . '/lib/View.php';
|
|
|
|
|
require_once __DIR__ . '/lib/Csrf.php';
|
|
|
|
|
require_once __DIR__ . '/lib/ContactPrefillColumns.php';
|
|
|
|
|
require_once __DIR__ . '/lib/CronHeartbeat.php';
|
|
|
|
|
require_once __DIR__ . '/lib/TaskCertConstants.php';
|
|
|
|
|
require_once __DIR__ . '/lib/TaskUploadPolicy.php';
|
|
|
|
|
require_once __DIR__ . '/lib/TaskUploadStorage.php';
|
|
|
|
|
require_once __DIR__ . '/lib/Html.php';
|
|
|
|
|
|
|
|
|
|
require_once __DIR__ . '/repo/TaskDefinitionRepository.php';
|
|
|
|
|
require_once __DIR__ . '/repo/TaskChangeLogRepository.php';
|
|
|
|
|
require_once __DIR__ . '/repo/TaskCategoryRepository.php';
|
|
|
|
|
require_once __DIR__ . '/repo/TaskCategoryChangeLogRepository.php';
|
|
|
|
|
require_once __DIR__ . '/repo/TaskLookupRepository.php';
|
|
|
|
|
require_once __DIR__ . '/repo/TaskMonitoringRepository.php';
|
|
|
|
|
require_once __DIR__ . '/repo/TaskRuleRepository.php';
|
|
|
|
|
require_once __DIR__ . '/repo/TaskAssignmentRepository.php';
|
|
|
|
|
require_once __DIR__ . '/repo/TaskSubmissionRepository.php';
|
|
|
|
|
require_once __DIR__ . '/repo/TaskCertificateRepository.php';
|
|
|
|
|
|
|
|
|
|
require_once __DIR__ . '/service/TaskDefinitionService.php';
|
|
|
|
|
require_once __DIR__ . '/service/TaskCategoryService.php';
|
|
|
|
|
require_once __DIR__ . '/service/TaskLookupService.php';
|
|
|
|
|
require_once __DIR__ . '/service/TaskMonitoringService.php';
|
|
|
|
|
require_once __DIR__ . '/service/CycleCalculatorService.php';
|
|
|
|
|
require_once __DIR__ . '/service/AssignmentResolverService.php';
|
|
|
|
|
require_once __DIR__ . '/service/CompletionService.php';
|
|
|
|
|
require_once __DIR__ . '/service/ApprovalService.php';
|
|
|
|
|
require_once __DIR__ . '/service/CertificateService.php';
|
|
|
|
|
require_once __DIR__ . '/service/EscalationService.php';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_services(): array
|
|
|
|
|
{
|
|
|
|
|
static $services = null;
|
|
|
|
|
|
|
|
|
|
if ($services !== null) {
|
|
|
|
|
return $services;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$definitionRepo = new TaskDefinitionRepository();
|
|
|
|
|
$changeLogRepo = new TaskChangeLogRepository();
|
|
|
|
|
$taskCategoryRepo = new TaskCategoryRepository();
|
|
|
|
|
$taskCategoryChangeLogRepo = new TaskCategoryChangeLogRepository();
|
|
|
|
|
$lookupRepo = new TaskLookupRepository();
|
|
|
|
|
$monitoringRepo = new TaskMonitoringRepository();
|
|
|
|
|
$ruleRepo = new TaskRuleRepository();
|
|
|
|
|
$assignmentRepo = new TaskAssignmentRepository();
|
|
|
|
|
$submissionRepo = new TaskSubmissionRepository();
|
|
|
|
|
$certificateRepo = new TaskCertificateRepository();
|
|
|
|
|
$cycleCalculatorService = new CycleCalculatorService();
|
|
|
|
|
|
|
|
|
|
$certificateService = new CertificateService(
|
|
|
|
|
$certificateRepo,
|
|
|
|
|
$assignmentRepo,
|
|
|
|
|
$definitionRepo,
|
|
|
|
|
$cycleCalculatorService
|
|
|
|
|
);
|
|
|
|
|
$assignmentResolverService = new AssignmentResolverService(
|
|
|
|
|
$definitionRepo,
|
|
|
|
|
$ruleRepo,
|
|
|
|
|
$assignmentRepo,
|
|
|
|
|
$submissionRepo,
|
|
|
|
|
$certificateRepo,
|
|
|
|
|
$cycleCalculatorService,
|
|
|
|
|
$changeLogRepo
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$taskDefinitionService = new TaskDefinitionService(
|
|
|
|
|
$definitionRepo,
|
|
|
|
|
$taskCategoryRepo,
|
|
|
|
|
$ruleRepo,
|
|
|
|
|
$assignmentRepo,
|
|
|
|
|
$submissionRepo,
|
|
|
|
|
$certificateRepo,
|
|
|
|
|
$cycleCalculatorService,
|
|
|
|
|
$assignmentResolverService,
|
|
|
|
|
$changeLogRepo
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$completionService = new CompletionService(
|
|
|
|
|
$ruleRepo,
|
|
|
|
|
$assignmentRepo,
|
|
|
|
|
$submissionRepo,
|
|
|
|
|
$certificateService,
|
|
|
|
|
$definitionRepo,
|
|
|
|
|
$assignmentResolverService
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$services = [
|
|
|
|
|
'definitionRepo' => $definitionRepo,
|
|
|
|
|
'taskCategoryRepo' => $taskCategoryRepo,
|
|
|
|
|
'taskCategoryChangeLogRepo' => $taskCategoryChangeLogRepo,
|
|
|
|
|
'lookupRepo' => $lookupRepo,
|
|
|
|
|
'changeLogRepo' => $changeLogRepo,
|
|
|
|
|
'monitoringRepo' => $monitoringRepo,
|
|
|
|
|
'ruleRepo' => $ruleRepo,
|
|
|
|
|
'assignmentRepo' => $assignmentRepo,
|
|
|
|
|
'submissionRepo' => $submissionRepo,
|
|
|
|
|
'certificateRepo' => $certificateRepo,
|
|
|
|
|
'cycleCalculatorService' => $cycleCalculatorService,
|
|
|
|
|
'taskCategoryService' => new TaskCategoryService(
|
|
|
|
|
$taskCategoryRepo,
|
|
|
|
|
$taskCategoryChangeLogRepo
|
|
|
|
|
),
|
|
|
|
|
'lookupService' => new TaskLookupService($lookupRepo),
|
|
|
|
|
'taskMonitoringService' => new TaskMonitoringService(
|
|
|
|
|
$monitoringRepo,
|
|
|
|
|
$cycleCalculatorService,
|
|
|
|
|
$ruleRepo
|
|
|
|
|
),
|
|
|
|
|
'taskDefinitionService' => $taskDefinitionService,
|
|
|
|
|
'assignmentResolverService' => $assignmentResolverService,
|
|
|
|
|
'completionService' => $completionService,
|
|
|
|
|
'approvalService' => new ApprovalService(
|
|
|
|
|
$submissionRepo,
|
|
|
|
|
$assignmentRepo,
|
|
|
|
|
$completionService
|
|
|
|
|
),
|
|
|
|
|
'certificateService' => $certificateService,
|
|
|
|
|
'escalationService' => new EscalationService(
|
|
|
|
|
$assignmentRepo,
|
|
|
|
|
$ruleRepo,
|
|
|
|
|
$changeLogRepo
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return $services;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_asset_url(string $relativeAssetPath): string
|
|
|
|
|
{
|
|
|
|
|
$cleanPath = ltrim($relativeAssetPath, '/');
|
|
|
|
|
return task_cert_url('assets/' . $cleanPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_base_url(): string
|
|
|
|
|
{
|
|
|
|
|
static $baseUrl = null;
|
|
|
|
|
|
|
|
|
|
if ($baseUrl !== null) {
|
|
|
|
|
return $baseUrl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$configured = (string) (getenv('TASK_CERT_BASE_URL') ?: ($_ENV['TASK_CERT_BASE_URL'] ?? ''));
|
|
|
|
|
if (trim($configured) === '') {
|
|
|
|
|
$configured = '/module/tasks';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$configured = '/' . trim($configured, '/');
|
|
|
|
|
$baseUrl = ($configured === '/') ? '' : $configured;
|
|
|
|
|
|
|
|
|
|
return $baseUrl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_site_code(): string
|
|
|
|
|
{
|
|
|
|
|
$siteCode = '';
|
|
|
|
|
|
|
|
|
|
$siteGlobal = $GLOBALS['site'] ?? null;
|
|
|
|
|
if (is_array($siteGlobal)) {
|
|
|
|
|
$siteCode = (string) ($siteGlobal['code'] ?? ($siteGlobal['site_code'] ?? ''));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($siteCode === '') {
|
|
|
|
|
$siteCode = (string) ($GLOBALS['site_code'] ?? '');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($siteCode === '' && isset($_SESSION['site']) && is_array($_SESSION['site'])) {
|
|
|
|
|
$siteCode = (string) ($_SESSION['site']['code'] ?? ($_SESSION['site']['site_code'] ?? ''));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($siteCode === '') {
|
|
|
|
|
$siteCode = (string) ($_SESSION['site_code'] ?? '');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($siteCode === '') {
|
|
|
|
|
if (!task_cert_is_endpoint_request()) {
|
|
|
|
|
$requestPath = (string) parse_url((string) ($_SERVER['REQUEST_URI'] ?? ''), PHP_URL_PATH);
|
|
|
|
|
$segments = array_values(array_filter(explode('/', trim($requestPath, '/'))));
|
|
|
|
|
if (isset($segments[0])) {
|
|
|
|
|
$siteCode = (string) $segments[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$siteCode = strtolower(trim($siteCode));
|
|
|
|
|
$siteCode = preg_replace('/[^a-z0-9_-]/', '', $siteCode) ?? '';
|
|
|
|
|
|
|
|
|
|
return $siteCode !== '' ? $siteCode : 'intranet';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_language_code(): string
|
|
|
|
|
{
|
|
|
|
|
$languageCode = '';
|
|
|
|
|
|
|
|
|
|
$languageGlobal = $GLOBALS['language'] ?? null;
|
|
|
|
|
if (is_array($languageGlobal)) {
|
|
|
|
|
$languageCode = (string) ($languageGlobal['code'] ?? '');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($languageCode === '' && isset($_SESSION['language']) && is_array($_SESSION['language'])) {
|
|
|
|
|
$languageCode = (string) ($_SESSION['language']['code'] ?? '');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($languageCode === '') {
|
|
|
|
|
$languageCode = (string) ($GLOBALS['language_code'] ?? ($_SESSION['language_code'] ?? ''));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($languageCode === '') {
|
|
|
|
|
if (!task_cert_is_endpoint_request()) {
|
|
|
|
|
$requestPath = (string) parse_url((string) ($_SERVER['REQUEST_URI'] ?? ''), PHP_URL_PATH);
|
|
|
|
|
$segments = array_values(array_filter(explode('/', trim($requestPath, '/'))));
|
|
|
|
|
if (isset($segments[1])) {
|
|
|
|
|
$languageCode = (string) $segments[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$languageCode = strtolower(trim($languageCode));
|
|
|
|
|
$languageCode = preg_replace('/[^a-z0-9_-]/', '', $languageCode) ?? '';
|
|
|
|
|
|
|
|
|
|
return $languageCode !== '' ? $languageCode : 'de';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_view_base_url(): string
|
|
|
|
|
{
|
|
|
|
|
static $baseUrl = null;
|
|
|
|
|
|
|
|
|
|
if ($baseUrl !== null) {
|
|
|
|
|
return $baseUrl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$configured = trim((string) (getenv('TASK_CERT_VIEW_BASE_URL') ?: ($_ENV['TASK_CERT_VIEW_BASE_URL'] ?? '')));
|
|
|
|
|
if ($configured !== '') {
|
|
|
|
|
$configured = '/' . trim($configured, '/');
|
|
|
|
|
$baseUrl = ($configured === '/') ? '' : $configured;
|
|
|
|
|
return $baseUrl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$slug = trim((string) (getenv('TASK_CERT_VIEW_SLUG') ?: ($_ENV['TASK_CERT_VIEW_SLUG'] ?? 'tasks-cert')));
|
|
|
|
|
$slug = strtolower($slug);
|
|
|
|
|
$slug = preg_replace('/[^a-z0-9_-]/', '', $slug) ?? '';
|
|
|
|
|
if ($slug === '') {
|
|
|
|
|
$slug = 'tasks-cert';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$baseUrl = '/' . task_cert_site_code() . '/' . task_cert_language_code() . '/' . $slug;
|
|
|
|
|
return $baseUrl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_view_url(string $viewKey = 'admin.task_list', array $query = []): string
|
|
|
|
|
{
|
|
|
|
|
$viewMap = [
|
|
|
|
|
'admin.task_list' => 'admin-task-list',
|
|
|
|
|
'admin.task_form' => 'edit',
|
|
|
|
|
'admin.task_detail' => 'view',
|
|
|
|
|
'admin.approval_queue' => 'approvals',
|
|
|
|
|
'admin.escalation_dashboard' => 'escalations',
|
|
|
|
|
'admin.task_categories' => 'categories',
|
|
|
|
|
'user.my_tasks' => 'my-tasks',
|
|
|
|
|
'user.task_detail' => 'task',
|
|
|
|
|
'user.overdue_widget' => 'overdue-widget',
|
|
|
|
|
'user.summary_widget' => 'summary-widget',
|
|
|
|
|
'user.escalation_overlay_widget' => 'escalation-overlay-widget',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$relativePath = $viewMap[$viewKey] ?? trim($viewKey);
|
|
|
|
|
$base = rtrim(task_cert_view_base_url(), '/');
|
|
|
|
|
$cleanPath = trim((string) $relativePath, '/');
|
|
|
|
|
|
|
|
|
|
$url = $base;
|
|
|
|
|
if ($cleanPath !== '') {
|
|
|
|
|
$url .= '/' . $cleanPath . '/';
|
|
|
|
|
} else {
|
|
|
|
|
$url .= '/';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($viewKey === 'admin.task_detail' && !array_key_exists('route_guard', $query)) {
|
|
|
|
|
// Guard param prevents monolith route edge cases when URL ends with numeric query values.
|
|
|
|
|
$query['route_guard'] = 'load/';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($query !== []) {
|
|
|
|
|
$queryString = http_build_query($query);
|
|
|
|
|
if ($queryString !== '') {
|
|
|
|
|
$url .= '?' . $queryString;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $url;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_url(string $relativePath = ''): string
|
|
|
|
|
{
|
|
|
|
|
$base = task_cert_base_url();
|
|
|
|
|
$cleanPath = ltrim(trim($relativePath), '/');
|
|
|
|
|
|
|
|
|
|
if ($cleanPath === '') {
|
|
|
|
|
return $base === '' ? '/' : $base;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ($base === '' ? '' : $base) . '/' . $cleanPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_asset_versioned_url(string $relativeAssetPath): string
|
|
|
|
|
{
|
|
|
|
|
$cleanPath = ltrim($relativeAssetPath, '/');
|
|
|
|
|
$absolutePath = __DIR__ . '/assets/' . $cleanPath;
|
|
|
|
|
$version = file_exists($absolutePath) ? (string) filemtime($absolutePath) : (string) time();
|
|
|
|
|
return task_cert_asset_url($cleanPath) . '?v=' . rawurlencode($version);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_render_styles(array $variants = [], array $extraFiles = []): void
|
|
|
|
|
{
|
|
|
|
|
static $printed = [];
|
|
|
|
|
|
|
|
|
|
$files = [
|
|
|
|
|
'css/task_cert.css',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if (in_array('admin', $variants, true)) {
|
|
|
|
|
$files[] = 'css/task_cert_admin.css';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (in_array('user', $variants, true)) {
|
|
|
|
|
$files[] = 'css/task_cert_user.css';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$files = array_values(array_unique(array_merge($files, $extraFiles)));
|
|
|
|
|
|
|
|
|
|
foreach ($files as $file) {
|
|
|
|
|
if (isset($printed[$file])) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$href = task_cert_asset_versioned_url($file);
|
|
|
|
|
|
|
|
|
|
echo '<link rel="stylesheet" href="' . htmlspecialchars($href, ENT_QUOTES, 'UTF-8') . '">' . PHP_EOL;
|
|
|
|
|
$printed[$file] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function task_cert_render_scripts(array $files): void
|
|
|
|
|
{
|
|
|
|
|
static $printed = [];
|
|
|
|
|
|
|
|
|
|
foreach ($files as $file) {
|
|
|
|
|
$cleanFile = ltrim((string) $file, '/');
|
|
|
|
|
if ($cleanFile === '' || isset($printed[$cleanFile])) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$src = task_cert_asset_versioned_url($cleanFile);
|
|
|
|
|
echo '<script src="' . htmlspecialchars($src, ENT_QUOTES, 'UTF-8') . '" defer></script>' . PHP_EOL;
|
|
|
|
|
$printed[$cleanFile] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|