فهرست منبع

add the redirection:add and redirection:remove CLI commands

Olivier Massot 4 سال پیش
والد
کامیت
77d4b39db4

+ 70 - 0
ot_admin/Classes/Command/AddRedirectionCommand.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace Opentalent\OtAdmin\Command;
+
+
+use Opentalent\OtAdmin\Controller\SiteController;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+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\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+
+/**
+ * This CLI command adds a redirection from a domain to another
+ *
+ * @package Opentalent\OtAdmin\Command
+ */
+class AddRedirectionCommand extends Command
+{
+    /**
+     * -- This method is expected by Typo3, do not rename ou remove --
+     *
+     * Allows to configure the command.
+     * Allows to add a description, a help text, and / or define arguments.
+     *
+     */
+    protected function configure()
+    {
+        $this
+            ->setName("ot:redirection:add")
+            ->setDescription("Add a redirection from a domain to another")
+            ->setHelp("Add a redirection from a domain to another")
+            ->addArgument(
+                'from_domain',
+                InputArgument::REQUIRED,
+                "The domain to be redirected"
+            )->addArgument(
+                'to_domain',
+                InputArgument::REQUIRED,
+                "The target domain"
+            );
+    }
+
+    /**
+     * -- This method is expected by Typo3, do not rename ou remove --
+     *
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @throws \Exception
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $fromDomain = $input->getArgument('from_domain');
+        $toDomain = $input->getArgument('to_domain');
+
+        $io = new SymfonyStyle($input, $output);
+
+        $siteController = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
+        $status = $siteController->addRedirection($fromDomain, $toDomain);
+
+        if ($status == SiteController::REDIRECTION_UPDATED) {
+            $io->success(sprintf("A existing redirection has been restored and updated"));
+        } else {
+            $io->success(sprintf("A new redirection has been added"));
+        }
+    }
+}

+ 71 - 0
ot_admin/Classes/Command/RemoveRedirectionCommand.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace Opentalent\OtAdmin\Command;
+
+
+use Opentalent\OtAdmin\Controller\SiteController;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+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\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+
+/**
+ * This CLI command removes any redirection from the given domain
+ * with the latest data from the Opentalent DB
+ *
+ * @package Opentalent\OtAdmin\Command
+ */
+class RemoveRedirectionCommand extends Command
+{
+    /**
+     * -- This method is expected by Typo3, do not rename ou remove --
+     *
+     * Allows to configure the command.
+     * Allows to add a description, a help text, and / or define arguments.
+     *
+     */
+    protected function configure()
+    {
+        $this
+            ->setName("ot:redirection:remove")
+            ->setDescription("Remove any redirection from the given domain")
+            ->setHelp("Remove any redirection from the given domain. If --hard is true, they will be permanently deleted.")
+            ->addArgument(
+                'from-domain',
+                InputArgument::REQUIRED,
+                "The source domain"
+            )->addOption(
+                'hard',
+                null,
+                InputOption::VALUE_NONE,
+                "Permanently delete the records and files. Use with caution."
+            );
+    }
+
+    /**
+     * -- This method is expected by Typo3, do not rename ou remove --
+     *
+     * Executes the command for creating the new organization
+     *
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @throws \Exception
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $fromDomain = $input->getArgument('from-domain');
+        $hard = $input->getOption('hard');
+
+        $io = new SymfonyStyle($input, $output);
+
+        $siteController = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
+        $count = $siteController->removeRedirectionsFrom($fromDomain, $hard);
+
+        $actionName = $hard ? 'hardly-deleted' : 'deleted';
+        $io->success(sprintf("$count existing redirections from $fromDomain have been $actionName"));
+    }
+}

+ 158 - 11
ot_admin/Classes/Controller/SiteController.php

@@ -79,10 +79,15 @@ class SiteController extends ActionController
         self::STATUS_EXISTING_WITH_WARNINGS => 'Existing with warnings',
     ];
 
-
     const MODE_PROD = 1;
     const MODE_DEV = 1;
 
+    const RX_DOMAIN = "/([a-z0-9A-Z]\.)*[a-z0-9-]+\.([a-z0-9]{2,24})+(\.co\.([a-z0-9]{2,24})|\.([a-z0-9]{2,24}))*\/?/";
+
+    const REDIRECTION_UNKNOWN_STATUS = 0;
+    const REDIRECTION_UPDATED = 1;
+    const REDIRECTION_CREATED = 2;
+
     /**
      * @var \TYPO3\CMS\Core\Database\ConnectionPool
      */
@@ -171,7 +176,6 @@ class SiteController extends ActionController
         }
 
         return $site;
-
     }
 
     /**
@@ -1197,15 +1201,9 @@ class SiteController extends ActionController
      */
     public function setSiteDomainAction(int $organizationId, string $newDomain, bool $redirect = true): int
     {
-        if (!preg_match(
-                "/([a-z0-9A-Z]\.)*[a-z0-9-]+\.([a-z0-9]{2,24})+(\.co\.([a-z0-9]{2,24})|\.([a-z0-9]{2,24}))*\/?/",
-                $newDomain
-            ) && !preg_match(
-                "/[a-z0-9A-Z-]+\//",
-                $newDomain
-            )
-        ) {
-            throw new \RuntimeException("The given domain does not seems to be a valid domain: " . $newDomain);
+        if (!preg_match(self::RX_DOMAIN,$newDomain) &&
+            !preg_match("/[a-z0-9A-Z-]+\//", $newDomain)) {
+            throw new \InvalidArgumentException("The given domain does not seems to be a valid domain: " . $newDomain);
         }
 
         $rootUid = $this->findRootUidFor($organizationId);
@@ -1214,6 +1212,155 @@ class SiteController extends ActionController
         return $rootUid;
     }
 
+    /**
+     * Return all of the redirections from the given domain name,
+     * even if they have been marked as deleted.
+     *
+     * @param $domain string Domain name, without the http(s):// part
+     * @return array Rows from the sys_redirect table
+     */
+    protected function getRedirectionsFrom(string $domain): array
+    {
+        $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_redirect');
+        $queryBuilder->getRestrictions()->removeAll();
+        return $queryBuilder
+            ->select('*')
+            ->from('sys_redirect')
+            ->where($queryBuilder->expr()->eq('source_host', $queryBuilder->expr()->literal($domain)))
+            ->execute()
+            ->fetchAll();
+    }
+
+    /**
+     * Return all of the redirections to the given domain name,
+     * even if they have been marked as deleted.
+     *
+     * @param $domain string Domain name, without the http(s):// part
+     * @return array Rows from the sys_redirect table
+     */
+    protected function getRedirectionsTo(string $domain): array
+    {
+        $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_redirect');
+        $queryBuilder->getRestrictions()->removeAll();
+        return $queryBuilder
+            ->select('*')
+            ->from('sys_redirect')
+            ->where(
+                $queryBuilder->expr()->in(
+                    'target',
+                    [
+                        'http://' . $queryBuilder->expr()->literal($domain),
+                        'https://' . $queryBuilder->expr()->literal($domain)
+                    ]
+                )
+            )
+            ->execute()
+            ->fetchAll();
+    }
+
+    /**
+     * Add a new redirection from $fromDomain to $toDomain.
+     * Domains should not contain the http(s):// part
+     * If this redirection already exists but has been deleted and/or disabled, it will be restored and enabled
+     * If a redirection already exists but is not deleted and targets another domain, a RuntimeException will be thrown.
+     *
+     * @param $fromDomain
+     * @param $toDomain
+     * @return int  Status of the operation
+     */
+    public function addRedirection($fromDomain, $toDomain): int
+    {
+        $fromDomain = preg_replace('/https?:\/\//', '', $fromDomain);
+        $toDomain = preg_replace('/https?:\/\//', '', $toDomain);
+
+        if (!preg_match(self::RX_DOMAIN, $fromDomain)) {
+            throw new \InvalidArgumentException("The does not seems to be a valid domain: " . $fromDomain);
+        }
+        if (!preg_match(self::RX_DOMAIN, $toDomain)) {
+            throw new \InvalidArgumentException("The does not seems to be a valid domain: " . $toDomain);
+        }
+
+        $existing = $this->getRedirectionsFrom($fromDomain);
+        $toUpdate = null;
+
+        foreach ($existing as $redirection) {
+            if (!$redirection['deleted'] && !$redirection['disabled']) {
+                // a redirection from this domain already exists, and it is not deleted nor disabled
+
+                if (!preg_match('/https?:\/\/' . $toDomain . '/', $redirection['target'])) {
+                    // the target is not the same domain
+                    throw new \RuntimeException(
+                        'A redirection is already active for ' . $fromDomain . ' targeting ' . $redirection['target']
+                    );
+                } else {
+                    // else, target is already the same domain, it will be updated
+                    $toUpdate = $redirection;
+                    break;
+                }
+
+            } else {
+                // a redirection from this domain already exists, but it is deleted or disabled
+                if (preg_match('/https?:\/\/' . $toDomain . '/', $redirection['target'])) {
+                    // the target is the same domain, we'll reactivate this record
+                    $toUpdate = $redirection;
+                    break;
+                }
+            }
+        }
+
+        $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_redirect');
+
+        $data = [
+            'deleted' => 0,
+            'disabled' => 0,
+            'source_host' => $fromDomain,
+            'source_path' => '/.*/',
+            'is_regexp' => 1,
+            'force_https' => 0,
+            'respect_query_parameters' => 0,
+            'keep_query_parameters' => 1,
+            'target' => 'https://' . $toDomain,
+            'target_statuscode' => 301
+        ];
+
+        if ($toUpdate !== null) {
+            $q = $queryBuilder
+                ->update('sys_redirect')
+                ->where($queryBuilder->expr()->eq('uid', $toUpdate['uid']));
+            foreach ($data as $k => $v) {
+                $q->set($k, $v);
+            }
+            $q->execute();
+            return self::REDIRECTION_UPDATED;
+
+        } else {
+            $queryBuilder
+                ->insert('sys_redirect')
+                ->values($data)
+                ->execute();
+            return self::REDIRECTION_CREATED;
+        }
+    }
+
+    /**
+     * Remove any existing redirection from $fromDomain to any url by marking it as deleted.
+     * If $hard is true, delete it completely.
+     *
+     * @param $fromDomain
+     * @param bool $hard
+     * @return int Number of affected rows
+     */
+    public function removeRedirectionsFrom($fromDomain, $hard=false): int
+    {
+        $existing = $this->getRedirectionsFrom($fromDomain);
+        $deleted = 0;
+        foreach ($existing as $redirection) {
+            $this->delete('sys_redirect', 'uid', $redirection['uid'], $hard);
+            $deleted += 1;
+        }
+        return $deleted;
+    }
+
     /**
      * Retrieve the Organization object from the repository and then,
      * from the Opentalent API

+ 6 - 0
ot_admin/Configuration/Commands.php

@@ -34,6 +34,12 @@ return [
     'ot:site:status' => [
         'class' => Opentalent\OtAdmin\Command\GetSiteStatusCommand::class
     ],
+    'ot:redirection:add' => [
+        'class' => Opentalent\OtAdmin\Command\AddRedirectionCommand::class
+    ],
+    'ot:redirection:remove' => [
+        'class' => Opentalent\OtAdmin\Command\RemoveRedirectionCommand::class
+    ],
     'ot:scan' => [
         'class' => Opentalent\OtAdmin\Command\ScanCommand::class
     ]

+ 12 - 0
ot_admin/Configuration/Services.yaml

@@ -49,6 +49,18 @@ services:
         command: 'ot:site:status'
         schedulable: false
 
+  Opentalent\OtAdmin\Command\AddRedirectionCommand:
+    tags:
+      - name: 'ot:redirection:add'
+        command: 'ot:redirection:add'
+        schedulable: false
+
+  Opentalent\OtAdmin\Command\RemoveRedirectionCommand:
+    tags:
+      - name: 'ot:redirection:remove'
+        command: 'ot:redirection:remove'
+        schedulable: false
+
   Opentalent\OtAdmin\Command\ScanCommand:
     tags:
       - name: 'ot:scan'