vendor/pimcore/pimcore/bundles/AdminBundle/Controller/Admin/IndexController.php line 77

Open in your IDE?
  1. <?php
  2. /**
  3. * Pimcore
  4. *
  5. * This source file is available under two different licenses:
  6. * - GNU General Public License version 3 (GPLv3)
  7. * - Pimcore Commercial License (PCL)
  8. * Full copyright and license information is available in
  9. * LICENSE.md which is distributed with this source code.
  10. *
  11. * @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12. * @license http://www.pimcore.org/license GPLv3 and PCL
  13. */
  14. namespace Pimcore\Bundle\AdminBundle\Controller\Admin;
  15. use Pimcore\Analytics\Google\Config\SiteConfigProvider;
  16. use Pimcore\Bundle\AdminBundle\Controller\AdminController;
  17. use Pimcore\Bundle\AdminBundle\HttpFoundation\JsonResponse;
  18. use Pimcore\Bundle\AdminBundle\Security\CsrfProtectionHandler;
  19. use Pimcore\Config;
  20. use Pimcore\Controller\KernelResponseEventInterface;
  21. use Pimcore\Db\ConnectionInterface;
  22. use Pimcore\Event\Admin\IndexActionSettingsEvent;
  23. use Pimcore\Event\AdminEvents;
  24. use Pimcore\Extension\Bundle\PimcoreBundleManager;
  25. use Pimcore\Google;
  26. use Pimcore\Maintenance\Executor;
  27. use Pimcore\Maintenance\ExecutorInterface;
  28. use Pimcore\Model\Element\Service;
  29. use Pimcore\Model\User;
  30. use Pimcore\Tool;
  31. use Pimcore\Tool\Admin;
  32. use Pimcore\Tool\Session;
  33. use Pimcore\Version;
  34. use Symfony\Component\HttpFoundation\Request;
  35. use Symfony\Component\HttpFoundation\Response;
  36. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  37. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  38. use Symfony\Component\HttpKernel\KernelInterface;
  39. use Symfony\Component\Routing\Annotation\Route;
  40. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  41. /**
  42. * @internal
  43. */
  44. class IndexController extends AdminController implements KernelResponseEventInterface
  45. {
  46. /**
  47. * @var EventDispatcherInterface
  48. */
  49. private $eventDispatcher;
  50. /**
  51. * @param EventDispatcherInterface $eventDispatcher
  52. */
  53. public function __construct(EventDispatcherInterface $eventDispatcher)
  54. {
  55. $this->eventDispatcher = $eventDispatcher;
  56. }
  57. /**
  58. * @Route("/", name="pimcore_admin_index", methods={"GET"})
  59. *
  60. * @param Request $request
  61. * @param SiteConfigProvider $siteConfigProvider
  62. * @param KernelInterface $kernel
  63. * @param Executor $maintenanceExecutor
  64. * @param CsrfProtectionHandler $csrfProtection
  65. * @param Config $config
  66. *
  67. * @return Response
  68. *
  69. * @throws \Exception
  70. */
  71. public function indexAction(
  72. Request $request,
  73. SiteConfigProvider $siteConfigProvider,
  74. KernelInterface $kernel,
  75. Executor $maintenanceExecutor,
  76. CsrfProtectionHandler $csrfProtection,
  77. Config $config
  78. ) {
  79. $user = $this->getAdminUser();
  80. $templateParams = [
  81. 'config' => $config,
  82. ];
  83. $this
  84. ->addRuntimePerspective($templateParams, $user)
  85. ->addPluginAssets($templateParams);
  86. $this->buildPimcoreSettings($request, $templateParams, $user, $kernel, $maintenanceExecutor, $csrfProtection, $siteConfigProvider);
  87. if ($user->getTwoFactorAuthentication('required') && !$user->getTwoFactorAuthentication('enabled')) {
  88. // only one login is allowed to setup 2FA by the user himself
  89. $user->setTwoFactorAuthentication('enabled', true);
  90. // disable the 2FA prompt for the current session
  91. Tool\Session::useSession(function (AttributeBagInterface $adminSession) {
  92. $adminSession->set('2fa_required', false);
  93. });
  94. $user->save();
  95. $templateParams['settings']['twoFactorSetupRequired'] = true;
  96. }
  97. // allow to alter settings via an event
  98. $settingsEvent = new IndexActionSettingsEvent($templateParams['settings'] ?? []);
  99. $this->eventDispatcher->dispatch($settingsEvent, AdminEvents::INDEX_ACTION_SETTINGS);
  100. $templateParams['settings'] = $settingsEvent->getSettings();
  101. return $this->render('@PimcoreAdmin/Admin/Index/index.html.twig', $templateParams);
  102. }
  103. /**
  104. * @Route("/index/statistics", name="pimcore_admin_index_statistics", methods={"GET"})
  105. *
  106. * @param Request $request
  107. * @param ConnectionInterface $db
  108. * @param KernelInterface $kernel
  109. *
  110. * @return JsonResponse
  111. *
  112. * @throws \Exception
  113. */
  114. public function statisticsAction(Request $request, ConnectionInterface $db, KernelInterface $kernel)
  115. {
  116. // DB
  117. try {
  118. $tables = $db->fetchAll('SELECT TABLE_NAME as name,TABLE_ROWS as `rows` from information_schema.TABLES
  119. WHERE TABLE_ROWS IS NOT NULL AND TABLE_SCHEMA = ?', [$db->getDatabase()]);
  120. } catch (\Exception $e) {
  121. $tables = [];
  122. }
  123. try {
  124. $mysqlVersion = $db->fetchOne('SELECT VERSION()');
  125. } catch (\Exception $e) {
  126. $mysqlVersion = null;
  127. }
  128. try {
  129. $data = [
  130. 'instanceId' => $this->getInstanceId(),
  131. 'pimcore_major_version' => 10,
  132. 'pimcore_version' => Version::getVersion(),
  133. 'pimcore_hash' => Version::getRevision(),
  134. 'php_version' => PHP_VERSION,
  135. 'mysql_version' => $mysqlVersion,
  136. 'bundles' => array_keys($kernel->getBundles()),
  137. 'tables' => $tables,
  138. ];
  139. } catch (\Exception $e) {
  140. $data = [];
  141. }
  142. return $this->adminJson($data);
  143. }
  144. /**
  145. * @param array $templateParams
  146. * @param User $user
  147. *
  148. * @return $this
  149. */
  150. protected function addRuntimePerspective(array &$templateParams, User $user)
  151. {
  152. $runtimePerspective = Config::getRuntimePerspective($user);
  153. $templateParams['runtimePerspective'] = $runtimePerspective;
  154. return $this;
  155. }
  156. /**
  157. * @param array $templateParams
  158. *
  159. * @return $this
  160. */
  161. protected function addPluginAssets(array &$templateParams)
  162. {
  163. $bundleManager = $this->get(PimcoreBundleManager::class);
  164. $templateParams['pluginJsPaths'] = $bundleManager->getJsPaths();
  165. $templateParams['pluginCssPaths'] = $bundleManager->getCssPaths();
  166. return $this;
  167. }
  168. /**
  169. * @param Request $request
  170. * @param array $templateParams
  171. * @param User $user
  172. * @param KernelInterface $kernel
  173. * @param ExecutorInterface $maintenanceExecutor
  174. * @param CsrfProtectionHandler $csrfProtection
  175. * @param SiteConfigProvider $siteConfigProvider
  176. *
  177. * @return $this
  178. */
  179. protected function buildPimcoreSettings(Request $request, array &$templateParams, User $user, KernelInterface $kernel, ExecutorInterface $maintenanceExecutor, CsrfProtectionHandler $csrfProtection, SiteConfigProvider $siteConfigProvider)
  180. {
  181. $config = $templateParams['config'];
  182. $dashboardHelper = new \Pimcore\Helper\Dashboard($user);
  183. $settings = [
  184. 'instanceId' => $this->getInstanceId(),
  185. 'version' => Version::getVersion(),
  186. 'build' => Version::getRevision(),
  187. 'debug' => \Pimcore::inDebugMode(),
  188. 'devmode' => \Pimcore::inDevMode(),
  189. 'disableMinifyJs' => \Pimcore::disableMinifyJs(),
  190. 'environment' => $kernel->getEnvironment(),
  191. 'cached_environments' => Tool::getCachedSymfonyEnvironments(),
  192. 'sessionId' => htmlentities(Session::getSessionId(), ENT_QUOTES, 'UTF-8'),
  193. // languages
  194. 'language' => $request->getLocale(),
  195. 'websiteLanguages' => Admin::reorderWebsiteLanguages(
  196. $this->getAdminUser(),
  197. $config['general']['valid_languages'],
  198. true
  199. ),
  200. // flags
  201. 'showCloseConfirmation' => true,
  202. 'debug_admin_translations' => (bool)$config['general']['debug_admin_translations'],
  203. 'document_generatepreviews' => (bool)$config['documents']['generate_preview'],
  204. 'asset_disable_tree_preview' => (bool)$config['assets']['disable_tree_preview'],
  205. 'htmltoimage' => \Pimcore\Image\HtmlToImage::isSupported(),
  206. 'videoconverter' => \Pimcore\Video::isAvailable(),
  207. 'asset_hide_edit' => (bool)$config['assets']['hide_edit_image'],
  208. 'main_domain' => $config['general']['domain'],
  209. 'timezone' => $config['general']['timezone'],
  210. 'tile_layer_url_template' => $config['maps']['tile_layer_url_template'],
  211. 'geocoding_url_template' => $config['maps']['geocoding_url_template'],
  212. 'reverse_geocoding_url_template' => $config['maps']['reverse_geocoding_url_template'],
  213. 'asset_tree_paging_limit' => $config['assets']['tree_paging_limit'],
  214. 'document_tree_paging_limit' => $config['documents']['tree_paging_limit'],
  215. 'object_tree_paging_limit' => $config['objects']['tree_paging_limit'],
  216. 'maxmind_geoip_installed' => (bool) $this->getParameter('pimcore.geoip.db_file'),
  217. 'hostname' => htmlentities(\Pimcore\Tool::getHostname(), ENT_QUOTES, 'UTF-8'),
  218. 'document_auto_save_interval' => $config['documents']['auto_save_interval'],
  219. 'object_auto_save_interval' => $config['objects']['auto_save_interval'],
  220. // perspective and portlets
  221. 'perspective' => $templateParams['runtimePerspective'],
  222. 'availablePerspectives' => Config::getAvailablePerspectives($user),
  223. 'disabledPortlets' => $dashboardHelper->getDisabledPortlets(),
  224. // google analytics
  225. 'google_analytics_enabled' => (bool) $siteConfigProvider->isSiteReportingConfigured(),
  226. ];
  227. $this
  228. ->addSystemVarSettings($settings)
  229. ->addMaintenanceSettings($settings, $maintenanceExecutor)
  230. ->addMailSettings($settings, $config)
  231. ->addCustomViewSettings($settings);
  232. $settings['csrfToken'] = $csrfProtection->getCsrfToken();
  233. $templateParams['settings'] = $settings;
  234. return $this;
  235. }
  236. /**
  237. * @return string
  238. */
  239. private function getInstanceId()
  240. {
  241. $instanceId = 'not-set';
  242. try {
  243. $instanceId = $this->getParameter('secret');
  244. $instanceId = sha1(substr($instanceId, 3, -3));
  245. } catch (\Exception $e) {
  246. // nothing to do
  247. }
  248. return $instanceId;
  249. }
  250. /**
  251. * @param array $settings
  252. *
  253. * @return $this
  254. */
  255. protected function addSystemVarSettings(array &$settings)
  256. {
  257. // upload limit
  258. $max_upload = filesize2bytes(ini_get('upload_max_filesize') . 'B');
  259. $max_post = filesize2bytes(ini_get('post_max_size') . 'B');
  260. $upload_mb = min($max_upload, $max_post);
  261. $settings['upload_max_filesize'] = (int) $upload_mb;
  262. // session lifetime (gc)
  263. $session_gc_maxlifetime = ini_get('session.gc_maxlifetime');
  264. if (empty($session_gc_maxlifetime)) {
  265. $session_gc_maxlifetime = 120;
  266. }
  267. $settings['session_gc_maxlifetime'] = (int)$session_gc_maxlifetime;
  268. return $this;
  269. }
  270. /**
  271. * @param array $settings
  272. * @param ExecutorInterface $maintenanceExecutor
  273. *
  274. * @return $this
  275. */
  276. protected function addMaintenanceSettings(array &$settings, ExecutorInterface $maintenanceExecutor)
  277. {
  278. // check maintenance
  279. $maintenance_active = false;
  280. if ($lastExecution = $maintenanceExecutor->getLastExecution()) {
  281. if ((time() - $lastExecution) < 3660) { // maintenance script should run at least every hour + a little tolerance
  282. $maintenance_active = true;
  283. }
  284. }
  285. $settings['maintenance_active'] = $maintenance_active;
  286. $settings['maintenance_mode'] = Admin::isInMaintenanceMode();
  287. return $this;
  288. }
  289. /**
  290. * @param array $settings
  291. * @param Config $config
  292. *
  293. * @return $this
  294. */
  295. protected function addMailSettings(array &$settings, $config)
  296. {
  297. //mail settings
  298. $mailIncomplete = false;
  299. if (isset($config['email'])) {
  300. if (empty($config['email']['debug']['email_addresses'])) {
  301. $mailIncomplete = true;
  302. }
  303. if (empty($config['email']['sender']['email'])) {
  304. $mailIncomplete = true;
  305. }
  306. }
  307. $settings['mail'] = !$mailIncomplete;
  308. $settings['mailDefaultAddress'] = $config['email']['sender']['email'] ?? null;
  309. return $this;
  310. }
  311. /**
  312. * @param array $settings
  313. *
  314. * @return $this
  315. */
  316. protected function addCustomViewSettings(array &$settings)
  317. {
  318. $cvData = [];
  319. // still needed when publishing objects
  320. $cvConfig = Tool::getCustomViewConfig();
  321. if ($cvConfig) {
  322. foreach ($cvConfig as $node) {
  323. $tmpData = $node;
  324. // backwards compatibility
  325. $treeType = $tmpData['treetype'] ? $tmpData['treetype'] : 'object';
  326. $rootNode = Service::getElementByPath($treeType, $tmpData['rootfolder']);
  327. if ($rootNode) {
  328. $tmpData['rootId'] = $rootNode->getId();
  329. $tmpData['allowedClasses'] = $tmpData['classes'] ?? null;
  330. $tmpData['showroot'] = (bool)$tmpData['showroot'];
  331. // Check if a user has privileges to that node
  332. if ($rootNode->isAllowed('list')) {
  333. $cvData[] = $tmpData;
  334. }
  335. }
  336. }
  337. }
  338. $settings['customviews'] = $cvData;
  339. return $this;
  340. }
  341. /**
  342. * {@inheritdoc}
  343. */
  344. public function onKernelResponseEvent(ResponseEvent $event)
  345. {
  346. $event->getResponse()->headers->set('X-Frame-Options', 'deny', true);
  347. }
  348. }