Bladeren bron

Merge branch 'master' into feature/structure-details-frame

Conflicts:
	ot_templating/Resources/Public/assets/Classic/script/structures.js
	ot_templating/Resources/Public/assets/Classic/style/classic-blue.css
	ot_templating/Resources/Public/assets/Classic/style/classic-blue.css.map
	ot_templating/Resources/Public/assets/Classic/style/classic-green.css
	ot_templating/Resources/Public/assets/Classic/style/classic-green.css.map
	ot_templating/Resources/Public/assets/Classic/style/classic-grey.css
	ot_templating/Resources/Public/assets/Classic/style/classic-grey.css.map
	ot_templating/Resources/Public/assets/Classic/style/classic-light-blue.css
	ot_templating/Resources/Public/assets/Classic/style/classic-light-blue.css.map
	ot_templating/Resources/Public/assets/Classic/style/classic-light-red.css
	ot_templating/Resources/Public/assets/Classic/style/classic-light-red.css.map
	ot_templating/Resources/Public/assets/Classic/style/classic-orange.css
	ot_templating/Resources/Public/assets/Classic/style/classic-orange.css.map
	ot_templating/Resources/Public/assets/Classic/style/classic-purple.css
	ot_templating/Resources/Public/assets/Classic/style/classic-purple.css.map
	ot_templating/Resources/Public/assets/Classic/style/classic-red.css
	ot_templating/Resources/Public/assets/Classic/style/classic-red.css.map
	ot_templating/Resources/Public/assets/Classic/style/module/_structures.scss
	ot_templating/Resources/Public/assets/Classic/style/style.css
	ot_templating/Resources/Public/assets/Classic/style/style.css.map
Olivier Massot 4 jaren geleden
bovenliggende
commit
2573dfbf37

+ 0 - 36
ot_admin/Classes/Middleware/OtBackendUserAuthenticator.php

@@ -1,36 +0,0 @@
-<?php
-namespace Opentalent\OtAdmin\Middleware;
-
-use Opentalent\OtAdmin\Http\ApiController;
-use TYPO3\CMS\Backend\Middleware\BackendUserAuthenticator;
-
-/**
- * Overrides (XClass) the core BackendUserAuthenticator middleware to extend
- * the public routes to the /otadmin/* routes (only for authorized Ips)
- *
- * @internal
- */
-class OtBackendUserAuthenticator extends BackendUserAuthenticator
-{
-    /**
-     * Check if the user is required for the request
-     * If we're trying to do a login or an ajax login, don't require a user
-     *
-     * @param string $routePath the Route path to check against
-     * @return bool whether the request can proceed without a login required
-     */
-    protected function isLoggedInBackendUserRequired(string $routePath): bool
-    {
-        $isOtAdminRoute = (bool)preg_match('/\/otadmin\/.+/', $routePath);
-        $ipAllowed = ApiController::isIpAllowed($_SERVER['REMOTE_ADDR']);
-        if ($isOtAdminRoute) {
-            if ($ipAllowed) {
-                return true;
-            } else {
-                throw new \RuntimeException('An unauthorized IP (' . $_SERVER['REMOTE_ADDR'] . ') ' .
-                                                    'tried to run the following ot-admin command: ' . $_SERVER['QUERY_STRING']);
-            }
-        }
-        return parent::isLoggedInBackendUserRequired($routePath);
-    }
-}

+ 0 - 10
ot_admin/ext_localconf.php

@@ -1,10 +0,0 @@
-<?php
-defined('TYPO3_MODE') || die();
-
-// Because of this issue https://forge.typo3.org/issues/89449,
-// we have to xclass the BackendUserAuthenticator backend middleware
-// to allow routes to be public (but restricted to authorized ips)
-$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][TYPO3\CMS\Backend\Middleware\BackendUserAuthenticator::class] = [
-    'className' => Opentalent\OtAdmin\Middleware\OtBackendUserAuthenticator::class
-];
-

+ 73 - 0
ot_core/Classes/Http/ApiController.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace Opentalent\OtCore\Http;
+
+use PDO;
+use TYPO3\CMS\Core\Http\JsonResponse;
+use TYPO3\CMS\Core\Http\ServerRequest;
+
+/**
+ * Actions for Http API calls
+ *
+ * @package Opentalent\OtCore\Http
+ */
+class ApiController
+{
+    /**
+     * -- Target of the route 'all' --
+     *
+     * Get all of the Opentalent structures directly
+     * from the Opentalent DB (API Platform is too slow with so many records)
+     *
+     * @param ServerRequest $request
+     * @return JsonResponse
+     */
+    public function getAllStructures(ServerRequest $request)
+    {
+        if ($_SERVER['HTTP_HOST'] == 'typo3' | $_SERVER['HTTP_HOST'] == 'local.sub.opentalent.fr') {
+            $db_host = 'db';
+        } elseif ($_SERVER['HTTP_HOST'] == 'preprod.opentalent.fr') {
+            $db_host = 'localhost';
+        } else {
+            $db_host = 'prod-back';
+        }
+
+        $cnn = new PDO(
+            "mysql:host=" . $db_host . ";dbname=opentalent",
+            'dbcloner',
+            'wWZ4hYcrmHLW2mUK',
+            array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8')
+        );
+        $cnn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+        $stmt = $cnn->prepare(
+            "SELECT o.id, o.name, o.logo_id as logoId, o.principalType, p.otherWebsite as website, a.latitude, a.longitude,
+           TRIM(BOTH ' ' FROM CONCAT(a.streetAddress, ' ', a.streetAddressSecond, ' ', a.streetAddressThird)) AS streetAddress,
+           a.postalCode, a.addressCity, c.name AS country,
+            (SELECT CONCAT(GROUP_CONCAT(DISTINCT CONCAT(f.code)))
+            FROM Activity AS a
+            LEFT JOIN activity_categories AS ac ON(ac.activity_id = a.id)
+            LEFT JOIN Categories AS cs ON (cs.id = ac.categories_id)
+            LEFT JOIN Familly AS f ON(f.id = cs.familly_id)
+            WHERE a.organization_id = o.id) AS categories,
+           n1.parent_id as n1Id, net1.name as n1Name, n2.parent_id as n2Id, n3.parent_id as n3Id, n4.parent_id as n4Id, n5.parent_id as n5Id,
+           CONCAT_WS(',', n1.parent_id, n2.parent_id, n3.parent_id, n4.parent_id, n5.parent_id) as parents
+    FROM opentalent.Organization o
+        INNER JOIN opentalent.Parameters p on o.parameters_id = p.id
+        INNER JOIN (SELECT * FROM opentalent.OrganizationAddressPostal WHERE `type`='ADDRESS_HEAD_OFFICE') oa on oa.organization_id = o.id
+        INNER JOIN opentalent.AddressPostal a on oa.addressPostal_id = a.id
+        LEFT JOIN opentalent.Country c ON (c.id = a.addressCountry_id)
+        INNER JOIN (SELECT * FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n1 on n1.organization_id = o.id
+        INNER JOIN Organization net1 ON net1.id = n1.parent_id
+        LEFT JOIN (SELECT * FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n2 on n2.organization_id = n1.parent_id
+        LEFT JOIN (SELECT * FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n3 on n3.organization_id = n2.parent_id
+        LEFT JOIN (SELECT * FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n4 on n4.organization_id = n3.parent_id
+        LEFT JOIN (SELECT * FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n5 on n5.organization_id = n4.parent_id
+"
+        );
+        $stmt->execute();
+        $stmt->setFetchMode(PDO::FETCH_ASSOC);
+        $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
+        return new JsonResponse($data);
+    }
+}

+ 43 - 0
ot_core/Classes/Middleware/OtBackendUserAuthenticator.php

@@ -0,0 +1,43 @@
+<?php
+namespace Opentalent\OtCore\Middleware;
+
+use PHPUnit\Exception;
+use TYPO3\CMS\Backend\Middleware\BackendUserAuthenticator;
+
+/**
+ * Overrides (XClass) the core BackendUserAuthenticator middleware to extend
+ * the public routes to the /otadmin/* routes (only for authorized Ips)
+ *
+ * @internal
+ */
+class OtBackendUserAuthenticator extends BackendUserAuthenticator
+{
+    /**
+     * Check if the user is required for the request
+     * If we're trying to do a login or an ajax login, don't require a user
+     *
+     * @param string $routePath the Route path to check against
+     * @return bool whether the request can proceed without a login required
+     */
+    protected function isLoggedInBackendUserRequired(string $routePath): bool
+    {
+        if (class_exists('\Opentalent\OtAdmin\Http\ApiController')) {
+            // The routes defined in the ot-admin extension are limited to some ips
+            if (preg_match('/\/otadmin\/.+/', $routePath)) {
+                if (\Opentalent\OtAdmin\Http\ApiController::isIpAllowed($_SERVER['REMOTE_ADDR'])) {
+                    return true;
+                } else {
+                    throw new \RuntimeException('An unauthorized IP (' . $_SERVER['REMOTE_ADDR'] . ') ' .
+                                                        'tried to run the following ot-admin command: ' . $_SERVER['QUERY_STRING']);
+                }
+            }
+        }
+
+        // The routes defined in the ot-core extension are public
+        if (preg_match('/\/otcore\/.+/', $routePath)) {
+            return true;
+        }
+
+        return parent::isLoggedInBackendUserRequired($routePath);
+    }
+}

+ 15 - 0
ot_core/Configuration/Backend/Routes.php

@@ -0,0 +1,15 @@
+<?php
+
+use Opentalent\OtCore\Http\ApiController;
+
+// Defines the routes used to trigger the admin actions
+// @see https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/BackendRouting/Index.html
+
+return [
+    // Get a json array containing all of the opentalent structures
+    'all-structures' => [
+        'path' => '/otcore/structures/all',
+        'target' => ApiController::class . '::getAllStructures',
+        'access' => 'public'
+    ]
+];

+ 7 - 0
ot_core/ext_localconf.php

@@ -21,5 +21,12 @@ $GLOBALS['TYPO3_CONF_VARS']['LOG']['Opentalent']['OtCore']['writerConfiguration'
     ]
 ];
 
+// Because of this issue https://forge.typo3.org/issues/89449,
+// we have to xclass the BackendUserAuthenticator backend middleware
+// to allow public routes to be really public
+$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][TYPO3\CMS\Backend\Middleware\BackendUserAuthenticator::class] = [
+    'className' => Opentalent\OtCore\Middleware\OtBackendUserAuthenticator::class
+];
+
 
 $GLOBALS['TYPO3_CONF_VARS']['EXT']['news']['Controller/NewsController.php']['createDemandObjectFromSettings'] = ['Opentalent\OtTemplating\News\NewsFilter->createDemandObjectFromSettings'];

+ 3 - 0
ot_templating/Resources/Private/Language/locallang.xlf

@@ -390,6 +390,9 @@
 			<trans-unit id="an_error_occured">
 				<source>Une erreur s'est produite, nous nous excusons pour la gêne occasionnée</source>
 			</trans-unit>
+			<trans-unit id="results">
+				<source>résultats</source>
+			</trans-unit>
 			<trans-unit id="theme_updated">
 				<source>Le thème a bien été modifié</source>
 			</trans-unit>

File diff suppressed because it is too large
+ 3 - 1
ot_templating/Resources/Private/Layouts/Classic/StructuresFrame.html


+ 65 - 40
ot_templating/Resources/Public/assets/Classic/script/structures.js

@@ -1,14 +1,6 @@
 // Specific code for the 'federation-structures' page
 
-const variants_uris = {
-    "preprod.opentalent.fr": "https://api.preprod.opentalent.fr",
-    "local.sub.opentalent.fr": "https://local.api.opentalent.fr",
-    "typo3": "http://docker.nginx.opentalent.fr"
-};
-
-const base_uri = variants_uris[$(location).attr('hostname')];
-let apiGetUrl = base_uri + '/api/public/federation_structures?_format=json&page=1&itemsPerPage=99999';
-
+const apiGetUrl = "/typo3/index.php?route=/otcore/structures/all";
 
 // Converts numeric degrees to radians
 function toRad(Value)
@@ -69,7 +61,7 @@ $(document).ready(function() {
     let resetButton = form.find("button.reset-search").first();
     let submitButton = form.find("button.submit-search").first();
 
-    let organizationId = queryParameters.get('organization-id') || structureFrame.data('organization-id');
+    let organizationId = parseInt(queryParameters.get('organization-id') || structureFrame.data('organization-id'));
     if (!organizationId) {
         pleaseWaitSpan.hide();
         errorMsgSpan.show();
@@ -151,6 +143,11 @@ $(document).ready(function() {
     // Does the given structure match the current query
     function matchCurrentQuery(structure) {
 
+        // Is the structure a member of the website federation?
+        if (![structure.n1Id, structure.n2Id, structure.n3Id, structure.n4Id, structure.n5Id].includes(organizationId)) {
+            return false;
+        }
+
         // Filter by name
         if (query['what'] && !structure.name.toLowerCase().includes(query['what'].toLowerCase())) {
             return false;
@@ -207,10 +204,10 @@ $(document).ready(function() {
     function populateFederationsSelect() {
         federationSelect.children('option:not(:first)').remove();
         let has_options = false;
+
         structures.forEach(function (structure) {
             if (structure.n1Id === organizationId && structure.principalType.endsWith('FEDERATION')) {
-                let id = structure['@id'].split('/').pop()
-                let option = '<option value="' + id + '">' + structure.name + '</option>';
+                let option = '<option value="' + structure.id + '">' + structure.name + '</option>';
                 federationSelect.append(option);
                 has_options = true;
             }
@@ -260,24 +257,31 @@ $(document).ready(function() {
             }
         });
 
+        sortKeys = function (x) {
+            return x.addressCity.toLowerCase() + x.name.toLowerCase();
+        }
+        results.sort((a, b) => sortKeys(a).localeCompare(sortKeys(b)));
+
         // ** Show the results for the current page
         let index = 0;
 
         results.forEach(function(structure) {
             if (((currentPage - 1) * itemsPerPage) <= index && index < (currentPage * itemsPerPage)) {
                 let cardDiv = $(cardDivModel).clone();
+                let categoryTagModel = cardDiv.find('.structure-category-model').first();
 
                 cardDiv.data('id', structure.id);
 
-                let categoryTagModel = cardDiv.find('.structure-category-model').first();
-                structure.categories.forEach(function (cat) {
-                    let tag = categoryTagModel.clone();
-                    tag.text(structures_categories[cat]);
-                    tag.removeClass('structure-category-model')
-                    tag.addClass('structure-category')
-                    tag.show();
-                    categoryTagModel.parent().append(tag);
-                });
+                if (structure.categories !== null) {
+                    structure.categories.forEach(function (cat) {
+                        let tag = categoryTagModel.clone();
+                        tag.text(structures_categories[cat]);
+                        tag.removeClass('structure-category-model')
+                        tag.addClass('structure-category')
+                        tag.show();
+                        categoryTagModel.parent().append(tag);
+                    });
+                }
 
                 cardDiv.find('.structure-poster').first().children('img').first().attr('src', structure.logoUri);
                 cardDiv.find('.structure-name').first().text(structure.name);
@@ -310,8 +314,12 @@ $(document).ready(function() {
             map.addLayer(clusters);
         }
 
-        // ** Update pagination
+        // ** Update results count and pagination
         let resultsCount = results.length;
+
+        resultsCountMessage.show();
+        resultsCountVar.text("" + resultsCount);
+
         let pagesCount = Math.floor(resultsCount / itemsPerPage) + 1;
         gotoLastPage.data("page", pagesCount);
 
@@ -355,24 +363,41 @@ $(document).ready(function() {
     }
 
     // #### Load structures data and refresh
-    var structures = [];
-    $.ajax({
-        type: 'GET',
-        url: apiGetUrl,
-        dataType: "json",
-        contentType: "application/json; charset=utf-8",
-        timeout : 5000
-    })
-    .done(function(res) {
-        structures = res["hydra:member"];
-        populateFederationsSelect();
-        refresh();
-    })
-    .fail(function(xhr, textStatus, errorThrown) {
-        pleaseWaitSpan.hide();
-        errorMsgSpan.show();
-        throw 'Error while fetching the API data: ' + textStatus  + ' - ' + errorThrown;
-    });
+    var structures;
+
+    function loadStructures() {
+        structures = []
+
+        $.ajax({
+            type: 'GET',
+            url: apiGetUrl,
+            dataType: "json",
+            contentType: "application/json; charset=utf-8",
+            timeout : 12000,
+        })
+        .done(function(res) {
+
+            res.forEach(function(item) {
+                structure = item;
+                structure.n1Id = parseInt(structure.n1Id);
+                structure.n2Id = parseInt(structure.n2Id);
+                structure.n3Id = parseInt(structure.n3Id);
+                structure.n4Id = parseInt(structure.n4Id);
+                structure.n5Id = parseInt(structure.n5Id);
+                structure.categories = structure.categories !== null ? structure.categories.split(",") : [];
+                structures.push(structure);
+            })
+
+            populateFederationsSelect();
+            refresh();
+        })
+        .fail(function(xhr, textStatus, errorThrown) {
+            pleaseWaitSpan.hide();
+            errorMsgSpan.show();
+            throw 'Error while fetching the API data: ' + textStatus  + ' - ' + errorThrown;
+        });
+    }
+    loadStructures();
 
 
     // #### Events

+ 0 - 1
ot_templating/Resources/Public/assets/Classic/style/module/_structures.scss

@@ -137,5 +137,4 @@ $input-border-color: #bfbfbf;
     text-decoration: none;
     font-weight: bold;
   }
-
 }

Some files were not shown because too many files changed in this diff