app = $app; $this->app->appName = 'Timerecording'; $this->config = $config; UriFactory::setQuery('/app', \strtolower($this->app->appName)); } /** * Rendering timerecording. * * @param HttpRequest $request Request * @param HttpResponse $response Response * * @return void * * @since 1.0.0 */ public function run(HttpRequest $request, HttpResponse $response) : void { $this->app->l11nManager = new L11nManager($this->app->appName); $pageView = new TimerecordingView($this->app->l11nManager, $request, $response); $head = new Head(); $pageView->setData('head', $head); $response->set('Content', $pageView); /* Timerecording only allows GET */ if ($request->getMethod() !== RequestMethod::GET) { $this->create406Response($response, $pageView); return; } $this->app->dbPool = new DatabasePool(); $this->app->router = new WebRouter(); $this->app->router->importFromFile(__DIR__ . '/Routes.php'); $this->app->router->add( '/timerecording/e403', function() use ($request, $response) { $view = new View($this->app->l11nManager, $request, $response); $view->setTemplate('/Web/Timerecording/Error/403_inline'); $response->getHeader()->setStatusCode(RequestStatusCode::R_403); return $view; }, RouteVerb::GET ); $this->app->sessionManager = new HttpSession(60); $this->app->cookieJar = new CookieJar(); $this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../Modules'); $this->app->dispatcher = new Dispatcher($this->app); $this->app->dbPool->create('select', $this->config['db']['core']['masters']['select']); /* Database OK? */ if ($this->app->dbPool->get()->getStatus() !== DatabaseStatus::OK) { $this->create503Response($response, $pageView); return; } /* CSRF token OK? */ if ($request->getData('CSRF') !== null && !\hash_equals($this->app->sessionManager->get('CSRF'), $request->getData('CSRF')) ) { $response->getHeader()->setStatusCode(RequestStatusCode::R_403); return; } /** @var ConnectionAbstract $con */ $con = $this->app->dbPool->get(); DataMapperAbstract::setConnection($con); $this->app->cachePool = new CachePool(); $this->app->appSettings = new CoreSettings($con); $this->app->eventManager = new EventManager($this->app->dispatcher); $this->app->accountManager = new AccountManager($this->app->sessionManager); $this->app->l11nServer = LocalizationMapper::get(1); $this->app->orgId = $this->getApplicationOrganization($request, $this->config); $pageView->setData('orgId', $this->app->orgId); $aid = Auth::authenticate($this->app->sessionManager); $request->getHeader()->setAccount($aid); $response->getHeader()->setAccount($aid); $account = $this->loadAccount($request); if (!($account instanceof NullAccount)) { $response->getHeader()->setL11n($account->getL11n()); } elseif ($this->app->sessionManager->get('language') !== null) { $response->getHeader()->getL11n() ->loadFromLanguage( $this->app->sessionManager->get('language'), $this->app->sessionManager->get('country') ?? '*' ); } elseif ($this->app->cookieJar->get('language') !== null) { $response->getHeader()->getL11n() ->loadFromLanguage( $this->app->cookieJar->get('language'), $this->app->cookieJar->get('country') ?? '*' ); } UriFactory::setQuery('/lang', $response->getHeader()->getL11n()->getLanguage()); $this->loadLanguageFromPath( $response->getHeader()->getL11n()->getLanguage(), __DIR__ . '/lang/' . $response->getHeader()->getL11n()->getLanguage() . '.lang.php' ); $response->getHeader()->set('content-language', $response->getHeader()->getL11n()->getLanguage(), true); /* Create html head */ $this->initResponseHead($head, $request, $response); /* Handle not logged in */ if ($account->getId() < 1) { $this->createLoggedOutResponse($response, $head, $pageView); return; } /* No reading permission */ if (!$account->hasPermission(PermissionType::READ, $this->app->orgId, $this->app->appName, 'Dashboard')) { $this->create403Response($response, $pageView); return; } $this->app->moduleManager->initRequestModules($request); $this->createDefaultPageView($request, $response, $pageView); $dispatched = $this->app->dispatcher->dispatch( $this->app->router->route( $request->getUri()->getRoute(), $request->getData('CSRF'), $request->getRouteVerb(), $this->app->appName, $this->app->orgId, $account, $request->getData() ), $request, $response ); $pageView->addData('dispatch', $dispatched); } /** * Get application organization * * @param HttpRequest $request Client request * @param array $config App config * * @return int Organization id * * @since 1.0.0 */ private function getApplicationOrganization(HttpRequest $request, array $config) : int { return (int) ( $request->getData('u') ?? ( $config['domains'][$request->getUri()->getHost()]['org'] ?? $this->app->appSettings->get( Settings::DEFAULT_ORGANIZATION ) ?? 1 ) ); } /** * Create 406 response. * * @param HttpResponse $response Response * @param View $pageView View * * @return void * * @since 1.0.0 */ private function create406Response(HttpResponse $response, View $pageView) : void { $response->getHeader()->setStatusCode(RequestStatusCode::R_406); $pageView->setTemplate('/Web/Timerecording/Error/406'); $this->loadLanguageFromPath( $response->getHeader()->getL11n()->getLanguage(), __DIR__ . '/Error/lang/' . $response->getHeader()->getL11n()->getLanguage() . '.lang.php' ); } /** * Create 406 response. * * @param HttpResponse $response Response * @param View $pageView View * * @return void * * @since 1.0.0 */ private function create503Response(HttpResponse $response, View $pageView) : void { $response->getHeader()->setStatusCode(RequestStatusCode::R_503); $pageView->setTemplate('/Web/Timerecording/Error/503'); $this->loadLanguageFromPath( $response->getHeader()->getL11n()->getLanguage(), __DIR__ . '/Error/lang/' . $response->getHeader()->getL11n()->getLanguage() . '.lang.php' ); } /** * Load theme language from path * * @param string $language Language name * @param string $path Language path * * @return void * * @since 1.0.0 */ private function loadLanguageFromPath(string $language, string $path) : void { /* Load theme language */ if (($absPath = \realpath($path)) === false) { throw new PathException($path); } /** @noinspection PhpIncludeInspection */ $themeLanguage = include $absPath; $this->app->l11nManager->loadLanguage($language, '0', $themeLanguage); } /** * Load permission * * @param HttpRequest $request Current request * * @return Account * * @since 1.0.0 */ private function loadAccount(HttpRequest $request) : Account { $account = AccountMapper::getWithPermissions($request->getHeader()->getAccount()); $this->app->accountManager->add($account); return $account; } /** * Create 406 response. * * @param HttpResponse $response Response * @param View $pageView View * * @return void * * @since 1.0.0 */ private function create403Response(HttpResponse $response, View $pageView) : void { $response->getHeader()->setStatusCode(RequestStatusCode::R_403); $pageView->setTemplate('/Web/Timerecording/Error/403'); $this->loadLanguageFromPath( $response->getHeader()->getL11n()->getLanguage(), __DIR__ . '/Error/lang/' . $response->getHeader()->getL11n()->getLanguage() . '.lang.php' ); } /** * Initialize response head * * @param Head $head Head to fill * @param HttpRequest $request Request * @param HttpResponse $response Response * * @return void * * @since 1.0.0 */ private function initResponseHead(Head $head, HttpRequest $request, HttpResponse $response) : void { /* Load assets */ $head->addAsset(AssetType::CSS, 'Resources/fontawesome/css/font-awesome.min.css'); $head->addAsset(AssetType::CSS, 'cssOMS/styles.css'); $head->addAsset(AssetType::CSS, '//fonts.googleapis.com/css?family=Roboto:100,300,300i,400,700,900'); // Framework $head->addAsset(AssetType::JS, 'jsOMS/Utils/oLib.js'); $head->addAsset(AssetType::JS, 'jsOMS/UnhandledException.js'); $head->addAsset(AssetType::JS, 'Web/Timerecording/js/timerecording.js', ['type' => 'module']); $head->addAsset(AssetType::JSLATE, 'Modules/Navigation/Controller.js', ['type' => 'module']); $script = ''; $response->getHeader()->set( 'content-security-policy', 'base-uri \'self\'; script-src \'self\' blob: \'sha256-' . \base64_encode(\hash('sha256', $script, true)) . '\'; worker-src \'self\'', true ); if ($request->hasData('debug')) { $head->addAsset(AssetType::CSS, 'cssOMS/debug.css'); } $css = \file_get_contents(__DIR__ . '/css/timerecording-small.css'); if ($css === false) { $css = ''; } $css = \preg_replace('!\s+!', ' ', $css); $head->setStyle('core', $css ?? ''); $head->setTitle('Orange Management Timerecording'); } /** * Create logged out response * * @param HttpResponse $response Response * @param Head $head Head to fill * @param View $pageView View * * @return void * * @since 1.0.0 */ private function createLoggedOutResponse(HttpResponse $response, Head $head, View $pageView) : void { $response->getHeader()->setStatusCode(RequestStatusCode::R_403); $pageView->setTemplate('/Web/Timerecording/login'); $head->addAsset(AssetType::JS, 'Web/Timerecording/js/login.js', ['type' => 'module']); } /** * Create default page view * * @param HttpRequest $request Request * @param HttpResponse $response Response * @param TimerecordingView $pageView View * * @return void * * @since 1.0.0 */ private function createDefaultPageView(HttpRequest $request, HttpResponse $response, TimerecordingView $pageView) : void { $pageView->setOrganizations(UnitMapper::getAll()); $pageView->setProfile(ProfileMapper::getFor($request->getHeader()->getAccount(), 'account')); $pageView->setData('nav', $this->getNavigation($request, $response)); $pageView->setTemplate('/Web/Timerecording/index'); } /** * Create navigation * * @param HttpRequest $request Request * @param HttpResponse $response Response * * @return View * * @since 1.0.0 */ private function getNavigation(HttpRequest $request, HttpResponse $response) : View { /** @var \Modules\Navigation\Controller\TimerecordingController $navController */ $navController = $this->app->moduleManager->get('Navigation'); $navController->loadLanguage($request, $response); return $navController->getView($request, $response); } }