浏览代码

fix some docs and refactor the scan / status part commands

Olivier Massot 4 年之前
父节点
当前提交
f039829bb3

+ 4 - 4
ot_admin/Classes/Command/AddRedirectionCommand.php

@@ -34,11 +34,11 @@ class AddRedirectionCommand extends Command
             ->setDescription("Add a redirection from a domain to another")
             ->setHelp("Add a redirection from a domain to another")
             ->addArgument(
-                'from_domain',
+                'from-domain',
                 InputArgument::REQUIRED,
                 "The domain to be redirected"
             )->addArgument(
-                'to_domain',
+                'to-domain',
                 InputArgument::REQUIRED,
                 "The target domain"
             );
@@ -53,8 +53,8 @@ class AddRedirectionCommand extends Command
      */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $fromDomain = $input->getArgument('from_domain');
-        $toDomain = $input->getArgument('to_domain');
+        $fromDomain = $input->getArgument('from-domain');
+        $toDomain = $input->getArgument('to-domain');
 
         $io = new SymfonyStyle($input, $output);
 

+ 2 - 4
ot_admin/Classes/Command/ClearSiteCacheCommand.php

@@ -37,7 +37,7 @@ class ClearSiteCacheCommand extends Command
             ->setDescription("Clear the cache of an organization website")
             ->setHelp("This CLI command clears the cache of an existing organization's website")
             ->addArgument(
-                'organization_id',
+                'organization-id',
                 InputArgument::REQUIRED,
                 "The organization's id in the opentalent DB"
             )->addOption(
@@ -51,15 +51,13 @@ class ClearSiteCacheCommand extends Command
     /**
      * -- This method is expected by Typo3, do not rename ou remove --
      *
-     * Executes the command for clearing the cache of the organization's website
-     *
      * @param InputInterface $input
      * @param OutputInterface $output
      * @throws \Exception
      */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $org_id = $input->getArgument('organization_id');
+        $org_id = $input->getArgument('organization-id');
         $clearAll = $input->getOption('all');
 
         $io = new SymfonyStyle($input, $output);

+ 5 - 9
ot_admin/Classes/Command/CreateSiteCommand.php

@@ -21,8 +21,6 @@ use TYPO3\CMS\Extbase\Object\ObjectManager;
  */
 class CreateSiteCommand extends Command
 {
-
-
     /**
      * -- This method is expected by Typo3, do not rename ou remove --
      *
@@ -37,32 +35,30 @@ class CreateSiteCommand extends Command
             ->setDescription("Create an organization's website " .
                                        "by fetching its latest data from the Opentalent API")
             ->setHelp("Call this method by giving it the organization's id in the Opentalent DB. 
-                            If no site exists, create it; 
-                            If a site already exists, do nothing.")
+                            If no site exists, it will create it; 
+                            If a site already exists, it won't do anything.")
             ->addArgument(
-                'organization_id',
+                'organization-id',
                 InputArgument::REQUIRED,
                 "The organization's id in the opentalent DB"
             )->addOption(
                 'dev',
                 null,
                 InputOption::VALUE_NONE,
-                "Add this option to get url like 'http://host/subdomain' instead of 'http://subdomain/host'"
+                "Add this option to get url like 'http://host/subdomain' instead of 'http://subdomain.host'"
             );
     }
 
     /**
      * -- 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)
     {
-        $org_id = $input->getArgument('organization_id');
+        $org_id = $input->getArgument('organization-id');
         $isDev = $input->getOption('dev');
 
         $io = new SymfonyStyle($input, $output);

+ 2 - 4
ot_admin/Classes/Command/DeleteSiteCommand.php

@@ -53,7 +53,7 @@ class DeleteSiteCommand extends Command
                 "Organization id of the website to which add a redirection."
             )
             ->addArgument(
-                'organization_id',
+                'organization-id',
                 InputArgument::REQUIRED,
                 "The organization's id in the opentalent DB"
             );
@@ -62,15 +62,13 @@ class DeleteSiteCommand extends Command
     /**
      * -- 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)
     {
-        $org_id = $input->getArgument('organization_id');
+        $org_id = $input->getArgument('organization-id');
         $hard = $input->getOption('hard');
         $redirectTo = $input->getOption('redirect-to');
 

+ 0 - 73
ot_admin/Classes/Command/GetSiteInfosCommand.php

@@ -1,73 +0,0 @@
-<?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\Output\OutputInterface;
-use Symfony\Component\Console\Style\SymfonyStyle;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\Object\ObjectManager;
-
-/**
- * Display the main informations about the organization's website
- *
- * @package Opentalent\OtAdmin\Command
- */
-class GetSiteInfosCommand 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:site:infos")
-            ->setDescription("Display the main informations about the organization's website")
-            ->addArgument(
-                'organization_id',
-                InputArgument::REQUIRED,
-                "The organization's id in the opentalent DB"
-            );
-    }
-
-    /**
-     * -- 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)
-    {
-        $org_id = $input->getArgument('organization_id');
-
-        $io = new SymfonyStyle($input, $output);
-
-        $siteController = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
-        $infos = $siteController->getSiteInfosAction($org_id);
-        $io->title(sprintf("Informations about the organization " . $org_id . ' typo3 website'));
-
-        $headers = [];
-        $values = [];
-        foreach ($infos as $key => $value) {
-            $headers[] = $key;
-            $values[] = json_encode(
-                str_replace("\"", "'", $value),
-                JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
-            );
-        }
-
-        $io->horizontalTable($headers, [$values]);
-
-        $io->success(sprintf('Informations retrieved'));
-    }
-
-}

+ 18 - 18
ot_admin/Classes/Command/GetSiteStatusCommand.php

@@ -14,7 +14,8 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
 
 /**
- * This CLI command returns a status code representing the current state of a given website
+ * This CLI command returns the status and some useful informations
+ * about the given website
  *
  * @package Opentalent\OtAdmin\Command
  */
@@ -37,10 +38,10 @@ class GetSiteStatusCommand extends Command
                 'full',
                 null,
                 InputOption::VALUE_NONE,
-                "Performs a full scan"
+                "Performs a full scan (with warnings)"
             )
             ->addArgument(
-                'organization_id',
+                'organization-id',
                 InputArgument::REQUIRED,
                 "The organization's id in the opentalent DB"
             );
@@ -55,7 +56,7 @@ class GetSiteStatusCommand extends Command
      */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $org_id = $input->getArgument('organization_id');
+        $org_id = $input->getArgument('organization-id');
         $full = $input->getOption('full');
 
         $io = new SymfonyStyle($input, $output);
@@ -63,22 +64,21 @@ class GetSiteStatusCommand extends Command
         $siteController = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
         $status = $siteController->getSiteStatusAction($org_id, $full);
 
-        $output = "## Status of the website: \n" .
-            "Organization Id: " . $status['organization_id'] . "\n" .
-            "Status: " . $status['status'] . "\n" .
-            "Message: " . $status['message'] . "\n" .
-            "Site root uid: " . $status['root_uid'] . "\n" .
-            "Site's title: " . $status['title'] . "";
-
-        if (isset($status['warnings'])) {
-            if ($status['warnings']) {
-                $output .= "\nWarnings: \n - " . join("\n - ", $status['warnings']);
-            } else {
-                $output .= "\nWarnings: None";
-            }
+        $headers = [];
+        $values = [];
+        foreach ($status->toArray() as $key => $value) {
+            $headers[] = $key;
+            $value = json_encode(
+                str_replace("\"", "'", $value),
+                JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
+            );
+            $value = trim($value, "\"");
+            $values[] = $value;
         }
 
-        $io->success(sprintf($output));
+        $io->horizontalTable($headers, [$values]);
+
+        $io->success('');
     }
 
 }

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

@@ -15,7 +15,6 @@ 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
  */
@@ -49,8 +48,6 @@ class RemoveRedirectionCommand extends Command
     /**
      * -- 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

+ 0 - 5
ot_admin/Classes/Command/ScanCommand.php

@@ -2,11 +2,8 @@
 
 namespace Opentalent\OtAdmin\Command;
 
-
 use Opentalent\OtAdmin\Controller\ScanController;
-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;
@@ -45,8 +42,6 @@ class ScanCommand extends Command
     /**
      * -- 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

+ 5 - 4
ot_admin/Classes/Command/SetSiteDomainCommand.php

@@ -32,10 +32,11 @@ class SetSiteDomainCommand extends Command
         $this
             ->setName("ot:site:setdomain")
             ->setDescription("Set a new domain for the organization website")
-            ->setHelp("Set a new domain for the organization website. If the --redirect argument is passed, " .
-                           "a redirection will be added from the existing domain to the new one.")
+            ->setHelp("Set a new domain for the organization website. A new redirection will " .
+                           "be added from the existing domain to the new one. Use the --no-redirection option " .
+                           "to prevent this.")
             ->addArgument(
-                'organization_id',
+                'organization-id',
                 InputArgument::REQUIRED,
                 "The organization's id in the opentalent DB"
             )
@@ -63,7 +64,7 @@ class SetSiteDomainCommand extends Command
      */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $org_id = $input->getArgument('organization_id');
+        $org_id = $input->getArgument('organization-id');
         $domain = $input->getArgument('domain');
         $redirect = ($input->getOption('no-redirection') == null);
 

+ 2 - 6
ot_admin/Classes/Command/UndeleteSiteCommand.php

@@ -20,8 +20,6 @@ use TYPO3\CMS\Extbase\Object\ObjectManager;
  */
 class UndeleteSiteCommand extends Command
 {
-
-
     /**
      * -- This method is expected by Typo3, do not rename ou remove --
      *
@@ -39,7 +37,7 @@ class UndeleteSiteCommand extends Command
                             command and without the --hard option, you can undo the deletion with
                             this command.")
             ->addArgument(
-                'organization_id',
+                'organization-id',
                 InputArgument::REQUIRED,
                 "The organization's id in the opentalent DB"
             );
@@ -48,15 +46,13 @@ class UndeleteSiteCommand extends Command
     /**
      * -- 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)
     {
-        $org_id = $input->getArgument('organization_id');
+        $org_id = $input->getArgument('organization-id');
 
         $io = new SymfonyStyle($input, $output);
 

+ 3 - 5
ot_admin/Classes/Command/UpdateSiteCommand.php

@@ -14,7 +14,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
 
 /**
- * This CLI command update an existing organization's website
+ * This CLI command updates an existing organization's website
  * with the latest data from the Opentalent DB
  *
  * @package Opentalent\OtAdmin\Command
@@ -36,7 +36,7 @@ class UpdateSiteCommand extends Command
             ->setHelp("This CLI command update an existing organization's website
                             with the latest data from the Opentalent DB")
             ->addArgument(
-                'organization_id',
+                'organization-id',
                 InputArgument::REQUIRED,
                 "The organization's id in the opentalent DB"
             );
@@ -45,15 +45,13 @@ class UpdateSiteCommand extends Command
     /**
      * -- 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)
     {
-        $org_id = $input->getArgument('organization_id');
+        $org_id = $input->getArgument('organization-id');
 
         $io = new SymfonyStyle($input, $output);
 

+ 7 - 30
ot_admin/Classes/Controller/ScanController.php

@@ -4,13 +4,14 @@
 namespace Opentalent\OtAdmin\Controller;
 
 
+use Opentalent\OtAdmin\Domain\Entity\ScanReport;
 use Opentalent\OtCore\Controller\ActionController;
 use Opentalent\OtCore\Domain\Repository\OrganizationRepository;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
 
 /**
- * The ScanController allows to scan the Typo3 DB to find potential issues
+ * ScanController allows to scan the Typo3 DB to find potential issues
  */
 class ScanController extends ActionController
 {
@@ -18,48 +19,24 @@ class ScanController extends ActionController
      * Perform a full scan of the Typo3 DB, and confront it to the
      * Opentalent organizations list.
      *
-     * Result is an array of the form:
-     *
-     * [
-     *   'date' => Datetime,
-     *   'stats' => [
-     *                status => count,
-     *                ...
-     *              ]
-     *   'results' => [
-     *                  organization_id => status,
-     *                  ...
-     *                ]
-     * ]
-     *
-     *
      * @param bool $fullScan If true, a 'warnings' entry will be added to the result of each site status,
      *                        and a full scan of the website pages will be performed.
-     * @return array
+     * @return ScanReport
      */
-    public function scanAllAction(bool $fullScan = false): array
+    public function scanAllAction(bool $fullScan = false): ScanReport
     {
         $organizationRepository = GeneralUtility::makeInstance(ObjectManager::class)->get(OrganizationRepository::class);
         $siteController = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
 
-        $results = [];
-        $stats = [];
+        $report = new ScanReport();
 
         $organizationsCollection = $organizationRepository->getAll();
         foreach ($organizationsCollection->getMembers() as $organization) {
             $status = $siteController->getSiteStatusAction($organization->getId(), $fullScan);
-            $results[$organization->getId()] = $status;
 
-            if (!isset($stats[$status['status']])) {
-                $stats[$status['status']] = 0;
-            }
-            $stats[$status['status']] += 1;
+            $report->setResultFor($organization->getId(), $status);
         }
 
-        return [
-            'date' => new \DateTime(),
-            'stats' => $stats,
-            'results' => $results
-        ];
+        return $report;
     }
 }

+ 38 - 113
ot_admin/Classes/Controller/SiteController.php

@@ -3,13 +3,14 @@
 namespace Opentalent\OtAdmin\Controller;
 
 use http\Exception\RuntimeException;
+use Opentalent\OtAdmin\Domain\Entity\SiteInfos;
+use Opentalent\OtAdmin\Domain\Entity\SiteStatus;
 use Opentalent\OtAdmin\Exception\NoSuchWebsiteException;
 use Opentalent\OtCore\Cache\OtCacheManager;
 use Opentalent\OtCore\Controller\ActionController;
 use Opentalent\OtCore\Domain\Model\Organization;
 use Opentalent\OtCore\Domain\Repository\OrganizationRepository;
 use Opentalent\OtCore\Exception\ApiRequestException;
-use Opentalent\OtCore\Page\OtPageRepository;
 use PDO;
 use Symfony\Component\Yaml\Yaml;
 use TYPO3\CMS\Core\Crypto\Random;
@@ -64,21 +65,6 @@ class SiteController extends ActionController
         "manager" => 3, // Association writer full
     ];
 
-    // Websites statuses
-    const STATUS_NO_SUCH_WEBSITE = 0;
-    const STATUS_EXISTING = 1;
-    const STATUS_EXISTING_DELETED = 2;
-    const STATUS_EXISTING_HIDDEN = 3;
-    const STATUS_EXISTING_WITH_WARNINGS = 4;
-
-    const STATUS_LBL = [
-        self::STATUS_NO_SUCH_WEBSITE => 'Does not exist',
-        self::STATUS_EXISTING => 'Existing',
-        self::STATUS_EXISTING_DELETED => 'Existing, deleted',
-        self::STATUS_EXISTING_HIDDEN => 'Existing, hidden',
-        self::STATUS_EXISTING_WITH_WARNINGS => 'Existing with warnings',
-    ];
-
     const MODE_PROD = 1;
     const MODE_DEV = 1;
 
@@ -139,27 +125,27 @@ class SiteController extends ActionController
      * Return the main informations about the organization's website
      *
      * @param int $organizationId
-     * @return array
+     * @return SiteInfos
      * @throws NoSuchWebsiteException
      */
-    public function getSiteInfosAction(int $organizationId) {
+    public function getSiteInfosAction(int $organizationId): SiteInfos
+    {
         $rootUid = $this->findRootUidFor($organizationId);
         $config = $this->findConfigFor($organizationId, $rootUid);
-        $extraData = $this->fetchOrganizationExtraData($organizationId);
+        //$extraData = $this->fetchOrganizationExtraData($organizationId);
 
         $rootPage = $this->otPageRepository->getPage($rootUid);
 
-        $site = [
-            'rootUid' => $rootUid,
-            'siteTitle' => $rootPage['title'],
-            'baseUrl' => $config['base'],
-            'template' => $rootPage['tx_opentalent_template'],
-            'preferences' => $rootPage['tx_opentalent_template_preferences'],
-            'matomo_id' => $rootPage['tx_opentalent_matomo_id'],
-            'deleted' => $rootPage['deleted'],
-            'hiddenOrRestricted' => (int)($rootPage['hidden'] || $rootPage['fe_group'] < 0),
-            'mountedForBeUsers' => []
-        ];
+        $site = new SiteInfos(
+            $rootUid,
+            $rootPage['title'],
+            $config['base'],
+            $rootPage['tx_opentalent_template'],
+            $rootPage['tx_opentalent_template_preferences'],
+            $rootPage['tx_opentalent_matomo_id'],
+            (bool)$rootPage['deleted'],
+            (bool)($rootPage['hidden'] || $rootPage['fe_group'] < 0)
+        );
 
         // Owners
         $queryBuilder = $this->connectionPool->getQueryBuilderForTable('pages');
@@ -172,7 +158,7 @@ class SiteController extends ActionController
             ->fetchAll();
 
         foreach ($beUsers as $beUser) {
-            $site['mountedForBeUsers'][] = $beUser;
+            $site->addMountedForBeUser($beUser);
         }
 
         return $site;
@@ -664,8 +650,8 @@ class SiteController extends ActionController
             if ($redirectTo == $organizationId) {
                 throw new \InvalidArgumentException('redirectTo value has to be different from the organizationId');
             }
-            $originUrl = $this->getSiteInfosAction($organizationId)['baseUrl'];
-            $targetUrl = $this->getSiteInfosAction($redirectTo)['baseUrl'];
+            $originUrl = $this->getSiteInfosAction($organizationId)->getBaseUrl();
+            $targetUrl = $this->getSiteInfosAction($redirectTo)->getBaseUrl();
         }
 
         // start transactions
@@ -953,7 +939,7 @@ class SiteController extends ActionController
             }
 
             // remove eventual redirection from this site to another
-            $originUrl = $this->getSiteInfosAction($organizationId)['baseUrl'];
+            $originUrl = $this->getSiteInfosAction($organizationId)->getBaseUrl();
             $this->removeRedirectionsFrom($originUrl);
 
             // Try to commit the result
@@ -990,55 +976,6 @@ class SiteController extends ActionController
         return $rootUid;
     }
 
-    /**
-     * Pack the status informations into an array for the getSiteStatusAction method
-     *
-     * @param int $organizationId
-     * @param int $code
-     * @param int|null $rootUid
-     * @param array|null $warnings
-     * @return array
-     */
-    private function buildStatusResult(
-        int $organizationId,
-        int $code,
-        ?int $rootUid = null,
-        ?array $warnings = null): array
-    {
-        $message = "";
-        if($code == self::STATUS_NO_SUCH_WEBSITE) {
-            $message = 'No website were found for organization ' . $organizationId;
-        } elseif ($code == self::STATUS_EXISTING) {
-            $message = 'A website exists for organization ' . $organizationId;
-        }
-        elseif ($code == self::STATUS_EXISTING_DELETED) {
-            $message = 'A website exists for organization ' . $organizationId . ', but has been deleted';
-        }
-        elseif ($code == self::STATUS_EXISTING_HIDDEN) {
-            $message = 'A website exists for organization ' . $organizationId . ', but is hidden or has a restricted access';
-        } elseif ($code == self::STATUS_EXISTING_WITH_WARNINGS) {
-            $message = 'A website exists for organization ' . $organizationId . ', but warnings were raised';
-        }
-
-        $title = '';
-        if ($rootUid !== null) {
-            $title = $this->otPageRepository->getPage($rootUid)['title'];
-        }
-
-        $status = [
-            'organization_id' => $organizationId,
-            'code' => $code,
-            'status' => self::STATUS_LBL[$code],
-            'message' => $message,
-            'root_uid' => $rootUid,
-            'title' => $title
-        ];
-        if ($warnings !== null) {
-            $status['warnings'] = $warnings;
-        }
-        return $status;
-    }
-
     /**
      * Perform a full scan of the website and returns a list of warnings
      *
@@ -1155,22 +1092,9 @@ class SiteController extends ActionController
 
     /**
      * Get the current status of the organization's website
+     * If $fullScan is true, a deeper scan will be performed and warnings may be logged
      *
-     * The result is an array of the form:
-     *
-     *  [
-     *     'organization_id' => int,
-     *     'code' => int,
-     *     'status' => int,
-     *     'message' => string,
-     *     'root_uid' => ?int,
-     *     'site_title' => ?string,
-     *     ('warnings' => array)
-     *  ]
-     *
-     * If $statusOnly is true, the warnings entry won't be added
-     *
-     * The code value is among:
+     * The status is among:
      *
      *   - STATUS_NO_SUCH_WEBSITE
      *   - STATUS_EXISTING
@@ -1181,34 +1105,35 @@ class SiteController extends ActionController
      * @param int $organizationId the organization's id whom site cache should be cleared
      * @param bool $fullScan If true, a 'warnings' entry will be added to the result, and a full scan of
      *                       the website pages will be performed.
-     * @return array
+     * @return SiteStatus
      */
-    public function getSiteStatusAction(int $organizationId, bool $fullScan = false): array
+    public function getSiteStatusAction(int $organizationId, bool $fullScan = false): SiteStatus
     {
         try {
-            $rootUid = $this->findRootUidFor($organizationId);
+            $siteInfos = $this->getSiteInfosAction($organizationId);
         } catch (NoSuchWebsiteException $e) {
-            return $this->buildStatusResult($organizationId, self::STATUS_NO_SUCH_WEBSITE);
+            return new SiteStatus($organizationId, SiteStatus::STATUS_NO_SUCH_WEBSITE);
         }
 
-        if ($rootUid['deleted']) {
-            return $this->buildStatusResult($organizationId, self::STATUS_EXISTING_DELETED, $rootUid);
+        if ($siteInfos->isDeleted()) {
+            return new SiteStatus($organizationId, SiteStatus::STATUS_EXISTING_DELETED, $siteInfos);
         }
-        if ($rootUid['hidden'] || ($rootUid['fe_group'] < 0)) {
-            return $this->buildStatusResult($organizationId, self::STATUS_EXISTING_HIDDEN, $rootUid);
+        if ($siteInfos->isHiddenOrRestricted()) {
+            return new SiteStatus($organizationId, SiteStatus::STATUS_EXISTING_HIDDEN, $siteInfos);
         }
 
         $warnings = null;
         if ($fullScan) {
             // ** Look for potential issues
-            $warnings = $this->scanSite($organizationId, $rootUid);
+            $warnings = $this->scanSite($organizationId, $siteInfos->getRootUid());
         }
 
-        return $this->buildStatusResult(
+        return new SiteStatus(
             $organizationId,
-            $warnings ? self::STATUS_EXISTING_WITH_WARNINGS : self::STATUS_EXISTING,
-            $rootUid,
-            $warnings);
+            $warnings ? SiteStatus::STATUS_EXISTING_WITH_WARNINGS : SiteStatus::STATUS_EXISTING,
+            $siteInfos,
+            $warnings
+        );
     }
 
     /**
@@ -1230,8 +1155,8 @@ class SiteController extends ActionController
         }
 
         $infos = $this->getSiteInfosAction($organizationId);
-        $originUrl = $infos['baseUrl'];
-        $rootUid = $infos['rootUid'];
+        $originUrl = $infos->getBaseUrl();
+        $rootUid = $infos->getRootUid();
 
         if (preg_replace('/https?:\/\//', '', $originUrl) == preg_replace('/https?:\/\//', '', $newDomain) ) {
             throw new \RuntimeException('The new domain should be different of the current one');

+ 83 - 0
ot_admin/Classes/Domain/Entity/ScanReport.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace Opentalent\OtAdmin\Domain\Entity;
+
+/**
+ * Report of a ScanController->scanAllAction() operation
+ */
+class ScanReport
+{
+    /**
+     * Date and time of the scan report
+     * @var \DateTime|null
+     */
+    protected ?\DateTime $datetime = null;
+
+    /**
+     * Numeric statistics (number of website in each state)
+     * @var array
+     */
+    protected array $stats = [];
+
+    /**
+     * Per-site results
+     * @var array
+     */
+    protected array $results = [];
+
+    public function __construct() {
+        $this->datetime = new \DateTime();
+    }
+
+    /**
+     * @return \DateTime
+     */
+    public function getDatetime(): \DateTime
+    {
+        return $this->datetime;
+    }
+
+    /**
+     * @return array
+     */
+    public function getStats(): array
+    {
+        return $this->stats;
+    }
+
+    /**
+     * @return array
+     */
+    public function getLabelledStats(): array
+    {
+        $labelled = [];
+        foreach ($this->stats as $k => $v) {
+            $labelled[SiteStatus::STATUSES[$k]] = $v;
+        }
+        return $labelled;
+    }
+
+    /**
+     * @return array
+     */
+    public function getResults(): array
+    {
+        return $this->results;
+    }
+
+    /**
+     * Set the result associated with the given organization id
+     *
+     * @param int $organizationId
+     * @param SiteStatus $siteStatus
+     */
+    public function setResultFor(int $organizationId, SiteStatus $siteStatus): void
+    {
+        $this->results[$organizationId] = $siteStatus;
+
+        if (!isset($this->stats[$siteStatus->getStatusCode()])) {
+            $this->stats[$siteStatus->getStatusCode()] = 0;
+        }
+        $this->stats[$siteStatus->getStatusCode()] += 1;
+    }
+}

+ 231 - 0
ot_admin/Classes/Domain/Entity/SiteInfos.php

@@ -0,0 +1,231 @@
+<?php
+
+namespace Opentalent\OtAdmin\Domain\Entity;
+
+/**
+ * Basic informations about a typo3 website
+ */
+class SiteInfos
+{
+    protected int $rootUid;
+
+    protected string $siteTitle = "";
+
+    protected string $baseUrl = "";
+
+    protected string $template = "";
+
+    protected string $preferences = "";
+
+    protected ?int $matomoId = null;
+
+    protected bool $deleted = false;
+
+    protected bool $hiddenOrRestricted = false;
+
+    protected array $mountedForBeUsers = [];
+
+    /**
+     * SiteInfos constructor.
+     * @param int $rootUid
+     * @param string|null $siteTitle
+     * @param string|null $baseUrl
+     * @param string|null $template
+     * @param string|null $preferences
+     * @param int|null $matomoId
+     * @param bool $deleted
+     * @param bool $hiddenOrRestricted
+     * @param array|null $mountedForBeUsers
+     */
+    public function __construct(
+        int $rootUid,
+        string $siteTitle = null,
+        string $baseUrl = null,
+        string $template = null,
+        string $preferences = null,
+        int $matomoId = null,
+        bool $deleted = false,
+        bool $hiddenOrRestricted = false,
+        array $mountedForBeUsers = null
+    )
+    {
+        $this->rootUid = $rootUid;
+        if ($siteTitle !== null) {
+            $this->siteTitle = $siteTitle;
+        }
+        if ($baseUrl !== null) {
+            $this->baseUrl = $baseUrl;
+        }
+        if ($template !== null) {
+            $this->template = $template;
+        }
+        if ($preferences !== null) {
+            $this->preferences = $preferences;
+        }
+        if ($matomoId !== null) {
+            $this->matomoId = $matomoId;
+        }
+        if ($deleted !== null) {
+            $this->deleted = $deleted;
+        }
+        if ($hiddenOrRestricted !== null) {
+            $this->hiddenOrRestricted = $hiddenOrRestricted;
+        }
+        if ($mountedForBeUsers !== null) {
+            $this->mountedForBeUsers = $mountedForBeUsers;
+        }
+    }
+
+    /**
+     * @return int
+     */
+    public function getRootUid(): int
+    {
+        return $this->rootUid;
+    }
+
+    /**
+     * @param int $rootUid
+     */
+    public function setRootUid(int $rootUid): void
+    {
+        $this->rootUid = $rootUid;
+    }
+
+    /**
+     * @return string
+     */
+    public function getSiteTitle(): string
+    {
+        return $this->siteTitle;
+    }
+
+    /**
+     * @param string $siteTitle
+     */
+    public function setSiteTitle(string $siteTitle): void
+    {
+        $this->siteTitle = $siteTitle;
+    }
+
+    /**
+     * @return string
+     */
+    public function getBaseUrl(): string
+    {
+        return $this->baseUrl;
+    }
+
+    /**
+     * @param string $baseUrl
+     */
+    public function setBaseUrl(string $baseUrl): void
+    {
+        $this->baseUrl = $baseUrl;
+    }
+
+    /**
+     * @return string
+     */
+    public function getTemplate(): string
+    {
+        return $this->template;
+    }
+
+    /**
+     * @param string $template
+     */
+    public function setTemplate(string $template): void
+    {
+        $this->template = $template;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPreferences(): string
+    {
+        return $this->preferences;
+    }
+
+    /**
+     * @param string $preferences
+     */
+    public function setPreferences(string $preferences): void
+    {
+        $this->preferences = $preferences;
+    }
+
+    /**
+     * @return int
+     */
+    public function getMatomoId(): ?int
+    {
+        return $this->matomoId;
+    }
+
+    /**
+     * @param int|null $matomoId
+     */
+    public function setMatomoId(?int $matomoId): void
+    {
+        $this->matomoId = $matomoId;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isDeleted(): bool
+    {
+        return $this->deleted;
+    }
+
+    /**
+     * @param bool $deleted
+     */
+    public function setDeleted(bool $deleted): void
+    {
+        $this->deleted = $deleted;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isHiddenOrRestricted(): bool
+    {
+        return $this->hiddenOrRestricted;
+    }
+
+    /**
+     * @param bool $hiddenOrRestricted
+     */
+    public function setHiddenOrRestricted(bool $hiddenOrRestricted): void
+    {
+        $this->hiddenOrRestricted = $hiddenOrRestricted;
+    }
+
+    /**
+     * @return array
+     */
+    public function getMountedForBeUsers(): array
+    {
+        return $this->mountedForBeUsers;
+    }
+
+    /**
+     * @param array $mountedForBeUsers
+     */
+    public function setMountedForBeUsers(array $mountedForBeUsers): void
+    {
+        $this->mountedForBeUsers = $mountedForBeUsers;
+    }
+
+    /**
+     * @param array $beUser
+     */
+    public function addMountedForBeUser(array $beUser): void
+    {
+        $this->mountedForBeUsers[] = $beUser;
+    }
+
+}

+ 212 - 0
ot_admin/Classes/Domain/Entity/SiteStatus.php

@@ -0,0 +1,212 @@
+<?php
+
+namespace Opentalent\OtAdmin\Domain\Entity;
+
+/**
+ * Status of a website as returned by SiteController->getSiteStatusAction()
+ */
+class SiteStatus
+{
+    // Websites statuses
+    const STATUS_UNKNOWN = 0;
+    const STATUS_NO_SUCH_WEBSITE = -1;
+    const STATUS_EXISTING = 5;
+    const STATUS_EXISTING_DELETED = 2;
+    const STATUS_EXISTING_HIDDEN = 3;
+    const STATUS_EXISTING_WITH_WARNINGS = 4;
+
+    const STATUSES = [
+        self::STATUS_UNKNOWN => 'Unknown',
+        self::STATUS_NO_SUCH_WEBSITE => 'Does not exist',
+        self::STATUS_EXISTING => 'Existing',
+        self::STATUS_EXISTING_DELETED => 'Existing, deleted',
+        self::STATUS_EXISTING_HIDDEN => 'Existing, hidden',
+        self::STATUS_EXISTING_WITH_WARNINGS => 'Existing with warnings',
+    ];
+
+    /**
+     * Id of the organization owning the website
+     * @var int
+     */
+    protected int $organizationId;
+
+    /**
+     * Status-code of the website
+     * @var int
+     */
+    protected int $statusCode = self::STATUS_UNKNOWN;
+
+    /**
+     * SiteInfos of the website
+     *
+     * @var SiteInfos
+     */
+    protected SiteInfos $siteInfos;
+
+    /**
+     * Optional list of warnings
+     *
+     * @var array|null
+     */
+    protected ?array $warnings = null;
+
+    public function __construct(
+        int $organizationId,
+        $statusCode = null,
+        $siteInfos = null,
+        $warnings = null
+    )
+    {
+        $this->organizationId = $organizationId;
+        if ($statusCode !== null) {
+            $this->setStatusCode($statusCode);
+        }
+        if ($siteInfos !== null) {
+            $this->setSiteInfos($siteInfos);
+        }
+        if ($warnings !== null) {
+            $this->setWarnings($warnings);
+        }
+    }
+
+    /**
+     * Return the site status as a serializable array
+     *
+     * @return array
+     */
+    public function toArray(): array
+    {
+        $infos = [
+            "Organization Id" => $this->getOrganizationId(),
+            "Status" => $this->getStatusLabel(),
+            "Message" => $this->getMessage()
+        ];
+
+        if ($this->getStatusCode() > 0) {
+            $infos["Root Uid"] = $this->getSiteInfos()->getRootUid();
+            $infos["Site's title"] = $this->getSiteInfos()->getSiteTitle();
+            $infos["Base Url"] = $this->getSiteInfos()->getBaseUrl();
+            $infos["Template"] = $this->getSiteInfos()->getTemplate();
+            $infos["Preferences"] = $this->getSiteInfos()->getPreferences();
+            $infos["Matomo id"] = $this->getSiteInfos()->getMatomoId();
+            $infos["Mounted for: "] = $this->getSiteInfos()->getMountedForBeUsers();
+
+            if ($this->useWarnings()) {
+                $infos["Warnings"] = $this->getWarnings();
+            }
+        }
+        return $infos;
+    }
+
+    /**
+     * @return int
+     */
+    public function getOrganizationId(): int
+    {
+        return $this->organizationId;
+    }
+
+    /**
+     * @return int
+     */
+    public function getStatusCode(): int
+    {
+        return $this->statusCode;
+    }
+
+    /**
+     * @return string
+     */
+    public function getStatusLabel(): string
+    {
+        return self::STATUSES[$this->statusCode];
+    }
+
+    /**
+     * @return string
+     */
+    public function getMessage(): string
+    {
+        if($this->getStatusCode() == self::STATUS_NO_SUCH_WEBSITE) {
+            return 'No website were found for organization ' . $this->getOrganizationId();
+        }
+        elseif ($this->getStatusCode() == self::STATUS_EXISTING) {
+            return 'A website exists for organization ' . $this->getOrganizationId();
+        }
+        elseif ($this->getStatusCode() == self::STATUS_EXISTING_DELETED) {
+            return 'A website exists for organization ' . $this->getOrganizationId() . ', but has been deleted';
+        }
+        elseif ($this->getStatusCode() == self::STATUS_EXISTING_HIDDEN) {
+            return 'A website exists for organization ' . $this->getOrganizationId() . ', but is hidden or has a restricted access';
+        } elseif ($this->getStatusCode() == self::STATUS_EXISTING_WITH_WARNINGS) {
+            return 'A website exists for organization ' . $this->getOrganizationId() . ', but warnings were raised';
+        }
+    }
+
+    /**
+     * @param int $statusCode
+     */
+    public function setStatusCode(int $statusCode): void
+    {
+        if (!isset(self::STATUSES[$statusCode])) {
+            throw new \InvalidArgumentException('Invalid status code : ' . $statusCode);
+        }
+        $this->statusCode = $statusCode;
+    }
+
+    /**
+     * @return SiteInfos
+     */
+    public function getSiteInfos(): SiteInfos
+    {
+        return $this->siteInfos;
+    }
+
+    /**
+     * @param SiteInfos $siteInfos
+     */
+    public function setSiteInfos(SiteInfos $siteInfos): void
+    {
+        $this->siteInfos = $siteInfos;
+    }
+
+    /**
+     * @return array|null
+     */
+    public function getWarnings(): ?array
+    {
+        return $this->warnings;
+    }
+
+    /**
+     * @param array $warnings
+     */
+    public function setWarnings(array $warnings): void
+    {
+        $this->warnings = $warnings;
+    }
+
+    /**
+     * Warnings have been scanned (the warnings array still can be empty)
+     */
+    public function useWarnings(): bool
+    {
+        return $this->warnings !== null;
+    }
+
+    /**
+     * Warnings have been logged
+     */
+    public function hasWarnings(): bool
+    {
+        return count($this->warnings) > 0;
+    }
+
+    /**
+     * @param string $warning
+     */
+    public function addWarnings(string $warning): void
+    {
+        $this->warnings[] = $warning;
+    }
+}

+ 1 - 1
ot_admin/Classes/Http/ApiController.php

@@ -304,7 +304,7 @@ class ApiController implements LoggerAwareInterface
         $full = (isset($queryParams['full']) && $queryParams['full']);
         $status = $controller->getSiteStatusAction($organizationId, $full);
 
-        return new JsonResponse($status);
+        return new JsonResponse($status->toArray());
     }
 
     /**

+ 0 - 5
ot_admin/Configuration/Backend/Routes.php

@@ -7,11 +7,6 @@ use Opentalent\OtAdmin\Http\ApiController;
 
 return [
     // Create a new organization's website
-    'site_infos' => [
-        'path' => '/otadmin/site/infos',
-        'target' => ApiController::class . '::getSiteInfosAction',
-        'access' => 'public'
-    ],
     'site_create' => [
         'path' => '/otadmin/site/create',
         'target' => ApiController::class . '::createSiteAction',

+ 0 - 3
ot_admin/Configuration/Commands.php

@@ -10,9 +10,6 @@
 // https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/CommandControllers/Index.html#creating-a-new-command-in-extensions
 
 return [
-    'ot:site:infos' => [
-        'class' => Opentalent\OtAdmin\Command\GetSiteInfosCommand::class
-    ],
     'ot:site:create' => [
         'class' => Opentalent\OtAdmin\Command\CreateSiteCommand::class
     ],

+ 0 - 6
ot_admin/Configuration/Services.yaml

@@ -7,12 +7,6 @@ services:
   Opentalent\OtAdmin\:
     resource: '../Classes/*'
 
-  Opentalent\OtAdmin\Command\GetSiteInfosCommand:
-    tags:
-      - name: 'ot:site:infos'
-        command: 'ot:site:infos'
-        schedulable: false
-
   Opentalent\OtAdmin\Command\CreateOrganizationCommand:
     tags:
       - name: 'ot:site:create'

+ 12 - 6
ot_admin/templates/scan_report.twig

@@ -40,17 +40,23 @@
                         <th>Status</th>
                         <th>Root uid</th>
                         <th>Site's title</th>
+                        <th>Url</th>
                         <th>Warnings</th>
                     </tr>
                 </thead>
                 <tbody>
                 {% for status in scan.results %}
                     <tr>
-                        <td>{{ status.organization_id }}</td>
-                        <td>{{ status.status }}</td>
-                        <td>{{ status.root_uid }}</td>
-                        <td>{{ status.title }}</td>
-                        <td><ul>{% for warning in status.warnings %}<li>{{ warning }}</li>{% endfor %}</ul></td>
+                        <td>{{ status.organizationId }}</td>
+                        <td>{{ status.statusLabel }}</td>
+                        {% if status.statusCode > 0 %}
+                            <td>{{ status.siteInfos.rootUid }}</td>
+                            <td>{{ status.siteInfos.siteTitle }}</td>
+                            <td>{{ status.siteInfos.baseUrl }}</td>
+                            {% if status.useWarnings %}
+                                <td><ul>{% for warning in status.warnings %}<li>{{ warning }}</li>{% endfor %}</ul></td>
+                            {% endif %}
+                        {% endif %}
                     </tr>
                 {% endfor %}
                 </tbody>
@@ -68,7 +74,7 @@
             // Charts
             var labels = [];
             var values = [];
-            {% for lbl, val in scan.stats %}
+            {% for lbl, val in scan.labelledStats %}
             labels.push('{{ lbl }}');
             values.push({{ val }});
             {% endfor %}