Przeglądaj źródła

complete the update command, include the structure_domain db field

Olivier Massot 4 lat temu
rodzic
commit
0014b35bb2

+ 54 - 4
ot_admin/Classes/Command/UpdateSiteCommand.php

@@ -10,6 +10,7 @@ use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Style\SymfonyStyle;
+use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
 
@@ -35,10 +36,22 @@ class UpdateSiteCommand extends Command
             ->setDescription("Update an organization website")
             ->setHelp("This CLI command update an existing organization's website
                             with the latest data from the Opentalent DB")
+            ->addOption(
+                'all',
+                null,
+                InputOption::VALUE_NONE,
+                "Update all of the organization websites"
+            )
             ->addArgument(
                 'organization-id',
-                InputArgument::REQUIRED,
+                InputArgument::OPTIONAL,
                 "The organization's id in the opentalent DB"
+            )
+            ->addOption(
+                'deep',
+                'd',
+                InputOption::VALUE_NONE,
+                "Performs a deep update (recreate the site config file, reset the be_users permissions)"
             );
     }
 
@@ -52,13 +65,50 @@ class UpdateSiteCommand extends Command
     protected function execute(InputInterface $input, OutputInterface $output)
     {
         $org_id = $input->getArgument('organization-id');
+        $all = $input->getOption('all');
+        $deep = $input->getOption('deep');
+
+        if ($all && $org_id) {
+            throw new \InvalidArgumentException("You can not pass both an organization id and the --all option");
+        }
+        if (!$all && !$org_id) {
+            throw new \InvalidArgumentException("You shall either pass an organization id or use the --all option");
+        }
 
         $io = new SymfonyStyle($input, $output);
 
         $siteController = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
-        $rootUid = $siteController->updateSiteConstantsAction($org_id);
 
-        $io->success(sprintf("The website with root uid " . $rootUid . " has been updated"));
-    }
+        $msg_deep = $deep ? 'deeply ' : '';
+
+        if ($all) {
+            $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
+            $queryBuilder = $connectionPool->getQueryBuilderForTable('pages');
+            $sites = $queryBuilder
+                ->select('tx_opentalent_structure_id')
+                ->from('pages')
+                ->where('is_siteroot=1')
+                ->andWhere($queryBuilder->expr()->gt('tx_opentalent_structure_id', 0))
+                ->execute()
+                ->fetchAll();
 
+            $io->progressStart(count($sites));
+
+            foreach ($sites as $site) {
+                $org_id = $site['tx_opentalent_structure_id'];
+                try {
+                    $siteController->updateSiteAction($org_id, $deep);
+                } catch (\Throwable $e) {
+                    $io->error('Organization Id: ' . $org_id . ' - ' . $e->getMessage());
+                }
+                $io->progressAdvance(1);
+            }
+            $io->progressFinish();
+
+            $io->success(sprintf("The websites have all been " . $msg_deep . "updated"));
+        } else {
+            $rootUid = $siteController->updateSiteAction($org_id, $deep);
+            $io->success(sprintf("The website with root uid " . $rootUid . " has been " . $msg_deep . "updated"));
+        }
+    }
 }

+ 80 - 19
ot_admin/Classes/Controller/SiteController.php

@@ -15,6 +15,7 @@ use Opentalent\OtCore\Exception\ApiRequestException;
 use Opentalent\OtCore\Utility\FileUtility;
 use PDO;
 use Symfony\Component\Yaml\Yaml;
+use TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException;
 use TYPO3\CMS\Core\Crypto\Random;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
@@ -615,31 +616,89 @@ class SiteController extends ActionController
     }
 
     /**
-     * Update the `sys_template`.`constants` field of the given
-     * organization's website with the data fetched from the opentalent DB.
+     * Performs an update of the organization's website based on data fetched from the opentalent DB:
+     *
+     * - Update the pages table (structure id, structure domain)
+     * - (deep update only) Update the config.yaml file
+     * - Update the `sys_template`.`constants` field
+     * - (deep update only) Reset the users permissions
+     * - [todo] Reset the routing index
+     * - Clear the Typo3 cache for the website
      *
      * @param int $organizationId
+     * @param bool $deep Performs a deep update (recreate the site config file, reset the be_users permissions)
      * @return int
+     * @throws NoSuchCacheException
+     * @throws NoSuchRecordException
      * @throws NoSuchWebsiteException
+     * @throws \Doctrine\DBAL\ConnectionException
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Throwable
      */
-    public function updateSiteConstantsAction(int $organizationId): int
+    public function updateSiteAction(int $organizationId, bool $deep=false): int
     {
         $rootUid = $this->findRootUidFor($organizationId);
 
+        $organization = $this->fetchOrganization($organizationId);
+        $organizationDomain = $organization->getSubDomain() . '.opentalent.fr';
+
         // This extra-data can not be retrieved from the API for now, but
         // this shall be set up as soon as possible, to avoid requesting
         // the prod-back DB directly.
         $organizationExtraData = $this->fetchOrganizationExtraData($organizationId);
 
-        $constants = $this->getTemplateConstants($organizationId, $organizationExtraData);
+        // start transactions
+        $this->connectionPool->getConnectionByName('Default')->beginTransaction();
 
-        $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_template');
-        $queryBuilder
-            ->update('sys_template')
-            ->set('constants', $constants)
-            ->where($queryBuilder->expr()->eq('pid', $rootUid))
-            ->execute();
+        // keep tracks of the created folders and files to be able to remove them during a rollback
+        try {
+            // ## Update the pages table (structure id, structure domain)
+            $sitePages = $this->otPageRepository->getAllSitePages($rootUid);
+            foreach ($sitePages as $page) {
+                $queryBuilder = $this->connectionPool->getQueryBuilderForTable('pages');
+                $queryBuilder->update('pages')
+                    ->set('tx_opentalent_structure_id', $organizationId)
+                    ->set('tx_opentalent_structure_domain', $organizationDomain)
+                    ->where($queryBuilder->expr()->eq('uid', $page['uid']))
+                    ->execute();
+            }
 
+            // ## Update the config.yaml file
+            if ($deep) {
+                $this->writeConfigFile($organizationId, $rootUid, $organizationDomain, true);
+            }
+
+            // ## Update the `sys_template`.`constants` field
+            $constants = $this->getTemplateConstants($organizationId, $organizationExtraData);
+
+            $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_template');
+            $queryBuilder
+                ->update('sys_template')
+                ->set('constants', $constants)
+                ->where($queryBuilder->expr()->eq('pid', $rootUid))
+                ->execute();
+
+            // ## Reset the users permissions
+            if ($deep) {
+                $this->resetBeUserPermsAction($organizationId, true);
+            }
+
+            // ## Reset the routing index
+            // TODO: complete
+
+            // Try to commit the result
+            $commitSuccess = $this->connectionPool->getConnectionByName('Default')->commit();
+            if (!$commitSuccess) {
+                throw new \RuntimeException('Something went wrong while committing the result');
+            }
+
+        } catch(\Throwable $e) {
+            // rollback
+            $this->connectionPool->getConnectionByName('Default')->rollback();
+            throw $e;
+        }
+
+        // ## Clear the Typo3 cache for the website
         OtCacheManager::clearSiteCache($rootUid, true);
         return $rootUid;
     }
@@ -1770,7 +1829,8 @@ class SiteController extends ActionController
             'slug' => $slug,
             'backend_layout' => 'flux__grid',
             'backend_layout_next_level' => 'flux__grid',
-            'tx_opentalent_structure_id' => $organization->getId()
+            'tx_opentalent_structure_id' => $organization->getId(),
+            'tx_opentalent_structure_domain' => $organization->getSubDomain() . '.opentalent.fr',
         ];
 
         if ($template) {
@@ -1808,7 +1868,8 @@ class SiteController extends ActionController
             self::TEMPLATE_HOME,
             [
                 'is_siteroot' => 1,
-                'TSconfig' => 'TCAdefaults.pages.tx_opentalent_structure_id =' . $organization->getId(),
+                'TSconfig' => 'TCAdefaults.pages.tx_opentalent_structure_id =' . $organization->getId() . '\n' .
+                              'TCAdefaults.pages.tx_opentalent_structure_domain = ' . $organization->getSubDomain() .  '.opentalent.fr',
                 'tx_opentalent_template' => self::DEFAULT_THEME,
                 'tx_opentalent_template_preferences' => '{"themeColor":"' . self::DEFAULT_COLOR . '","displayCarousel":"1"}'
             ]
@@ -2046,9 +2107,8 @@ class SiteController extends ActionController
      * @param int $rootUid
      * @param string $domain
      * @param bool $forceRecreate
-     * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
      */
-    private function writeConfigFile(int $organizationId, int $rootUid, string $domain, bool $forceRecreate = false): string
+    private function writeConfigFile(int $organizationId, int $rootUid, string $domain, bool $forceRecreate = false): void
     {
         $existing = $this->findConfigFileAndContentFor($rootUid);
         $configFilename = $existing[0];
@@ -2122,11 +2182,12 @@ class SiteController extends ActionController
         }
 
         // Flush cache:
-        $cacheSystem = $this->cacheManager->getCache('cache_core');
-        $cacheSystem->remove('site-configuration');
-        $cacheSystem->remove('pseudo-sites');
-
-        return $configFilename;
+        try {
+            $cacheSystem = $this->cacheManager->getCache('cache_core');
+            $cacheSystem->remove('site-configuration');
+            $cacheSystem->remove('pseudo-sites');
+        } catch (NoSuchCacheException $e) {
+        }
     }
 
     /**

+ 28 - 14
ot_admin/Classes/Http/ApiController.php

@@ -37,7 +37,8 @@ class ApiController implements LoggerAwareInterface
      * @param string $clientIp
      * @return bool
      */
-    public static function isIpAllowed(string $clientIp) {
+    public static function isIpAllowed(string $clientIp): bool
+    {
         foreach (self::ALLOWED_IPS as $ipRule) {
             if (preg_match($ipRule, $clientIp)) {
                 return true;
@@ -51,7 +52,8 @@ class ApiController implements LoggerAwareInterface
      *
      * @return bool
      */
-    private function assertIpAllowed() {
+    private function assertIpAllowed(): bool
+    {
         $clientIp = $_SERVER['REMOTE_ADDR'];
         if (!self::isIpAllowed($clientIp)){
             $route = $_REQUEST['route'];
@@ -69,7 +71,8 @@ class ApiController implements LoggerAwareInterface
      * @param ServerRequest $request
      * @return int
      */
-    private function getOrganizationId(ServerRequest $request) {
+    private function getOrganizationId(ServerRequest $request): int
+    {
         $params = $request->getQueryParams();
         $organizationId = $params['organization-id'];
         if (!$organizationId) {
@@ -87,7 +90,8 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function getSiteInfosAction(ServerRequest $request) {
+    public function getSiteInfosAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $organizationId = $this->getOrganizationId($request);
@@ -109,7 +113,8 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function createSiteAction(ServerRequest $request) {
+    public function createSiteAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $organizationId = $this->getOrganizationId($request);
@@ -140,13 +145,15 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function updateSiteConstantsAction(ServerRequest $request) {
+    public function updateSiteConstantsAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $organizationId = $this->getOrganizationId($request);
+        $deep = (isset($queryParams['deep']) && $queryParams['deep']);
 
         $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
-        $rootUid = $controller->updateSiteConstantsAction($organizationId);
+        $rootUid = $controller->updateSiteAction($organizationId, $deep);
 
         $this->logger->info(sprintf(
             "OtAdmin API: The website with root uid " . $rootUid . " has been updated " .
@@ -171,7 +178,8 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function deleteSiteAction(ServerRequest $request) {
+    public function deleteSiteAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $organizationId = $this->getOrganizationId($request);
@@ -205,7 +213,8 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function undeleteSiteAction(ServerRequest $request) {
+    public function undeleteSiteAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $organizationId = $this->getOrganizationId($request);
@@ -236,7 +245,8 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function clearSiteCacheAction(ServerRequest $request) {
+    public function clearSiteCacheAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $organizationId = $this->getOrganizationId($request);
@@ -263,7 +273,8 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function setSiteDomainAction(ServerRequest $request) {
+    public function setSiteDomainAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $organizationId = $this->getOrganizationId($request);
@@ -298,7 +309,8 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function resetBeUserPermsAction(ServerRequest $request) {
+    public function resetBeUserPermsAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $organizationId = $this->getOrganizationId($request);
@@ -325,7 +337,8 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function getSiteStatusAction(ServerRequest $request) {
+    public function getSiteStatusAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $organizationId = $this->getOrganizationId($request);
@@ -348,7 +361,8 @@ class ApiController implements LoggerAwareInterface
      * @return JsonResponse
      * @throws \Exception
      */
-    public function scanAllAction(ServerRequest $request) {
+    public function scanAllAction(ServerRequest $request): JsonResponse
+    {
         $this->assertIpAllowed();
 
         $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(ScanController::class);