Explorar o código

add the .htaccess for docker

Olivier Massot %!s(int64=4) %!d(string=hai) anos
pai
achega
fe146c9340
Modificáronse 100 ficheiros con 2250 adicións e 515 borrados
  1. 3 2
      README.md
  2. 369 0
      docker/conf/.htaccess
  3. 15 3
      docker/conf/LocalConfiguration.php
  4. 3 2
      docker/conf/composer.json
  5. 12 5
      ot_admin/Classes/Command/CreateSiteCommand.php
  6. 21 7
      ot_admin/Classes/Controller/SiteController.php
  7. 0 19
      ot_admin/ext_localconf.php
  8. 4 3
      ot_connect/Classes/Middleware/RequestHandler.php
  9. 2 2
      ot_connect/Configuration/RequestMiddlewares.php
  10. 1 1
      ot_connect/ext_emconf.php
  11. 5 31
      ot_core/Classes/Cache/OtCacheManager.php
  12. 44 0
      ot_core/Classes/Controller/SelectedSiteController.php
  13. 1 1
      ot_core/Classes/Domain/Model/Donor.php
  14. 1 1
      ot_core/Classes/Domain/Model/Event.php
  15. 1 1
      ot_core/Classes/Domain/Model/Member.php
  16. 1 1
      ot_core/Classes/Domain/Model/Organization.php
  17. 2 2
      ot_core/Classes/Domain/Repository/ApiPagedCollection.php
  18. 2 2
      ot_core/Classes/Domain/Repository/BaseApiRepository.php
  19. 3 3
      ot_core/Classes/Domain/Repository/DonorRepository.php
  20. 3 3
      ot_core/Classes/Domain/Repository/EventRepository.php
  21. 3 3
      ot_core/Classes/Domain/Repository/MemberRepository.php
  22. 3 3
      ot_core/Classes/Domain/Repository/OrganizationRepository.php
  23. 2 2
      ot_core/Classes/Exception/ApiRequestException.php
  24. 18 0
      ot_core/Classes/Exception/NoSiteSelected.php
  25. 53 0
      ot_core/Classes/Logging/OtLogger.php
  26. 55 58
      ot_core/Classes/Page/OtPageRepository.php
  27. 40 0
      ot_core/Classes/ViewHelpers/OtAbstractViewHelper.php
  28. 0 0
      ot_core/Configuration/TCA/Overrides/Readme.md
  29. 0 0
      ot_core/Configuration/TCA/Overrides/pages.php
  30. 0 0
      ot_core/Configuration/TCA/Readme.md
  31. 18 0
      ot_core/Readme.md
  32. 12 0
      ot_core/Resources/Private/Language/locallang.xlf
  33. 7 0
      ot_core/Resources/Private/Layouts/Backend/Default.html
  34. 9 0
      ot_core/Resources/Private/Templates/SelectedSite/DisplayNoSelectedPageWarning.html
  35. BIN=BIN
      ot_core/Resources/Public/Icons/Extension.png
  36. BIN=BIN
      ot_core/Resources/Public/Icons/Extension_white.png
  37. 44 0
      ot_core/Resources/Public/assets/Backend/style/ot_be_module.css
  38. 33 0
      ot_core/composer.json
  39. 31 0
      ot_core/ext_emconf.php
  40. 25 0
      ot_core/ext_localconf.php
  41. 104 0
      ot_stats/Classes/Controller/OtStatsController.php
  42. 144 0
      ot_stats/Classes/Domain/Model/MatomoWebsite.php
  43. 269 0
      ot_stats/Classes/Domain/Repository/MatomoWebsiteRepository.php
  44. 75 0
      ot_stats/Classes/Middleware/RequestHandler.php
  45. 39 0
      ot_stats/Classes/Settings/StatsSettingsRepository.php
  46. 45 0
      ot_stats/Classes/ViewHelpers/MatomoSiteIdViewHelper.php
  47. 17 0
      ot_stats/Configuration/RequestMiddlewares.php
  48. 26 0
      ot_stats/Readme.md
  49. 17 0
      ot_stats/Resources/Private/Language/locallang_mod.xlf
  50. 8 0
      ot_stats/Resources/Private/Layouts/Backend/Default.html
  51. 46 0
      ot_stats/Resources/Private/Partials/ReportCard.html
  52. 26 0
      ot_stats/Resources/Private/Templates/Header/Include.html
  53. 20 0
      ot_stats/Resources/Private/Templates/OtStats/AskForActivationConfirmation.html
  54. 36 0
      ot_stats/Resources/Private/Templates/OtStats/AskForDeactivationConfirmation.html
  55. 134 0
      ot_stats/Resources/Private/Templates/OtStats/Index.html
  56. BIN=BIN
      ot_stats/Resources/Public/Icons/Extension.png
  57. BIN=BIN
      ot_stats/Resources/Public/Icons/Extension_white.png
  58. BIN=BIN
      ot_stats/Resources/Public/Icons/pie-chart.png
  59. 7 0
      ot_stats/Resources/Public/assets/Backend/script/iframeResizer.min.js
  60. 74 0
      ot_stats/Resources/Public/assets/Backend/style/ot_stats.css
  61. 26 0
      ot_stats/composer.json
  62. 32 0
      ot_stats/ext_emconf.php
  63. 29 0
      ot_stats/ext_tables.php
  64. 8 0
      ot_stats/ext_tables.sql
  65. 14 62
      ot_templating/Classes/Controller/OtCustomizerController.php
  66. 1 1
      ot_templating/Classes/News/NewsFilter.php
  67. 1 0
      ot_templating/Classes/Page/ErrorHandler.php
  68. 83 0
      ot_templating/Classes/Templating/TemplateRepository.php
  69. 0 35
      ot_templating/Classes/Utility/Tsfe.php
  70. 2 14
      ot_templating/Classes/ViewHelpers/Carousel/ImagesViewHelper.php
  71. 4 9
      ot_templating/Classes/ViewHelpers/Donors/GetAllViewHelper.php
  72. 5 8
      ot_templating/Classes/ViewHelpers/Events/GetAllViewHelper.php
  73. 5 8
      ot_templating/Classes/ViewHelpers/Events/GetByIdViewHelper.php
  74. 5 11
      ot_templating/Classes/ViewHelpers/Events/GetNextViewHelper.php
  75. 3 3
      ot_templating/Classes/ViewHelpers/EventsPage/GetIdViewHelper.php
  76. 3 4
      ot_templating/Classes/ViewHelpers/EventsPage/GetUriViewHelper.php
  77. 4 3
      ot_templating/Classes/ViewHelpers/GetPageUidViewHelper.php
  78. 0 7
      ot_templating/Classes/ViewHelpers/ImagePViewHelper.php
  79. 2 3
      ot_templating/Classes/ViewHelpers/LoginFailedViewHelper.php
  80. 4 7
      ot_templating/Classes/ViewHelpers/Members/GetAllCaViewHelper.php
  81. 4 7
      ot_templating/Classes/ViewHelpers/Members/GetAllViewHelper.php
  82. 5 8
      ot_templating/Classes/ViewHelpers/Organizations/GetByIdViewHelper.php
  83. 4 7
      ot_templating/Classes/ViewHelpers/Organizations/GetChildrenViewHelper.php
  84. 2 2
      ot_templating/Classes/ViewHelpers/Request/GetArgumentViewHelper.php
  85. 2 2
      ot_templating/Classes/ViewHelpers/Request/GetParameterViewHelper.php
  86. 2 11
      ot_templating/Classes/ViewHelpers/Request/GetViewHelper.php
  87. 2 2
      ot_templating/Classes/ViewHelpers/Request/WithPageViewHelper.php
  88. 3 3
      ot_templating/Classes/ViewHelpers/RootPage/GetIdViewHelper.php
  89. 3 5
      ot_templating/Classes/ViewHelpers/RootPage/GetUriViewHelper.php
  90. 8 5
      ot_templating/Classes/ViewHelpers/Template/CurrentViewHelper.php
  91. 9 4
      ot_templating/Classes/ViewHelpers/Template/GetPreferenceViewHelper.php
  92. 8 4
      ot_templating/Classes/ViewHelpers/Template/GetPreferencesViewHelper.php
  93. 2 2
      ot_templating/Classes/ViewHelpers/Utilities/CountViewHelper.php
  94. 1 1
      ot_templating/Configuration/TypoScript/constants.txt
  95. 2 2
      ot_templating/Configuration/TypoScript/setup.txt
  96. 6 4
      ot_templating/Readme.md
  97. 3 4
      ot_templating/Resources/Private/Layouts/Backend/Default.html
  98. 9 55
      ot_templating/Resources/Private/Layouts/Modern/Members.html
  99. 9 55
      ot_templating/Resources/Private/Layouts/Modern/MembersCa.html
  100. 2 2
      ot_templating/Resources/Private/Partials/Classic/Assets.html

+ 3 - 2
README.md

@@ -2,7 +2,7 @@
 
 ### Pré-requis:
 
-* php 7.2
+* php 7.4
 * Typo3 v9.5 (en mode composer)
 
 ### Les extensions
@@ -17,9 +17,10 @@ du répertoire de l'application typo3
 
     	"autoload": {
     		"psr-4": {
-                "Opentalent\\OtWidgets\\": "public/typo3conf/ext/ot_widgets/Classes",
+                "Opentalent\\OtCore\\": "public/typo3conf/ext/ot_core/Classes",
                 "Opentalent\\OtConnect\\": "public/typo3conf/ext/ot_connect/Classes",
                 "Opentalent\\OtTemplating\\": "public/typo3conf/ext/ot_templating/Classes",
+                "Opentalent\\OtStats\\": "public/typo3conf/ext/ot_stats/Classes",
                 "Opentalent\\OtAdmin\\": "public/typo3conf/ext/ot_admin/Classes"
     		}
     	}

+ 369 - 0
docker/conf/.htaccess

@@ -0,0 +1,369 @@
+#####
+#
+# Example .htaccess file for TYPO3 CMS - for use with Apache Webserver
+#
+# This file includes settings for the following configuration options:
+#
+# - Compression
+# - Caching
+# - MIME types
+# - Cross Origin requests
+# - Rewriting and Access
+# - Miscellaneous
+# - PHP optimisation
+#
+# If you want to use it, you have to copy it to the root folder of your TYPO3 installation (if its
+# not there already) and rename it to '.htaccess'. To make .htaccess files work, you might need to
+# adjust the 'AllowOverride' directive in your Apache configuration file.
+#
+# IMPORTANT: You may need to change this file depending on your TYPO3 installation!
+#            Consider adding this file's content to your webserver's configuration directly for speed improvement
+#
+# Lots of the options are taken from https://github.com/h5bp/html5-boilerplate/blob/master/dist/.htaccess
+#
+####
+
+SetEnv TYPO3_CONTEXT Development
+SetEnv TYPO3_OPTIMIZE 1
+
+### Begin: Compression ###
+
+# Compressing resource files will save bandwidth and so improve loading speed especially for users
+# with slower internet connections. TYPO3 can compress the .js and .css files for you.
+# *) Uncomment the following lines and
+# *) Set $GLOBALS['TYPO3_CONF_VARS']['BE']['compressionLevel'] = 9 for the Backend
+# *) Set $GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel'] = 9 together with the TypoScript properties
+#    config.compressJs and config.compressCss for GZIP compression of Frontend JS and CSS files.
+
+<FilesMatch "\.js\.gzip$">
+	AddType "text/javascript" .gzip
+</FilesMatch>
+<FilesMatch "\.css\.gzip$">
+	AddType "text/css" .gzip
+</FilesMatch>
+AddEncoding gzip .gzip
+
+<IfModule mod_deflate.c>
+	# Force compression for mangled `Accept-Encoding` request headers
+	<IfModule mod_setenvif.c>
+		<IfModule mod_headers.c>
+			SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
+			RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
+		</IfModule>
+	</IfModule>
+
+	# Compress all output labeled with one of the following media types.
+	#
+	# (!) For Apache versions below version 2.3.7 you don't need to
+	# enable `mod_filter` and can remove the `<IfModule mod_filter.c>`
+	# and `</IfModule>` lines as `AddOutputFilterByType` is still in
+	# the core directives.
+	#
+	# https://httpd.apache.org/docs/current/mod/mod_filter.html#addoutputfilterbytype
+
+	<IfModule mod_filter.c>
+		AddOutputFilterByType DEFLATE application/atom+xml \
+			application/javascript \
+			application/json \
+			application/ld+json \
+			application/manifest+json \
+			application/rdf+xml \
+			application/rss+xml \
+			application/schema+json \
+			application/vnd.geo+json \
+			application/vnd.ms-fontobject \
+			application/x-font-ttf \
+			application/x-javascript \
+			application/x-web-app-manifest+json \
+			application/xhtml+xml \
+			application/xml \
+			font/eot \
+			font/opentype \
+			image/bmp \
+			image/svg+xml \
+			image/vnd.microsoft.icon \
+			image/x-icon \
+			text/cache-manifest \
+			text/css \
+			text/html \
+			text/javascript \
+			text/plain \
+			text/vcard \
+			text/vnd.rim.location.xloc \
+			text/vtt \
+			text/x-component \
+			text/x-cross-domain-policy \
+			text/xml
+	</IfModule>
+
+	<IfModule mod_mime.c>
+		AddEncoding gzip svgz
+	</IfModule>
+</IfModule>
+
+### End: Compression ###
+
+
+
+### Begin: Browser caching of resource files ###
+
+# This affects Frontend and Backend and increases performance.
+<IfModule mod_expires.c>
+
+	ExpiresActive on
+	ExpiresDefault                                      "access plus 1 month"
+
+	ExpiresByType text/css                              "access plus 1 year"
+
+	ExpiresByType application/json                      "access plus 0 seconds"
+	ExpiresByType application/ld+json                   "access plus 0 seconds"
+	ExpiresByType application/schema+json               "access plus 0 seconds"
+	ExpiresByType application/vnd.geo+json              "access plus 0 seconds"
+	ExpiresByType application/xml                       "access plus 0 seconds"
+	ExpiresByType text/xml                              "access plus 0 seconds"
+
+	ExpiresByType image/vnd.microsoft.icon              "access plus 1 week"
+	ExpiresByType image/x-icon                          "access plus 1 week"
+
+	ExpiresByType text/x-component                      "access plus 1 month"
+
+	ExpiresByType text/html                             "access plus 0 seconds"
+
+	ExpiresByType application/javascript                "access plus 1 year"
+	ExpiresByType application/x-javascript              "access plus 1 year"
+	ExpiresByType text/javascript                       "access plus 1 year"
+
+	ExpiresByType application/manifest+json             "access plus 1 week"
+	ExpiresByType application/x-web-app-manifest+json   "access plus 0 seconds"
+	ExpiresByType text/cache-manifest                   "access plus 0 seconds"
+
+	ExpiresByType audio/ogg                             "access plus 1 month"
+	ExpiresByType image/bmp                             "access plus 1 month"
+	ExpiresByType image/gif                             "access plus 1 month"
+	ExpiresByType image/jpeg                            "access plus 1 month"
+	ExpiresByType image/png                             "access plus 1 month"
+	ExpiresByType image/svg+xml                         "access plus 1 month"
+	ExpiresByType image/webp                            "access plus 1 month"
+	ExpiresByType video/mp4                             "access plus 1 month"
+	ExpiresByType video/ogg                             "access plus 1 month"
+	ExpiresByType video/webm                            "access plus 1 month"
+
+	ExpiresByType application/atom+xml                  "access plus 1 hour"
+	ExpiresByType application/rdf+xml                   "access plus 1 hour"
+	ExpiresByType application/rss+xml                   "access plus 1 hour"
+
+	ExpiresByType application/vnd.ms-fontobject         "access plus 1 month"
+	ExpiresByType font/eot                              "access plus 1 month"
+	ExpiresByType font/opentype                         "access plus 1 month"
+	ExpiresByType application/x-font-ttf                "access plus 1 month"
+	ExpiresByType application/font-woff                 "access plus 1 month"
+	ExpiresByType application/x-font-woff               "access plus 1 month"
+	ExpiresByType font/woff                             "access plus 1 month"
+	ExpiresByType application/font-woff2                "access plus 1 month"
+
+	ExpiresByType text/x-cross-domain-policy            "access plus 1 week"
+
+</IfModule>
+
+### End: Browser caching of resource files ###
+
+
+### Begin: MIME types ###
+
+# Proper MIME types for all files
+<IfModule mod_mime.c>
+
+	# Data interchange
+	AddType application/atom+xml                        atom
+	AddType application/json                            json map topojson
+	AddType application/ld+json                         jsonld
+	AddType application/rss+xml                         rss
+	AddType application/vnd.geo+json                    geojson
+	AddType application/xml                             rdf xml
+
+	# JavaScript
+	AddType application/javascript                      js
+
+	# Manifest files
+	AddType application/manifest+json                   webmanifest
+	AddType application/x-web-app-manifest+json         webapp
+	AddType text/cache-manifest                         appcache
+
+	# Media files
+
+	AddType audio/mp4                                   f4a f4b m4a
+	AddType audio/ogg                                   oga ogg opus
+	AddType image/bmp                                   bmp
+	AddType image/svg+xml                               svg svgz
+	AddType image/webp                                  webp
+	AddType video/mp4                                   f4v f4p m4v mp4
+	AddType video/ogg                                   ogv
+	AddType video/webm                                  webm
+	AddType video/x-flv                                 flv
+	AddType image/x-icon                                cur ico
+
+	# Web fonts
+	AddType application/font-woff                       woff
+	AddType application/font-woff2                      woff2
+	AddType application/vnd.ms-fontobject               eot
+	AddType application/x-font-ttf                      ttc ttf
+	AddType font/opentype                               otf
+
+	# Other
+	AddType application/octet-stream                    safariextz
+	AddType application/x-bb-appworld                   bbaw
+	AddType application/x-chrome-extension              crx
+	AddType application/x-opera-extension               oex
+	AddType application/x-xpinstall                     xpi
+	AddType text/vcard                                  vcard vcf
+	AddType text/vnd.rim.location.xloc                  xloc
+	AddType text/vtt                                    vtt
+	AddType text/x-component                            htc
+
+</IfModule>
+
+# UTF-8 encoding
+AddDefaultCharset utf-8
+<IfModule mod_mime.c>
+	AddCharset utf-8 .atom .css .js .json .manifest .rdf .rss .vtt .webapp .webmanifest .xml
+</IfModule>
+
+### End: MIME types ###
+
+
+
+### Begin: Cross Origin ###
+
+# Send the CORS header for images when browsers request it.
+<IfModule mod_setenvif.c>
+	<IfModule mod_headers.c>
+		<FilesMatch "\.(bmp|cur|gif|ico|jpe?g|png|svgz?|webp)$">
+			SetEnvIf Origin ":" IS_CORS
+			Header set Access-Control-Allow-Origin "*" env=IS_CORS
+		</FilesMatch>
+	</IfModule>
+</IfModule>
+
+# Allow cross-origin access to web fonts.
+<IfModule mod_headers.c>
+	<FilesMatch "\.(eot|otf|tt[cf]|woff2?)$">
+		Header set Access-Control-Allow-Origin "*"
+	</FilesMatch>
+</IfModule>
+
+### End: Cross Origin ###
+
+
+
+### Begin: Rewriting and Access ###
+
+# You need rewriting, if you use a URL-Rewriting extension (RealURL, CoolUri).
+
+<IfModule mod_rewrite.c>
+
+	# Enable URL rewriting
+	RewriteEngine On
+
+	# Store the current location in an environment variable CWD to use
+	# mod_rewrite in .htaccess files without knowing the RewriteBase
+	RewriteCond $0#%{REQUEST_URI} ([^#]*)#(.*)\1$
+	RewriteRule ^.*$ - [E=CWD:%2]
+
+	# Rules to set ApplicationContext based on hostname
+	#RewriteCond %{HTTP_HOST} ^dev\.example\.com$
+	#RewriteRule .? - [E=TYPO3_CONTEXT:Development]
+	#RewriteCond %{HTTP_HOST} ^staging\.example\.com$
+	#RewriteRule .? - [E=TYPO3_CONTEXT:Production/Staging]
+	#RewriteCond %{HTTP_HOST} ^www\.example\.com$
+	#RewriteRule .? - [E=TYPO3_CONTEXT:Production]
+
+	# Rule for versioned static files, configured through:
+	# - $GLOBALS['TYPO3_CONF_VARS']['BE']['versionNumberInFilename']
+	# - $GLOBALS['TYPO3_CONF_VARS']['FE']['versionNumberInFilename']
+	# IMPORTANT: This rule has to be the very first RewriteCond in order to work!
+	RewriteCond %{REQUEST_FILENAME} !-f
+	RewriteCond %{REQUEST_FILENAME} !-d
+	RewriteRule ^(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ %{ENV:CWD}$1.$3 [L]
+
+	# Access block for folders
+	RewriteRule _(?:recycler|temp)_/ - [F]
+	RewriteRule fileadmin/templates/.*\.(?:txt|ts)$ - [F]
+	RewriteRule ^(?:vendor|typo3_src|typo3temp/var) - [F]
+	RewriteRule (?:typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(?:Configuration|Resources/Private|Tests?|Documentation|docs?)/ - [F]
+
+	# Block access to all hidden files and directories with the exception of
+	# the visible content from within the `/.well-known/` hidden directory (RFC 5785).
+	RewriteCond %{REQUEST_URI} "!(^|/)\.well-known/([^./]+./?)+$" [NC]
+	RewriteCond %{SCRIPT_FILENAME} -d [OR]
+	RewriteCond %{SCRIPT_FILENAME} -f
+	RewriteRule (?:^|/)\. - [F]
+
+	# Stop rewrite processing, if we are in the typo3/ directory or any other known directory
+	# NOTE: Add your additional local storages here
+	RewriteRule ^(?:typo3/|fileadmin/|typo3conf/|typo3temp/|uploads/|favicon\.ico) - [L]
+
+	# If the file/symlink/directory does not exist => Redirect to index.php.
+	# For httpd.conf, you need to prefix each '%{REQUEST_FILENAME}' with '%{DOCUMENT_ROOT}'.
+	RewriteCond %{REQUEST_FILENAME} !-f
+	RewriteCond %{REQUEST_FILENAME} !-d
+	RewriteCond %{REQUEST_FILENAME} !-l
+	RewriteRule ^.*$ %{ENV:CWD}index.php [QSA,L]
+
+</IfModule>
+
+# Access block for files
+# Apache < 2.3
+<IfModule !mod_authz_core.c>
+	<FilesMatch "(?i:^\.|^#.*#|^(?:ChangeLog|ToDo|Readme|License)(?:\.md|\.txt)?|^composer\.(?:json|lock)|^ext_conf_template\.txt|^ext_typoscript_constants\.txt|^ext_typoscript_setup\.txt|flexform[^.]*\.xml|locallang[^.]*\.(?:xml|xlf)|\.(?:bak|co?nf|cfg|ya?ml|ts|typoscript|tsconfig|dist|fla|in[ci]|log|sh|sql(?:\..*)?|sqlite(?:\..*)?|sw[op]|git.*|rc)|.*~)$">
+		Order allow,deny
+		Deny from all
+		Satisfy All
+	</FilesMatch>
+</IfModule>
+# Apache ≥ 2.3
+<IfModule mod_authz_core.c>
+	<If "%{REQUEST_URI} =~ m#(?i:/\.|/\x23.*\x23|/(?:ChangeLog|ToDo|Readme|License)(?:\.md|\.txt)?|/composer\.(?:json|lock)|/ext_conf_template\.txt|/ext_typoscript_constants\.txt|/ext_typoscript_setup\.txt|flexform[^.]*\.xml|locallang[^.]*\.(?:xml|xlf)|\.(?:bak|co?nf|cfg|ya?ml|ts|typoscript|tsconfig|dist|fla|in[ci]|log|sh|sql(?:\..*)?|sqlite(?:\..*)?|sw[op]|git.*|rc)|.*~)$#">
+		Require all denied
+	</If>
+</IfModule>
+
+# Block access to vcs directories
+<IfModule mod_alias.c>
+	RedirectMatch 404 /\.(?:git|svn|hg)/
+</IfModule>
+
+### End: Rewriting and Access ###
+
+
+
+### Begin: Miscellaneous ###
+
+# 404 error prevention for non-existing redirected folders
+Options -MultiViews
+
+# Make sure that directory listings are disabled.
+<IfModule mod_autoindex.c>
+	Options -Indexes
+</IfModule>
+
+<IfModule mod_headers.c>
+	# Force IE to render pages in the highest available mode
+	Header set X-UA-Compatible "IE=edge"
+	<FilesMatch "\.(appcache|crx|css|eot|gif|htc|ico|jpe?g|js|m4a|m4v|manifest|mp4|oex|oga|ogg|ogv|otf|pdf|png|safariextz|svgz?|ttf|vcf|webapp|webm|webp|woff2?|xml|xpi)$">
+		Header unset X-UA-Compatible
+	</FilesMatch>
+
+	# Reducing MIME type security risks
+	Header set X-Content-Type-Options "nosniff"
+</IfModule>
+
+# ETag removal
+<IfModule mod_headers.c>
+	Header unset ETag
+</IfModule>
+FileETag None
+
+### End: Miscellaneous ###
+
+
+# Add your own rules here.

+ 15 - 3
docker/mount/LocalConfiguration.php → docker/conf/LocalConfiguration.php

@@ -4,7 +4,7 @@ return [
         'compressionLevel' => '7',
         'debug' => false,
         'enabledBeUserIPLock' => false,
-        'installToolPassword' => '$P$CrSD5kigkOX0Vtt./9VA3hOnXsS86E0',
+        'installToolPassword' => '$argon2i$v=19$m=65536,t=16,p=1$Z2NIbFRRVlVYZHhoaEUuMg$88qbJUyQLt7mgO0AhyVZIEzLWlX72oJ9oHuvzQHhYBM',
         'interfaces' => 'backend',
         'lockIP' => '0',
         'loginSecurityLevel' => 'normal',
@@ -36,6 +36,7 @@ return [
             'extensionmanager' => 'a:2:{s:21:"automaticInstallation";s:1:"1";s:11:"offlineMode";s:1:"0";}',
             'flux' => 'a:7:{s:9:"debugMode";s:1:"0";s:8:"doktypes";s:5:"0,1,4";s:12:"handleErrors";s:1:"0";s:8:"autoload";s:1:"1";s:11:"plugAndPlay";s:1:"0";s:20:"plugAndPlayDirectory";s:6:"design";s:33:"pagesLanguageConfigurationOverlay";s:1:"0";}',
             'frontend_editing' => 'a:3:{s:11:"seoProvider";s:4:"none";s:29:"contentEditableWrapperTagName";s:3:"div";s:18:"enablePlaceholders";s:1:"0";}',
+            'lfeditor' => 'a:9:{s:13:"viewLanguages";s:0:"";s:15:"defaultLanguage";s:0:"";s:11:"searchRegex";s:60:"/^([a-z0-9_]*locallang[a-z0-9_-]*\\.(php|xml)|[^\\.]*\\.xlf)$/i";s:9:"extIgnore";s:23:"/^(CVS|.svn|.git|csh_)/";s:12:"extWhitelist";s:0:"";s:13:"changeXlfDate";s:1:"1";s:17:"editModeExtension";s:1:"1";s:27:"pathAdditionalConfiguration";s:37:"typo3conf/AdditionalConfiguration.php";s:16:"beMainModuleName";s:4:"user";}',
             'news' => 'a:18:{s:13:"prependAtCopy";s:1:"1";s:6:"tagPid";s:1:"1";s:12:"rteForTeaser";s:1:"0";s:22:"contentElementRelation";s:1:"1";s:21:"contentElementPreview";s:1:"1";s:13:"manualSorting";s:1:"0";s:19:"categoryRestriction";s:0:"";s:34:"categoryBeGroupTceFormsRestriction";s:1:"0";s:19:"dateTimeNotRequired";s:1:"0";s:11:"archiveDate";s:4:"date";s:12:"mediaPreview";s:5:"false";s:20:"advancedMediaPreview";s:4:"true";s:13:"slugBehaviour";s:6:"unique";s:24:"showAdministrationModule";s:1:"1";s:35:"hidePageTreeForAdministrationModule";s:1:"0";s:12:"showImporter";s:1:"0";s:18:"storageUidImporter";s:1:"1";s:22:"resourceFolderImporter";s:12:"/news_import";}',
             'scheduler' => 'a:2:{s:11:"maxLifetime";s:4:"1440";s:15:"showSampleTasks";s:1:"1";}',
             'vhs' => 'a:1:{s:20:"disableAssetHandling";s:1:"0";}',
@@ -75,6 +76,17 @@ return [
             'enablePlaceholders' => '0',
             'seoProvider' => 'none',
         ],
+        'lfeditor' => [
+            'beMainModuleName' => 'user',
+            'changeXlfDate' => '1',
+            'defaultLanguage' => '',
+            'editModeExtension' => '1',
+            'extIgnore' => '/^(CVS|.svn|.git|csh_)/',
+            'extWhitelist' => '',
+            'pathAdditionalConfiguration' => 'typo3conf/AdditionalConfiguration.php',
+            'searchRegex' => '/^([a-z0-9_]*locallang[a-z0-9_-]*\\.(php|xml)|[^\\.]*\\.xlf)$/i',
+            'viewLanguages' => '',
+        ],
         'news' => [
             'advancedMediaPreview' => 'true',
             'archiveDate' => 'date',
@@ -104,8 +116,8 @@ return [
         ],
     ],
     'FE' => [
-        'compressionLevel' => 7,
-        'debug' => false,
+        'compressionLevel' => 5,
+        'debug' => true,
         'disableNoCacheParameter' => '0',
         'pageNotFoundOnCHashError' => '0',
         'passwordHashing' => [

+ 3 - 2
docker/mount/composer.json → docker/conf/composer.json

@@ -57,10 +57,11 @@
 	},
 	"autoload": {
 		"psr-4": {
-			"Opentalent\\OtWidgets\\": "public/typo3conf/ext/ot_widgets/Classes",
+			"Opentalent\\OtCore\\": "public/typo3conf/ext/ot_core/Classes",
 			"Opentalent\\OtConnect\\": "public/typo3conf/ext/ot_connect/Classes",
 			"Opentalent\\OtTemplating\\": "public/typo3conf/ext/ot_templating/Classes",
-			"Opentalent\\OtAdmin\\": "public/typo3conf/ext/ot_admin/Classes"
+			"Opentalent\\OtAdmin\\": "public/typo3conf/ext/ot_admin/Classes",
+			"Opentalent\\OtStats\\": "public/typo3conf/ext/ot_stats/Classes"
 		}
 	}
 }

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

@@ -7,6 +7,7 @@ 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;
 
@@ -40,6 +41,11 @@ class CreateSiteCommand extends Command
                 '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'"
             );
     }
 
@@ -50,20 +56,21 @@ class CreateSiteCommand extends Command
      *
      * @param InputInterface $input
      * @param OutputInterface $output
+     * @throws \Exception
      */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        // Make sure the _cli_ user is loaded
-        // TYPO3\CMS\Core\Core\Bootstrap::initializeBackendAuthentication();
-
         $org_id = $input->getArgument('organization_id');
+        $isDev = $input->getOption('dev');
 
         $io = new SymfonyStyle($input, $output);
 
         $siteController = new SiteController();
-        $rootUid = $siteController->createSiteAction($org_id);
+        $rootUid = $siteController->createSiteAction(
+            $org_id,
+            $isDev ? $siteController::MODE_DEV : $siteController::MODE_PROD
+        );
 
         $io->success(sprintf("A new website has been created with root page uid=" . $rootUid));
     }
-
 }

+ 21 - 7
ot_admin/Classes/Controller/SiteController.php

@@ -2,10 +2,11 @@
 
 namespace Opentalent\OtAdmin\Controller;
 
-use Opentalent\OtTemplating\Domain\Model\Organization;
-use Opentalent\OtTemplating\Domain\Repository\OrganizationRepository;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use http\Exception\RuntimeException;
+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 Psr\Log\LoggerAwareInterface;
 use Symfony\Component\Yaml\Yaml;
@@ -56,7 +57,7 @@ class SiteController extends ActionController
     const DEFAULT_COLOR = 'light-blue';
 
     // BE rights
-    CONST PRODUCT_MAPPING = [
+    const PRODUCT_MAPPING = [
         "school-standard" => 1, // Association writer basic
         "artist-standard" => 1, // Association writer basic
         "school-premium" => 3, // Association writer full
@@ -64,6 +65,9 @@ class SiteController extends ActionController
         "manager" => 3, // Association writer full
     ];
 
+    const MODE_PROD = 1;
+    const MODE_DEV = 1;
+
     /**
      * Doctrine connection pool
      * @var object|LoggerAwareInterface|\TYPO3\CMS\Core\SingletonInterface
@@ -103,10 +107,13 @@ class SiteController extends ActionController
      * returns the root page uid of the newly created site
      *
      * @param int $organizationId
+     * @param int $mode Can be either MODE_PROD or MODE_DEV, MODE_PROD being the normal behaviour.
+     *                    If MODE_DEV is used, sites urls will be of the form 'http://host/subdomain'
+     *                    instead of 'http://subdomain/host'
      * @return int Uid of the root page of the newly created website
      * @throws \RuntimeException|\Exception
      */
-    public function createSiteAction(int $organizationId) {
+    public function createSiteAction(int $organizationId, int $mode=self::MODE_PROD) {
 
         $organization = $this->fetchOrganization($organizationId);
 
@@ -385,7 +392,14 @@ class SiteController extends ActionController
             );
 
             // Build and update the domain
-            $domain = $organization->getSubDomain() .  '.opentalent.fr';
+            if ($mode == self::MODE_PROD) {
+                $domain = $organization->getSubDomain() .  '.opentalent.fr';
+            } elseif ($mode == self::MODE_DEV) {
+                $domain = $organization->getSubDomain() . '/';
+            } else {
+                throw new RuntimeException('Unknown value for $mode: ' . $mode);
+            }
+
             $queryBuilder = $this->cnnPool->getQueryBuilderForTable('sys_domain');
             $queryBuilder->insert('sys_domain')
                 ->values([

+ 0 - 19
ot_admin/ext_localconf.php

@@ -1,7 +1,6 @@
 <?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)
@@ -9,21 +8,3 @@ $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][TYPO3\CMS\Backend\Middleware\Backe
     'className' => Opentalent\OtAdmin\Middleware\OtBackendUserAuthenticator::class
 ];
 
-
-$GLOBALS['TYPO3_CONF_VARS']['LOG']['Opentalent']['OtAdmin']['writerConfiguration'] = [
-    // configuration for ERROR level log entries
-    TYPO3\CMS\Core\Log\LogLevel::DEBUG => [
-        // add a FileWriter
-        TYPO3\CMS\Core\Log\Writer\FileWriter::class => [
-            // configuration for the writer
-            'logFile' => TYPO3\CMS\Core\Core\Environment::getVarPath() . '/log/typo3_otadmin.log'
-        ]
-    ],
-    TYPO3\CMS\Core\Log\LogLevel::WARNING => [
-        // add a DatabaseWriter
-        TYPO3\CMS\Core\Log\Writer\DatabaseWriter::class => [
-            'logTable' => 'tx_opentalent_log'
-        ]
-    ]
-];
-

+ 4 - 3
ot_templating/Classes/Middleware/RequestHandler.php → ot_connect/Classes/Middleware/RequestHandler.php

@@ -1,5 +1,5 @@
 <?php
-namespace Opentalent\OtTemplating\Middleware;
+namespace Opentalent\OtConnect\Middleware;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
@@ -8,7 +8,8 @@ use Psr\Http\Server\RequestHandlerInterface;
 use TYPO3\CMS\Core\Http\RedirectResponse;
 
 /**
- * Hooks into the frontend request and process the request
+ * Hooks into the frontend request and process the request in order to
+ * rewrite the uri and remove the 'logintype=logout' part after it was processed.
  *
  * @internal
  */
@@ -31,7 +32,7 @@ class RequestHandler implements MiddlewareInterface
             return new RedirectResponse(
                 $uri->withQuery($newQuery),
                 303,
-                ['X-Redirect-By' => 'OtTemplating logout redirection']
+                ['X-Redirect-By' => 'OtConnect logout redirection']
             );
         }
 

+ 2 - 2
ot_templating/Configuration/RequestMiddlewares.php → ot_connect/Configuration/RequestMiddlewares.php

@@ -5,8 +5,8 @@
  */
 return [
     'frontend' => [
-        'ottemplating-errorhandler' => [
-            'target' => Opentalent\OtTemplating\Middleware\RequestHandler::class,
+        'logout-rewriter' => [
+            'target' => Opentalent\OtConnect\Middleware\RequestHandler::class,
             'before' => [
                 'typo3/cms-adminpanel/data-persister'
             ],

+ 1 - 1
ot_connect/ext_emconf.php

@@ -18,7 +18,7 @@ $EM_CONF[$_EXTKEY] = [
     'uploadfolder' => 0,
     'createDirs' => '',
     'clearCacheOnLoad' => 0,
-    'version' => '0.1.0',
+    'version' => '1.0.0',
     'constraints' => [
         'depends' => [
             'typo3' => '8.7.0-10.4.99',

+ 5 - 31
ot_templating/Classes/Utility/OtCacheManager.php → ot_core/Classes/Cache/OtCacheManager.php

@@ -1,8 +1,8 @@
 <?php
 
-namespace Opentalent\OtTemplating\Utility;
+namespace Opentalent\OtCore\Cache;
 
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use Opentalent\OtCore\Page\OtPageRepository;
 use Psr\Http\Message\ResponseInterface;
 use RuntimeException;
 use TYPO3\CMS\Core\Service\OpcodeCacheService;
@@ -49,38 +49,12 @@ class OtCacheManager
 
     /**
      * Clear cache framework and opcode caches
-     * (@see TYPO3\CMS\Install\Controller\MaintenanceController )
+     *
+     * @see TYPO3\CMS\Install\Controller\MaintenanceController
      */
-    public static function clearAllCache(): ResponseInterface
+    public static function clearAllCache()
     {
         GeneralUtility::makeInstance(ClearCacheService::class)->clearAll();
         GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive();
     }
-
-    /**
-     * Clear typo3temp/assets
-     * (@see TYPO3\CMS\Install\Controller\MaintenanceController )
-     */
-    public static function clearAssetsTempfiles()
-    {
-        $typo3tempFileService = GeneralUtility::makeInstance(Typo3tempFileService::class);
-
-        try {
-            $typo3tempFileService->clearAssetsFolder("/typo3temp/assets/css");
-        } catch (RuntimeException $e) {
-            // 1501781454 code means directory does not exist, we can ignore this error
-            if ($e->getCode() != 1501781454) {
-                throw $e;
-            }
-        }
-
-        try {
-            $typo3tempFileService->clearAssetsFolder("/typo3temp/assets/js");
-        } catch (RuntimeException $e) {
-            // 1501781454 code means directory does not exist, we can ignore this error
-            if ($e->getCode() != 1501781454) {
-                throw $e;
-            }
-        }
-    }
 }

+ 44 - 0
ot_core/Classes/Controller/SelectedSiteController.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace Opentalent\OtCore\Controller;
+
+use Opentalent\OtCore\Exception\NoSiteSelected;
+use Opentalent\OtCore\Page\OtPageRepository;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+
+/**
+ * Base class for all controllers of backend modules that need
+ * a typo3 site's page to be selected to execute **ALL** of its actions methods
+ *
+ * If no page is selected or if this page does not have any root page as an ancestor,
+ * the action is forwarded to a page asking the user to select one.
+ *
+ * Class BeOnSiteController
+ */
+class SelectedSiteController extends ActionController
+{
+    /**
+     * The current site root page uid
+     *
+     * @var int
+     */
+    protected $currentRootUid;
+
+    protected function callActionMethod() {
+        try {
+            $otPageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
+            $this->currentRootUid = $otPageRepository->getCurrentRootUid();
+        } catch (NoSiteSelected $e) {
+            $this->currentRootUid = null;
+        }
+
+        if ($this->actionMethodName != 'displayNoSelectedPageWarningAction' && $this->currentRootUid == null) {
+            $this->forward('displayNoSelectedPageWarning', 'SelectedSite', 'OtCore');
+        }
+
+        parent::callActionMethod();
+    }
+
+    protected function displayNoSelectedPageWarningAction() {}
+}

+ 1 - 1
ot_templating/Classes/Domain/Model/Donor.php → ot_core/Classes/Domain/Model/Donor.php

@@ -1,5 +1,5 @@
 <?php
-namespace Opentalent\OtTemplating\Domain\Model;
+namespace Opentalent\OtCore\Domain\Model;
 
 use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
 

+ 1 - 1
ot_templating/Classes/Domain/Model/Event.php → ot_core/Classes/Domain/Model/Event.php

@@ -1,5 +1,5 @@
 <?php
-namespace Opentalent\OtTemplating\Domain\Model;
+namespace Opentalent\OtCore\Domain\Model;
 
 use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
 

+ 1 - 1
ot_templating/Classes/Domain/Model/Member.php → ot_core/Classes/Domain/Model/Member.php

@@ -1,5 +1,5 @@
 <?php
-namespace Opentalent\OtTemplating\Domain\Model;
+namespace Opentalent\OtCore\Domain\Model;
 
 use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
 

+ 1 - 1
ot_templating/Classes/Domain/Model/Organization.php → ot_core/Classes/Domain/Model/Organization.php

@@ -1,5 +1,5 @@
 <?php
-namespace Opentalent\OtTemplating\Domain\Model;
+namespace Opentalent\OtCore\Domain\Model;
 
 use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
 

+ 2 - 2
ot_templating/Classes/Domain/Repository/ApiPagedCollection.php → ot_core/Classes/Domain/Repository/ApiPagedCollection.php

@@ -1,12 +1,12 @@
 <?php
 
 
-namespace Opentalent\OtTemplating\Domain\Repository;
+namespace Opentalent\OtCore\Domain\Repository;
 
 /**
  * Represents an unserialized api response of 'PagedCollection' type
  *
- * @package Opentalent\OtTemplating\Domain\Repository
+ * @package Opentalent\OtCore\Domain\Repository
  */
 class ApiPagedCollection
 {

+ 2 - 2
ot_templating/Classes/Domain/Repository/BaseApiRepository.php → ot_core/Classes/Domain/Repository/BaseApiRepository.php

@@ -1,10 +1,10 @@
 <?php
 
-namespace Opentalent\OtTemplating\Domain\Repository;
+namespace Opentalent\OtCore\Domain\Repository;
 
 use GuzzleHttp\Client;
 use GuzzleHttp\Exception\GuzzleException;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
+use Opentalent\OtCore\Exception\ApiRequestException;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerAwareTrait;

+ 3 - 3
ot_templating/Classes/Domain/Repository/DonorRepository.php → ot_core/Classes/Domain/Repository/DonorRepository.php

@@ -1,9 +1,9 @@
 <?php
 
-namespace Opentalent\OtTemplating\Domain\Repository;
+namespace Opentalent\OtCore\Domain\Repository;
 
-use Opentalent\OtTemplating\Domain\Model\Donor;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
+use Opentalent\OtCore\Domain\Model\Donor;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 class DonorRepository extends BaseApiRepository
 {

+ 3 - 3
ot_templating/Classes/Domain/Repository/EventRepository.php → ot_core/Classes/Domain/Repository/EventRepository.php

@@ -1,11 +1,11 @@
 <?php
 
-namespace Opentalent\OtTemplating\Domain\Repository;
+namespace Opentalent\OtCore\Domain\Repository;
 
 use DateTimeZone;
 use Exception;
-use Opentalent\OtTemplating\Domain\Model\Event;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
+use Opentalent\OtCore\Domain\Model\Event;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 class EventRepository extends BaseApiRepository
 {

+ 3 - 3
ot_templating/Classes/Domain/Repository/MemberRepository.php → ot_core/Classes/Domain/Repository/MemberRepository.php

@@ -1,11 +1,11 @@
 <?php
 
-namespace Opentalent\OtTemplating\Domain\Repository;
+namespace Opentalent\OtCore\Domain\Repository;
 
 use DateTimeZone;
 use GuzzleHttp\Exception\GuzzleException;
-use Opentalent\OtTemplating\Domain\Model\Member;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
+use Opentalent\OtCore\Domain\Model\Member;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 class MemberRepository extends BaseApiRepository
 {

+ 3 - 3
ot_templating/Classes/Domain/Repository/OrganizationRepository.php → ot_core/Classes/Domain/Repository/OrganizationRepository.php

@@ -1,10 +1,10 @@
 <?php
 
-namespace Opentalent\OtTemplating\Domain\Repository;
+namespace Opentalent\OtCore\Domain\Repository;
 
 use GuzzleHttp\Exception\GuzzleException;
-use Opentalent\OtTemplating\Domain\Model\Organization;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
+use Opentalent\OtCore\Domain\Model\Organization;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 class OrganizationRepository extends BaseApiRepository
 {

+ 2 - 2
ot_templating/Classes/Exception/ApiRequestException.php → ot_core/Classes/Exception/ApiRequestException.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace Opentalent\OtTemplating\Exception;
+namespace Opentalent\OtCore\Exception;
 
 use Exception;
 
@@ -10,7 +10,7 @@ use Exception;
  * An ApiRequestException is raised when a request to the
  * Opentalent Api did not return a valid answer.
  *
- * @package Opentalent\OtTemplating\Exception
+ * @package Opentalent\OtCore\Exception
  */
 class ApiRequestException extends Exception
 {

+ 18 - 0
ot_core/Classes/Exception/NoSiteSelected.php

@@ -0,0 +1,18 @@
+<?php
+
+
+namespace Opentalent\OtCore\Exception;
+
+
+use Exception;
+
+/**
+ * Class NoSiteSelected
+ * Raise this exception in a BE module if no site is selected while it should
+ *
+ * @package Opentalent\OtCore\Exception
+ */
+class NoSiteSelected extends Exception
+{
+
+}

+ 53 - 0
ot_core/Classes/Logging/OtLogger.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace Opentalent\OtCore\Logging;
+
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerAwareTrait;
+use TYPO3\CMS\Core\Log\LogLevel;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+class OtLogger implements LoggerAwareInterface
+{
+    use LoggerAwareTrait;
+
+    public static function log(int $level, string $msg, array $context = []) {
+        $loggerService = GeneralUtility::makeInstance(self::class);
+        $loggerService->getLogger()->log($level, $msg, $context);
+    }
+
+    public function getLogger() {
+        return $this->logger;
+    }
+
+    public static function alert(string $msg, array $context = []) {
+        self::log(LogLevel::ALERT, $msg, $context);
+    }
+
+    public static function critical(string $msg, array $context = []) {
+        self::log(LogLevel::CRITICAL, $msg, $context);
+    }
+
+    public static function error(string $msg, array $context = []) {
+        self::log(LogLevel::ERROR, $msg, $context);
+    }
+
+    public static function warning(string $msg, array $context = []) {
+        self::log(LogLevel::WARNING, $msg, $context);
+    }
+
+    public static function notice(string $msg, array $context = []) {
+        self::log(LogLevel::NOTICE, $msg, $context);
+    }
+
+    public static function info(string $msg, array $context = []) {
+        self::log(LogLevel::INFO, $msg, $context);
+    }
+
+    public static function debug(string $msg, array $context = []) {
+        self::log(LogLevel::DEBUG, $msg, $context);
+    }
+
+
+
+}

+ 55 - 58
ot_templating/Classes/Page/OtPageRepository.php → ot_core/Classes/Page/OtPageRepository.php

@@ -1,10 +1,12 @@
 <?php
 
-namespace Opentalent\OtTemplating\Page;
+namespace Opentalent\OtCore\Page;
 
 use FluidTYPO3\Vhs\Service\PageService;
+use Opentalent\OtCore\Exception\NoSiteSelected;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Exception\SiteNotFoundException;
+use TYPO3\CMS\Core\Site\Entity\Site;
 use TYPO3\CMS\Core\Site\SiteFinder;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
@@ -15,32 +17,12 @@ use TYPO3\CMS\Frontend\Page\PageRepository;
  *
  * Provides some useful methods to query typo3 pages
  *
- * @package Opentalent\OtTemplating\Page
+ * @package Opentalent\OtCore\Page
  */
 class OtPageRepository extends PageRepository
 {
-    CONST templates = [
-        'Classic' => [
-            'name' => 'Classique',
-            'description' => "Le thème classique, simple et complet. C'est le thème par défaut.",
-            'picture' => 'EXT:ot_templating/Resources/Public/media/theme_classic.png'
-        ],
-        'Modern' => [
-            'name' => 'Moderne',
-            'description' => '[Nouveauté 2020] Un thème moderne et intuitif.',
-            'picture' => 'EXT:ot_templating/Resources/Public/media/theme_modern.png'
-        ]
-    ];
-
-    CONST defaultTemplate = 'Classic';
-
-    CONST defaultPreferences = [
-        'themeColor' => 'lightblue',
-        'displayCarousel' => '1'
-    ];
-
     /**
-     * Returns the root page of the given page,
+     * Returns the root page of the given page website,
      * or the page itself if the given page is
      * already the rootpage of the site
      *
@@ -55,13 +37,13 @@ class OtPageRepository extends PageRepository
         for (end($rootLine); key($rootLine)!==null; prev($rootLine)){
             $page = current($rootLine);
             if ($page['is_siteroot'] == 1) {
+                $page = $this->getPage($page['uid']);
                 return $page;
             }
         }
         return [];
     }
 
-
     /**
      * Recursively returns all the subpages of the given page
      *
@@ -69,7 +51,7 @@ class OtPageRepository extends PageRepository
      * @param bool $withRestrictions Set to true to add the standard restrictions (deleted, forbidden...etc.)
      * @return array
      */
-    public function getAllSubpagesForPage($pageUid, bool $withRestrictions=false) {
+    public function getAllSubpagesForPage(int $pageUid, bool $withRestrictions=false) {
         $subpages = [];
 
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
@@ -95,45 +77,23 @@ class OtPageRepository extends PageRepository
     }
 
     /**
-     * Returns the current site template's name
-     * @return string
-     */
-    public function getCurrentTemplate() {
-        $rootPageUid = $this->getCurrentSiteRootPageId();
-        if (!($rootPageUid >= 0)) {
-            return self::defaultTemplate;
-        }
-
-        $rootPage = $this->getPage($rootPageUid);
-        $templateName = $rootPage['tx_opentalent_template'];
-        if ($templateName==='') {
-            return self::defaultTemplate;
-        }
-        return $templateName;
-    }
-
-    /**
-     * Returns the current site template's name
-     * @return array
+     * Return the Site object for the given page
+     *
+     * @param int $pageUid
+     * @return Site
      */
-    public function getTemplatePreferences() {
-        $rootPageUid = $this->getCurrentSiteRootPageId();
-        if (!($rootPageUid >= 0)) {
-            return [];
-        }
-
-        $rootPage = $this->getPage($rootPageUid);
-        $templatePreferences = $rootPage['tx_opentalent_template_preferences'];
+    public function getSiteFor(int $pageUid) {
+        $rootPage = $this->getRootPageFor($pageUid);
+        $rootUid = $rootPage['uid'];
 
-        if ($templatePreferences==='') {
-            return self::defaultPreferences;
-        }
-        return json_decode($templatePreferences, true);
+        $siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
+        return $siteFinder->getSiteByRootPageId($rootUid);
     }
 
     /**
-     * Returns the typo3 site matching the current request
+     * Returns the typo3 site matching the current request (FE only)
      *
+     * @return Site
      */
     public function getCurrentSite() {
         $request = $GLOBALS['TYPO3_REQUEST'];
@@ -143,7 +103,9 @@ class OtPageRepository extends PageRepository
     }
 
     /**
+     * Returns the current site's rootpage uid (FE only)
      *
+     * @return int
      */
     public function getCurrentSiteRootPageId() {
         $site = $this->getCurrentSite();
@@ -151,7 +113,9 @@ class OtPageRepository extends PageRepository
     }
 
     /**
+     * Returns the current site's rootpage URI (FE only)
      *
+     * @return string
      */
     public function getCurrentSiteRootPageUri() {
         $site = $this->getCurrentSite();
@@ -159,11 +123,44 @@ class OtPageRepository extends PageRepository
     }
 
     /**
+     * [Frontend Only]
+     * Returns the current site's rootpage array
      *
+     * @return array
      */
     public function getCurrentSiteRootPage() {
         $uid = $this->getCurrentSiteRootPageUri();
         return $this->getPage($uid);
     }
 
+    /**
+     * [Backend Only]
+     * Returns the page currently selected in the backend if any
+     *
+     * @return int|null
+     */
+    public function getCurrentPageId() {
+        return (int)GeneralUtility::_GP('id');
+    }
+
+    /**
+     * [Backend Only]
+     * Return the root uid of the currently selected website if any,
+     * or throw a NoSiteSelected exception
+     *
+     * @return int
+     * @throws NoSiteSelected
+     */
+    public function getCurrentRootUid() {
+        $pageUid = $this->getCurrentPageId();
+
+        $otPageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
+        $rootPage = $otPageRepository->getRootPageFor($pageUid);
+        $rootUid = $rootPage['uid'] ?? 0;
+        if (!$rootUid > 0) {
+            throw new NoSiteSelected();
+        }
+        return $rootUid;
+    }
+
 }

+ 40 - 0
ot_core/Classes/ViewHelpers/OtAbstractViewHelper.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace Opentalent\OtCore\ViewHelpers;
+
+use FluidTYPO3\Vhs\Utility\ErrorUtility;
+use Opentalent\OtCore\Page\OtPageRepository;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerAwareTrait;
+use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+
+/**
+ * Class OtAbstractViewHelper
+ * Base class for Opentalent viewhelpers
+ *
+ * @package Opentalent\OtCore\ViewHelpers
+ */
+class OtAbstractViewHelper  extends AbstractViewHelper implements LoggerAwareInterface {
+    use LoggerAwareTrait;
+
+    /**
+     * @var OtPageRepository
+     *
+     */
+    protected $pageRepository;
+
+    /**
+     * Throw a VHS viewhelper error
+     */
+    protected function throwException(string $msg) {
+        ErrorUtility::throwViewHelperException($msg);
+    }
+
+    /**
+     * @param OtPageRepository $pageRepository
+     */
+    public function injectOtPageRepository(OtPageRepository $pageRepository)
+    {
+        $this->pageRepository = $pageRepository;
+    }
+}

+ 0 - 0
ot_templating/Configuration/TCA/Overrides/Readme.md → ot_core/Configuration/TCA/Overrides/Readme.md


+ 0 - 0
ot_templating/Configuration/TCA/Overrides/pages.php → ot_core/Configuration/TCA/Overrides/pages.php


+ 0 - 0
ot_templating/Configuration/TCA/Readme.md → ot_core/Configuration/TCA/Readme.md


+ 18 - 0
ot_core/Readme.md

@@ -0,0 +1,18 @@
+
+# OtCore
+
+Core extension pour typo3.
+
+|||
+|---|---|
+| Extension key | ot_core |
+| Vendor | Opentalent |
+| Nom | OtCore |
+
+Cette extension fournit de nombreuses classes et ressources communes aux autres extensions Opentalent.
+
+**IMPORTANT**:
+
+* Cette extension ne doit dépendre d'aucune autre pour fonctionner, c'est à dire que son fonctionnement ne doit 
+pas être modifié si aucune autre extension n'est installée
+* Cette extension est aussi la seule dont les autres extensions doivent pouvoir dépendre

+ 12 - 0
ot_core/Resources/Private/Language/locallang.xlf

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<xliff version="1.0">
+	<file source-language="fr" datatype="plaintext" original="messages" date="2020-04-03T15:44:11Z" product-name="ot_templating">
+		<header/>
+		<body>
+			<!--  -->
+			<trans-unit id="noPageSelected">
+				<source>Veuillez sélectionner une des pages du site à personnaliser pour accéder à cette rubrique.</source>
+			</trans-unit>
+		</body>
+	</file>
+</xliff>

+ 7 - 0
ot_core/Resources/Private/Layouts/Backend/Default.html

@@ -0,0 +1,7 @@
+{namespace v=FluidTYPO3\Vhs\ViewHelpers}
+
+<f:be.container includeCssFiles="{ot_core: '{f:uri.resource(path:\'assets/Backend/style/ot_be_module.css\')}'}">
+    <div class="ot-be-module">
+        <f:render section="content" />
+    </div>
+</f:be.container>

+ 9 - 0
ot_core/Resources/Private/Templates/SelectedSite/DisplayNoSelectedPageWarning.html

@@ -0,0 +1,9 @@
+
+<f:layout name="Backend/Default" />
+
+<f:section name="content">
+    <div class="no-page-warning">
+        <f:comment><!-- No page selected --></f:comment>
+        <f:translate key="noPageSelected" />
+    </div>
+</f:section>

BIN=BIN
ot_core/Resources/Public/Icons/Extension.png


BIN=BIN
ot_core/Resources/Public/Icons/Extension_white.png


+ 44 - 0
ot_core/Resources/Public/assets/Backend/style/ot_be_module.css

@@ -0,0 +1,44 @@
+
+.ot-be-module {
+}
+
+.ot-be-module h3 {
+    font-weight: 500;
+    font-size: 1.35em;
+    line-height: 1.2em;
+}
+
+.ot-be-module .ot-btn {
+    padding: 6px;
+
+    border: solid 1px #bbb;
+    border-radius: 2px;
+    background-color: #eee;
+    font-weight: 600;
+}
+
+.ot-be-module .ot-btn:hover {
+    text-decoration: none;
+    cursor: pointer;
+
+    color: #333;
+    background-color: #d5d4d4;
+    border-color: #9c9c9c;
+}
+
+.ot-be-module .success-msg {
+    color: #009933;
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    font-size: 14px;
+}
+
+.ot-be-module .no-page-warning {
+    margin: 36px;
+    padding: 12px;
+    background-color: #e6e6e6;
+    border: solid 1px #666666;
+}
+

+ 33 - 0
ot_core/composer.json

@@ -0,0 +1,33 @@
+{
+    "name": "opentalent/ot_core",
+    "type": "typo3-cms-extension",
+    "description": "Core extension par Opentalent",
+    "authors": [
+        {
+            "name": "Olivier Massot",
+            "role": "Developer"
+        }
+    ],
+    "require": {
+        "typo3/cms-core": "^9.5 || ^10.4",
+        "fluidtypo3/vhs": "^6",
+        "fluidtypo3/flux": "^9",
+        "fluidtypo3/fluidpages": "^5",
+        "co-stack/logs": "",
+        "guzzlehttp/guzzle": "^6"
+    },
+    "replace": {
+        "ot_core": "self.version",
+        "typo3-ter/ot_core": "self.version"
+    },
+    "autoload": {
+        "psr-4": {
+            "Opentalent\\OtCore\\": "Classes"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Opentalent\\OtCore\\Tests\\": "Tests"
+        }
+    }
+}

+ 31 - 0
ot_core/ext_emconf.php

@@ -0,0 +1,31 @@
+<?php
+
+/***************************************************************
+ * Extension Manager/Repository config file for ext: "ot_core"
+ *
+ * Manual updates:
+ * Only the data in the array - anything else is removed by next write.
+ * "version" and "dependencies" must not be touched!
+ ***************************************************************/
+
+$EM_CONF[$_EXTKEY] = [
+    'title' => 'Core',
+    'description' => "Core extension par Opentalent",
+    'category' => 'services',
+    'author' => 'Olivier Massot',
+    'author_email' => 'olivier.massot@2iopenservice.fr',
+    'state' => 'alpha',
+    'uploadfolder' => 0,
+    'createDirs' => '',
+    'clearCacheOnLoad' => 0,
+    'version' => '0.1.0',
+    'constraints' => [
+        'depends' => [
+            'typo3' => '8.7.0-10.4.99',
+            'flux'  => '9.3.0-9.4.99',
+            'vhs'  => '6.0.0-6.0.99',
+        ],
+        'conflicts' => [],
+        'suggests' => [],
+    ],
+];

+ 25 - 0
ot_core/ext_localconf.php

@@ -0,0 +1,25 @@
+<?php
+
+if (!defined('TYPO3_MODE')) {
+    die('Access denied.');
+}
+
+$GLOBALS['TYPO3_CONF_VARS']['LOG']['Opentalent']['OtCore']['writerConfiguration'] = [
+    // configuration for ERROR level log entries
+    TYPO3\CMS\Core\Log\LogLevel::DEBUG => [
+        // add a FileWriter
+        TYPO3\CMS\Core\Log\Writer\FileWriter::class => [
+            // configuration for the writer
+            'logFile' => TYPO3\CMS\Core\Core\Environment::getVarPath() . '/log/ot_typo3.log'
+        ]
+    ],
+    TYPO3\CMS\Core\Log\LogLevel::WARNING => [
+        // add a DatabaseWriter
+        TYPO3\CMS\Core\Log\Writer\DatabaseWriter::class => [
+            'logTable' => 'tx_opentalent_log'
+        ]
+    ]
+];
+
+
+$GLOBALS['TYPO3_CONF_VARS']['EXT']['news']['Controller/NewsController.php']['createDemandObjectFromSettings'] = ['Opentalent\OtTemplating\News\NewsFilter->createDemandObjectFromSettings'];

+ 104 - 0
ot_stats/Classes/Controller/OtStatsController.php

@@ -0,0 +1,104 @@
+<?php
+
+namespace Opentalent\OtStats\Controller;
+
+use Opentalent\OtCore\Controller\SelectedSiteController;
+use Opentalent\OtCore\Logging\OtLogger;
+use Opentalent\OtStats\Domain\Repository\MatomoWebsiteRepository;
+use Opentalent\OtStats\Settings\StatsSettingsRepository;
+use TYPO3\CMS\Core\Messaging\AbstractMessage;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
+
+/**
+ * Controller for the OtStats backend submodule
+ *
+ * @author olivier.massot
+ */
+class OtStatsController extends SelectedSiteController {
+
+    /**
+     * Access token of the 'typo3' user in matomo
+     */
+    const MATOMO_TOKEN = 'd781ebf1e210bc8ab1e9f4a3e21e9b01';
+
+    /**
+     * Index action (default action)
+     * Displays the customizer page on the backend
+     */
+    public function indexAction() {
+        $this->view->assign('rootPage', $this->currentRootUid);
+        $statsSettingsRepository = GeneralUtility::makeInstance(StatsSettingsRepository::class);
+        $matomoId = $statsSettingsRepository->getMatomoSiteId($this->currentRootUid);
+
+        if ($matomoId == null) {
+            $this->forward('askForActivationConfirmation');
+        }
+        $this->view->assign('matomoSiteId', (int)$matomoId);
+        $this->view->assign('matomoToken', self::MATOMO_TOKEN);
+        $args = $this->request->getArguments();
+
+        // Default interval
+        $period = isset($args['period']) ? $args['period'] : 'month';
+        $this->view->assign('period', $period);
+
+    }
+
+    /**
+     * Display a confirmation page before enabling the stats module
+     */
+    public function askForActivationConfirmationAction() {}
+
+    /**
+     * Display a confirmation page before disabling the stats module
+     */
+    public function askForDeactivationConfirmationAction() {
+        $this->view->assign('rootUid', $this->currentRootUid);
+    }
+
+    /**
+     * Creates a matomo site record if none exists and
+     * save its id
+     */
+    public function enableStatsAction() {
+        $matomoRepository = GeneralUtility::makeInstance(MatomoWebsiteRepository::class);
+
+        try {
+            $matomoRepository->createFor($this->currentRootUid);
+        } catch (\RuntimeException $e) {
+            OtLogger::error("OtStats - " . $e);
+            $this->addFlashMessage(
+                "Une erreur s'est produite lors de l'opération, veuillez contacter un administrateur.",
+                '',
+                AbstractMessage::ERROR
+            );
+            $this->forward('askForActivationConfirmation');
+        }
+        $this->forward('index');
+    }
+
+    /**
+     * Disable the stats monitoring
+     *
+     * @param int $rootUid    Pass the rootUid of the site as an argument to confirm of the decision
+     *                          of disabling the website. If no rootUid is passed, the user will be redirected to a
+     *                          confirmation page.
+     * @throws StopActionException
+     */
+    public function disableStatsAction(int $rootUid) {
+
+        $matomoRepository = GeneralUtility::makeInstance(MatomoWebsiteRepository::class);
+
+        try {
+            $matomoRepository->disableFor($rootUid);
+        } catch (\RuntimeException $e) {
+            OtLogger::error("OtStats - " . $e);
+            $this->addFlashMessage(
+                "Une erreur s'est produite lors de l'opération, veuillez contacter un administrateur.",
+                '',
+                AbstractMessage::ERROR
+            );
+        }
+        $this->forward('askForActivationConfirmation');
+    }
+}

+ 144 - 0
ot_stats/Classes/Domain/Model/MatomoWebsite.php

@@ -0,0 +1,144 @@
+<?php
+
+namespace Opentalent\OtStats\Domain\Model;
+
+class MatomoWebsite
+{
+    /**
+     * Website's id in the matomo DB
+     * @var int
+     */
+    public $id;
+
+    /**
+     * Name of the website in the matomo db
+     *
+     * @var string
+     */
+    public $name;
+
+    /**
+     * Main url of the website to monitor
+     *
+     * @var string
+     */
+    public $mainUrl;
+
+    /**
+     * Ips to ignore
+     *
+     * @var
+     */
+    public $excludedIps;
+
+    /**
+     * Matomo type (always 'website')
+     *
+     * @var string
+     */
+    public $type;
+
+    /**
+     * Login of the record creator (always 'matomo')
+     *
+     * @var string
+     */
+    public $creatorLogin;
+
+    /**
+     * @return int
+     */
+    public function getId(): int
+    {
+        return $this->id;
+    }
+
+    /**
+     * @param int $id
+     */
+    public function setId(int $id): void
+    {
+        $this->id = $id;
+    }
+
+    /**
+     * @return string
+     */
+    public function getName(): string
+    {
+        return $this->name;
+    }
+
+    /**
+     * @param string $name
+     */
+    public function setName(string $name): void
+    {
+        $this->name = $name;
+    }
+
+    /**
+     * @return string
+     */
+    public function getMainUrl(): string
+    {
+        return $this->mainUrl;
+    }
+
+    /**
+     * @param string $mainUrl
+     */
+    public function setMainUrl(string $mainUrl): void
+    {
+        $this->mainUrl = $mainUrl;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getExcludedIps()
+    {
+        return $this->excludedIps;
+    }
+
+    /**
+     * @param mixed $excludedIps
+     */
+    public function setExcludedIps($excludedIps): void
+    {
+        $this->excludedIps = $excludedIps;
+    }
+
+    /**
+     * @return string
+     */
+    public function getType(): string
+    {
+        return $this->type;
+    }
+
+    /**
+     * @param string $type
+     */
+    public function setType(string $type): void
+    {
+        $this->type = $type;
+    }
+
+    /**
+     * @return string
+     */
+    public function getCreatorLogin(): string
+    {
+        return $this->creatorLogin;
+    }
+
+    /**
+     * @param string $creatorLogin
+     */
+    public function setCreatorLogin(string $creatorLogin): void
+    {
+        $this->creatorLogin = $creatorLogin;
+    }
+
+}

+ 269 - 0
ot_stats/Classes/Domain/Repository/MatomoWebsiteRepository.php

@@ -0,0 +1,269 @@
+<?php
+
+namespace Opentalent\OtStats\Domain\Repository;
+
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtStats\Domain\Model\MatomoWebsite;
+use PDO;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+class MatomoWebsiteRepository
+{
+    /**
+     * Database connection data
+     */
+    const MATOMO_DB_HOST = 'tools';
+    const MATOMO_DB_NAME = 'matomo';
+    const MATOMO_DB_USER = 'matomo';
+    const MATOMO_DB_PWD = ']:*j8GYU/n9mp+';
+
+    /**
+     * Regex
+     */
+    const RELATIVE_PATH_VALIDATION = '/^\/[a-zA-Z0-9_\-]+\/?$/';
+    const DOMAIN_VALIDATION = '/^(https?:\/\/)?([a-zA-Z0-9]+\.)+[a-zA-Z]{2,}(:\d+)?(\/[a-zA-Z0-9_\-]+)*\/?$/';
+
+    /**
+     * Connection to the matomo DB
+     *
+     * @var PDO
+     */
+    private $matomoCnn;
+
+
+    public function __construct()
+    {
+        // Connection to the Matomo DB
+        $this->matomoCnn = new PDO(
+            "mysql:host=" . self::MATOMO_DB_HOST . ";dbname=" . self::MATOMO_DB_NAME,
+            self::MATOMO_DB_USER,
+            self::MATOMO_DB_PWD,
+            array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8')
+        );
+        $this->matomoCnn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+    }
+
+    /**
+     * Create a new MatomoWebsite from an array
+     *
+     * @param array $data
+     * @return MatomoWebsite
+     */
+    private function fromArray(array $data) {
+        $matomoSite = new MatomoWebsite();
+        $matomoSite->setId($data['idsite']);
+        $matomoSite->setName($data['name']);
+        $matomoSite->setMainUrl($data['main_url']);
+        $matomoSite->setExcludedIps($data['exluded_ips']);
+        $matomoSite->setType($data['type']);
+        $matomoSite->setCreatorLogin($data['creator_login']);
+        return $matomoSite;
+    }
+
+    /**
+     * Retrieve the MatomoWebsite object by id, otherwise, returns Null
+     *
+     * @param int $id
+     * @return MatomoWebsite|null
+     */
+    public function findById(int $id) {
+        $stmt = $this->matomoCnn->prepare(
+            "SELECT s.idsite, s.name, s.main_url, s.excluded_ips, s.type, s.creator_login
+                      FROM matomo.matomo_site s
+                      WHERE s.idsite=" . $id . ";"
+        );
+        $stmt->execute();
+        $stmt->setFetchMode(PDO::FETCH_ASSOC);
+        $data = $stmt->fetch();
+        if (!$data) {
+            return null;
+        }
+        return $this->fromArray($data);
+    }
+
+    /**
+     * Retrieve the MatomoWebsite object by uri, otherwise, returns Null
+     *
+     * @param string $uri
+     * @return MatomoWebsite|null
+     */
+    public function findByUri(string $uri) {
+        $stmt = $this->matomoCnn->prepare(
+            "SELECT s.idsite, s.name, s.main_url, s.excluded_ips, s.type, s.creator_login
+                      FROM matomo.matomo_site s
+                      WHERE s.main_url='" . $uri . "';"
+        );
+        $stmt->execute();
+        $stmt->setFetchMode(PDO::FETCH_ASSOC);
+        $data = $stmt->fetch();
+        if (!$data) {
+            return null;
+        }
+        return $this->fromArray($data);
+    }
+
+    /**
+     * Retrieve the MatomoWebsite object for the typo3 website with
+     * the given rootUid, otherwise, returns Null
+     *
+     * @param int $rootUid
+     * @return MatomoWebsite|null
+     */
+    public function findByRootUid(int $rootUid) {
+        $otPageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
+
+        // Just to make sure this page is actually the root page
+        $rootPage = $otPageRepository->getRootPageFor($rootUid);
+
+        if ($rootPage['tx_opentalent_matomo_id'] == null) {
+            return null;
+        }
+        return $this->findById($rootPage['tx_opentalent_matomo_id']);
+    }
+
+    /**
+     * Create a new matomo's website for the Typo3 site (or retrieve the existing if any),
+     * store its id in the Typo3 DB and return it
+     *
+     * @param int $rootUid
+     * @return int|string The matomo site's id
+     * @throws \Exception
+     */
+    public function createFor(int $rootUid) {
+        $otPageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
+
+        // Just to make sure this page is actually the root page
+        $rootPage = $otPageRepository->getRootPageFor($rootUid);
+        $rootUid = $rootPage['uid'];
+
+        // Retrieve current site informations
+        $isDev = ($_SERVER['TYPO3_CONTEXT'] == 'Development');
+
+        $site = $otPageRepository->getSiteFor($rootUid);
+        $title = $site->getIdentifier();
+        if ($isDev) {
+            $title = $title . "_DEV";
+        }
+
+        $uri = $site->getBase();
+        if ($isDev && preg_match(self::RELATIVE_PATH_VALIDATION, $uri)) {
+            $host = $_SERVER['HTTP_HOST'];
+            $uri = $host . $uri;
+        }
+
+        if (!preg_match('/https?:\/\/.*/', $uri)) {
+            $uri = 'https://' . $uri;
+        }
+
+        if (!preg_match(self::DOMAIN_VALIDATION, $uri)) {
+            throw new \RuntimeException("The domain's name is not valid: " . $uri);
+        }
+
+        // Make sure the current typo3 website has no existing configured matomo website
+        if ($rootPage['tx_opentalent_matomo_id'] != null) {
+            // Check if the registered matomo site still exist. If it does, throw an error.
+            if ($this->findById($rootPage['tx_opentalent_matomo_id']) != null) {
+                throw new \RuntimeException('This website has already been registered (matomo id: ' . $rootPage['tx_opentalent_matomo_id'] . ')');
+            }
+        }
+
+        // Check if there is already an existing matomo record for this url
+        $existingMatomoSite = $this->findByUri($uri);
+        if ($existingMatomoSite) {
+            // Verify that the names match (just to be sure)
+            if ($existingMatomoSite->getName() != $title) {
+                throw new \RuntimeException('A website with this URL has already been registered: ' . $uri);
+            }
+            $matomoSiteId = $existingMatomoSite->getId();
+        }
+
+        // Set up a connection to the typo3 DB
+        $cnnPool = GeneralUtility::makeInstance(ConnectionPool::class);
+
+        // Create a new website record in the matomo DB, and store its id
+        $this->matomoCnn->beginTransaction();
+        $cnnPool->getConnectionByName('Default')->beginTransaction();
+        try {
+            $ignoreIps = $isDev ? '' : '10.8.0.*';
+
+            if ($existingMatomoSite == null) {
+                // Create the new website
+                $stmt = $this->matomoCnn->prepare(
+                    "INSERT INTO matomo.matomo_site
+                          (`name`, main_url, ts_created, ecommerce, sitesearch, sitesearch_keyword_parameters, 
+                           sitesearch_category_parameters, timezone, 
+                           currency, excluded_ips, excluded_parameters, excluded_user_agents, `group`, `type`, creator_login)
+                          VALUES ('" . $title . "', '" . $uri . "', NOW(), 0, 1, '', '', 'Europe/Paris', 
+                                  'EUR', '" . $ignoreIps . "', '', '', '', 'website', 'typo3');");
+                $stmt->execute();
+
+                // Get the new site's id
+                $matomoSiteId = $this->matomoCnn->lastInsertId();
+
+                # Give the right to the typo3 user on this new site
+                $stmt = $this->matomoCnn->prepare(
+                    "INSERT INTO matomo.matomo_access
+                          (login, idSite, access)
+                          VALUES ('typo3', $matomoSiteId, 'view');");
+                $stmt->execute();
+            }
+
+            // Update typo3 DB
+            $queryBuilder = $cnnPool->getQueryBuilderForTable('pages');
+            $queryBuilder
+                ->update('pages')
+                ->where($queryBuilder->expr()->eq('uid', $rootUid))
+                ->set('tx_opentalent_matomo_id', $matomoSiteId)
+                ->execute();
+
+            // finalize
+            $this->matomoCnn->commit();
+            $cnnPool->getConnectionByName('Default')->commit();
+
+            return $matomoSiteId;
+
+        } catch (\Exception $e) {
+            // An error happened, rollback and throw
+            $this->matomoCnn->rollBack();
+            $cnnPool->getConnectionByName('Default')->rollback();
+            throw $e;
+        }
+    }
+
+    /**
+     * Disable the matomo monitoring for the website
+     * > Data wont be deleted from the matomo DB, but no more data will
+     *   be collected unless it is reactivated with the 'createFor' method
+     *
+     * @param int $rootUid
+     * @throws \Exception
+     */
+    public function disableFor(int $rootUid) {
+        $matomoSite = $this->findByRootUid($rootUid);
+        if ($matomoSite == null) {
+            throw new \RuntimeException('Activity monitoring is already disabled for this website');
+        }
+
+        // Set up a connection to the typo3 DB
+        $cnnPool = GeneralUtility::makeInstance(ConnectionPool::class);
+        $cnnPool->getConnectionByName('Default')->beginTransaction();
+        try {
+            // Update typo3 DB
+            $queryBuilder = $cnnPool->getQueryBuilderForTable('pages');
+            $queryBuilder
+                ->update('pages')
+                ->where($queryBuilder->expr()->eq('uid', $rootUid))
+                ->set('tx_opentalent_matomo_id', null)
+                ->execute();
+
+            // finalize
+            $cnnPool->getConnectionByName('Default')->commit();
+
+        } catch (\Exception $e) {
+            // An error happened, rollback and throw
+            $cnnPool->getConnectionByName('Default')->rollback();
+            throw $e;
+        }
+    }
+}

+ 75 - 0
ot_stats/Classes/Middleware/RequestHandler.php

@@ -0,0 +1,75 @@
+<?php
+namespace Opentalent\OtStats\Middleware;
+
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtStats\Settings\StatsSettingsRepository;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Core\Http\Stream;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\View\StandaloneView;
+
+/**
+ * Hooks into the frontend request to add the matomo script into
+ * the request's header
+ *
+ * @internal
+ */
+class RequestHandler implements MiddlewareInterface
+{
+    const TEMPLATES_ROOT_PATHS = 'EXT:ot_stats/Resources/Private/Templates';
+    const PARTIALS_ROOT_PATHS = 'EXT:ot_stats/Resources/Private/Partials';
+    const LAYOUTS_ROOT_PATHS = 'EXT:ot_stats/Resources/Private/Layouts';
+    const TEMPLATE_FILE = self::TEMPLATES_ROOT_PATHS . '/Header/Include.html';
+
+    /**
+     * Process the frontend request to insert the matomo script in the header
+     * if the stats module is activated
+     *
+     * @param ServerRequestInterface $request
+     * @param RequestHandlerInterface $handler
+     * @return ResponseInterface
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+
+        // Retrieve the current matomo site's id if set
+        $otPageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
+        $rootPageUid = $otPageRepository->getCurrentSiteRootPageId();
+
+        $statsSettingsRepository = GeneralUtility::makeInstance(StatsSettingsRepository::class);
+        $matomoSiteId = $statsSettingsRepository->getMatomoSiteId($rootPageUid);
+
+        if (!$matomoSiteId > 0) {
+            // stats are not enabled, continue
+            return $handler->handle($request);
+        }
+
+        // render view
+        $view = GeneralUtility::makeInstance(StandaloneView::class);
+        $view->setTemplateRootPaths([self::TEMPLATES_ROOT_PATHS]);
+        $view->setPartialRootPaths([self::PARTIALS_ROOT_PATHS]);
+        $view->setLayoutRootPaths([self::LAYOUTS_ROOT_PATHS]);
+        $view->setTemplatePathAndFilename(
+            GeneralUtility::getFileAbsFileName(self::TEMPLATE_FILE)
+        );
+
+        // Build the response
+        $response = $handler->handle($request);
+
+        // insert the rendered view in the body, just before the closing </html> tag
+        $newSection = $view->render();
+
+        $bodyContent = (string)$response->getBody();
+        $bodyContent = str_replace('</head>', $newSection . '</head>', $bodyContent);
+
+        $newBody = new Stream('php://temp', 'wb+');
+        $newBody->write($bodyContent);
+        $newBody->rewind();
+        $response = $response->withBody($newBody);
+
+        return $response;
+    }
+}

+ 39 - 0
ot_stats/Classes/Settings/StatsSettingsRepository.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace Opentalent\OtStats\Settings;
+
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Page\PageRepository;
+
+/**
+ * Class StatsRepository
+ *
+ * Give access to the website's settings for the stats module
+ *
+ * @package Opentalent\OtTemplating\Page
+ */
+class StatsSettingsRepository extends PageRepository
+{
+    /**
+     * Returns the website registered matomo site's id
+     * @param int $rootPageUid
+     * @return int|null
+     */
+    public function getMatomoSiteId(int $rootPageUid) {
+        // Set up a connection to the typo3 DB
+        $cnnPool = GeneralUtility::makeInstance(ConnectionPool::class);
+        $queryBuilder = $cnnPool->getQueryBuilderForTable('pages');
+        $matomoId = $queryBuilder
+                        ->select('tx_opentalent_matomo_id')
+                        ->from('pages')
+                        ->where($queryBuilder->expr()->eq('uid', $rootPageUid))
+                        ->andWhere($queryBuilder->expr()->eq('is_siteroot', 1))
+                        ->execute()
+                        ->fetchColumn(0);
+        if ($matomoId === false) {
+            throw new \RuntimeException('No existing root page with uid ' . $rootPageUid);
+        }
+        return $matomoId;
+    }
+}

+ 45 - 0
ot_stats/Classes/ViewHelpers/MatomoSiteIdViewHelper.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace Opentalent\OtStats\ViewHelpers;
+
+
+use Closure;
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtStats\Settings\StatsSettingsRepository;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+
+/**
+ * Returns the current site matomo's id if any, null else
+ *
+ *     {namespace st=Opentalent\OtStats\ViewHelpers}
+ *
+ *     {st:matomoSiteId(slug: 'foo')}
+ *
+ * @package Opentalent\OtTemplating\ViewHelpers
+ */
+class MatomoSiteIdViewHelper extends AbstractViewHelper
+{
+
+    /**
+     * -- This method is expected by Fluid --
+     * Renders the content as html
+     *
+     * @param array $arguments
+     * @param Closure $renderChildrenClosure
+     * @param RenderingContextInterface $renderingContext
+     * @return int|null
+     */
+    public static function renderStatic(
+        array $arguments,
+        Closure $renderChildrenClosure,
+        RenderingContextInterface $renderingContext
+    ) {
+        $otPageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
+        $rootPageUid = $otPageRepository->getCurrentSiteRootPageId();
+
+        $statsSettingsRepository = GeneralUtility::makeInstance(StatsSettingsRepository::class);
+        return $statsSettingsRepository->getMatomoSiteId($rootPageUid);
+    }
+}

+ 17 - 0
ot_stats/Configuration/RequestMiddlewares.php

@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * Register middlewares, which will be triggered at each request
+ */
+return [
+    'frontend' => [
+        'matomo-integration' => [
+            'target' => Opentalent\OtStats\Middleware\RequestHandler::class,
+            'before' => [
+            ],
+            'after' => [
+                'typo3/cms-frontend/output-compression'
+            ],
+        ],
+    ],
+];

+ 26 - 0
ot_stats/Readme.md

@@ -0,0 +1,26 @@
+
+# OtStats
+
+Extension de suivi des statistiques typo3.
+
+**Pré-requis**: Cette extension a été développée pour fonctionner avec Matomo 4.0+ 
+
+|||
+|---|---|
+| Extension key | ot_stats |
+| Vendor | Opentalent |
+| Nom | OtStats |
+
+Cette extension ajoute un module 'Statistiques' au backend typo3, qui permet aux administrateurs
+des sites de suivre l'activité sur leur site.
+
+Lorsqu'ils activent le suivi, l'extension va créer une nouvelle entrée dans la base de données
+Matomo, et récupère l'Id du site ainsi créé.
+Cette Id est ensuite stocké dans un champs dédié de la table 'pages'.
+
+Si un Id de site matomo est enregistré, l'extension intégrera alors le script de suivi matomo aux
+pages du site. 
+
+Aucune bannière demandant le consentement des utilisateurs n'est nécessaire d'après le RGPD, car
+les données sont anonymisées et ne sont pas utilisées pour des traitements externes à Typo3 (voir 
+[ici](https://www.cnil.fr/fr/cookies-solutions-pour-les-outils-de-mesure-daudience))

+ 17 - 0
ot_stats/Resources/Private/Language/locallang_mod.xlf

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<xliff version="1.0">
+    <file source-language="fr" datatype="plaintext" original="messages" date="2020-09-01T12:00:00Z" product-name="ot_templating">
+        <header/>
+        <body>
+            <trans-unit id="mlang_tabs_tab" xml:space="preserve">
+				<source>Statistiques</source>
+			</trans-unit>
+            <trans-unit id="mlang_labels_tablabel" xml:space="preserve">
+				<source>Statistiques</source>
+			</trans-unit>
+            <trans-unit id="mlang_labels_tabdescr" xml:space="preserve">
+				<source>Statistiques d'utilisation, par Opentalent</source>
+			</trans-unit>
+        </body>
+    </file>
+</xliff>

+ 8 - 0
ot_stats/Resources/Private/Layouts/Backend/Default.html

@@ -0,0 +1,8 @@
+{namespace v=FluidTYPO3\Vhs\ViewHelpers}
+
+<f:be.container includeCssFiles="{ot_core: '{f:uri.resource(path:\'assets/Backend/style/ot_be_module.css\', extensionName:\'ot_core\')}',
+                                  ot_stats: '{f:uri.resource(path:\'assets/Backend/style/ot_stats.css\')}'}"
+                includeJsFiles="{iframeresizer: '{f:uri.resource(path:\'assets/Backend/script/iframeResizer.min.js\')}'}">
+    <f:flashMessages />
+    <f:render section="content" />
+</f:be.container>

+ 46 - 0
ot_stats/Resources/Private/Partials/ReportCard.html

@@ -0,0 +1,46 @@
+<f:comment><!-- Displays a matomo widget --></f:comment>
+
+<f:comment>
+<!--
+   The following arguments are expected here:
+   * {title}           (string)   The widget title
+   * {id}              (string)   an html id
+   * {matomoSiteId}    (int)      the matomo site's id
+   * {matomoToken}     (string)   the matomo's user token
+   * {module}          (string)   the matomo 'moduleToWidgetize' parameter
+   * {action}          (string)   the matomo 'actionToWidgetize' parameter
+   * {period}      (string)   The analysis period ('day', 'month' or 'year')
+   * {additionalUrl}   (string)   [Optional] This string will be added at the end of the iframe's url without any formatting
+   * {width}           (int)      [Optional] Override the default card width
+   * {height}          (int)      [Optional] Override the default card height, and disable auto-resizing
+ -->
+</f:comment>
+
+<div class="reportCard">
+    <h4>{title}</h4>
+    <div class="widgetIframe">
+        <iframe width="{f:if(condition: '{width} > 0', then: width, else: '500')}"
+                height="{f:if(condition: '{height} > 0', then: height, else: '300')}"
+                id="{id}"
+				src="https://stats.2iopenservice.com/index.php?module=Widgetize
+						&action=iframe
+						&disableLink=1
+						&widget=1
+						&moduleToWidgetize={module}
+						&actionToWidgetize={action}
+						&idSite={matomoSiteId}
+						&period={period}
+						&date=today
+						&token_auth={matomoToken}
+						{additionalUrl}"
+                scrolling="yes"
+                frameborder="0"
+                marginheight="0"
+                marginwidth="0"></iframe>
+        <f:if condition="{height}>0"><f:then>
+            <f:comment><!-- no resizing --></f:comment>
+        </f:then><f:else>
+            <script defer>iFrameResize(<f:format.raw value="{"/>heightCalculationMethod:'grow'<f:format.raw value="}"/>, '#{id}')</script>
+        </f:else></f:if>
+    </div>
+</div>

+ 26 - 0
ot_stats/Resources/Private/Templates/Header/Include.html

@@ -0,0 +1,26 @@
+{namespace v=FluidTYPO3\Vhs\ViewHelpers}
+{namespace st=Opentalent\OtStats\ViewHelpers}
+
+<f:comment>
+    <!-- (Frontend) Render the matomo integration script to the current website (if stats are enabled) -->
+</f:comment>
+
+<v:variable.set name="matomo_site_id" value="{st:matomoSiteId()}" />
+
+<f:comment><!-- Matomo --></f:comment>
+<script type="text/javascript">
+    var _paq = window._paq || [];
+    _paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
+    _paq.push(["setDomains", ["*.opentalent.fr"]]);
+    _paq.push(['trackPageView']);
+    _paq.push(['enableLinkTracking']);
+    (function() <f:format.raw>{</f:format.raw>
+    var u="https://stats.2iopenservice.com/";
+    _paq.push(['setTrackerUrl', u+'matomo.php']);
+    _paq.push(['setSiteId', '{matomo_site_id}']);
+    var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
+    g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
+    <f:format.raw>}</f:format.raw>)();
+</script>
+<noscript><p><img src="https://stats.2iopenservice.com/matomo.php?idsite={matomo_site_id}&amp;rec=1" style="border:0;" alt="" /></p></noscript>
+<f:comment><!-- End Matomo Code --></f:comment>

+ 20 - 0
ot_stats/Resources/Private/Templates/OtStats/AskForActivationConfirmation.html

@@ -0,0 +1,20 @@
+<f:layout name="Backend/Default" />
+
+<f:section name="content">
+
+    <div class="ot-be-module ot-stats">
+        <div class="statsConfirmationPanel">
+            <p style="margin-bottom: 12px;">
+                Le suivi des statistiques d'utilisation n'est pas activé.
+            </p>
+            <f:link.action
+                    action="enableStats"
+                    title="select"
+                    class="ot-btn"
+            >
+                Activer le suivi de l'utilisation
+            </f:link.action>
+        </div>
+    </div>
+
+</f:section>

+ 36 - 0
ot_stats/Resources/Private/Templates/OtStats/AskForDeactivationConfirmation.html

@@ -0,0 +1,36 @@
+<f:layout name="Backend/Default" />
+
+<f:section name="content">
+
+    <div class="ot-be-module ot-stats">
+        <div class="statsConfirmationPanel">
+
+            <p>
+                Vous vous apprêtez à désactiver le suivi de l'utilisation du site. Si vous confirmez, plus aucune
+                donnée de suivi ne sera enregistrée tant que vous ne l'aurez pas réactivé.
+            </p>
+            <p>
+                <i>Notez que les données collectées jusqu'ici ne seront pas supprimées.</i>
+            </p>
+
+            <f:link.action
+                    action="disableStats"
+                    title="disableStats"
+                    class="ot-btn"
+                    arguments="{rootUid: rootUid}"
+            >
+                Désactiver le suivi de l'utilisation
+            </f:link.action>
+
+            <f:link.action
+                    action="index"
+                    title="index"
+                    class="ot-btn"
+            >
+                Annuler
+            </f:link.action>
+
+        </div>
+    </div>
+
+</f:section>

+ 134 - 0
ot_stats/Resources/Private/Templates/OtStats/Index.html

@@ -0,0 +1,134 @@
+{namespace v=FluidTYPO3\Vhs\ViewHelpers}
+{namespace ot=Opentalent\OtTemplating\ViewHelpers}
+
+<f:layout name="Backend/Default" />
+
+<f:section name="content">
+    <div class="ot-be-module ot-stats">
+        <h1>Statistiques d'utilisation</h1>
+
+        <div id="matomoFilters">
+            <span>Période d'analyse: </span>
+            <f:form action="index">
+                <f:form.select class="form-control"
+                               name="period"
+                               options="{week: 'La semaine passée',
+                                         month: 'Le mois passé',
+                                         year: 'L\'année passée'}"
+                               value="{period}">
+                </f:form.select>
+
+                <f:comment><!--
+                Important: if the cache is not disabled,
+                 then the results won't be updated even after submitting this form
+                 --></f:comment>
+                <input type="hidden"
+                       name="no_cache"
+                       value="1">
+
+                <f:form.button type="submit" class="ot-btn">
+                    Actualiser
+                </f:form.button>
+            </f:form>
+        </div>
+
+        <div id="matomoReport">
+
+            <div class="reportSection">
+
+                <f:comment><!-- Real time visits--></f:comment>
+                <f:render partial="ReportCard"
+                          arguments="{title: 'Visites en temps réel', id: 'realTimeVisits',
+                                      module: 'Live', action: 'widget',
+                                      matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+
+                <div class="reportSubSection">
+                    <f:comment><!-- Last visits graph--></f:comment>
+                    <f:render partial="ReportCard"
+                              arguments="{title: 'Dernières visites', id: 'lastVisitsGraph',
+                                          module: 'VisitsSummary', action: 'getEvolutionGraph',
+                                          matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+
+                    <f:comment><!-- Visits Summary --></f:comment>
+                    <f:render partial="ReportCard"
+                              arguments="{title: 'Résumé', id: 'visitsSummary',
+                                          module: 'VisitsSummary', action: 'get',
+                                          matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+                </div>
+            </div>
+
+            <div class="reportSection">
+
+                <f:comment><!-- By weekday --></f:comment>
+                <f:render partial="ReportCard"
+                          arguments="{title: 'Par jours de la semaine', id: 'visitsByWeekday',
+                                      module: 'VisitTime', action: 'getByDayOfWeek',
+                                      matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+
+                <f:comment><!-- By local hour --></f:comment>
+                <f:render partial="ReportCard"
+                          arguments="{title: 'Par heures locales', id: 'visitsByHour',
+                                      module: 'VisitTime', action: 'getVisitInformationPerLocalTime',
+                                      matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+
+                <f:comment><!-- Map --></f:comment>
+                <f:render partial="ReportCard"
+                          arguments="{title: 'Répartition géographique', id: 'visitsMap',
+                                      module: 'UserCountryMap', action: 'visitorMap',
+                                      matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+            </div>
+
+            <div class="reportSection">
+
+                <f:comment><!-- Refferers --></f:comment>
+                <f:render partial="ReportCard"
+                          arguments="{title: 'Origines', id: 'visitsRefferers',
+                                      module: 'Referrers', action: 'getAll',
+                                      matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+
+                <f:comment><!-- By web-browsers   --></f:comment>
+                <f:render partial="ReportCard"
+                          arguments="{title: 'DevicesDetection', id: 'getBrowsers',
+                                      module: 'Referrers', action: 'getAll',
+                                      matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+
+            </div>
+
+            <div class="reportSection">
+
+                <f:comment><!-- By page   --></f:comment>
+                <f:render partial="ReportCard"
+                          arguments="{title: 'Pages visitées', id: 'visitsByPage',
+                                      module: 'Actions', action: 'getPageUrls', width: '1028',
+                                      matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+            </div>
+
+            <div class="reportSection">
+
+                <f:comment><!-- By entry page --></f:comment>
+                <f:render partial="ReportCard"
+                          arguments="{title: 'Pages d\'entrée', id: 'visitorsEntryPoints',
+                                      module: 'Actions', action: 'getEntryPageUrls',
+                                      matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+
+                <f:comment><!-- By visits duration   --></f:comment>
+                <f:render partial="ReportCard"
+                          arguments="{title: 'Durée des visite', id: 'visitsByDuration',
+                                      module: 'VisitorInterest', action: 'getNumberOfVisitsPerVisitDuration',
+                                      matomoSiteId: matomoSiteId, matomoToken: matomoToken, period: period}"/>
+            </div>
+
+            <div class="reportFooter">
+                <f:link.action
+                        action="askForDeactivationConfirmation"
+                        title="select"
+                        id="disableLink"
+                        class="warning"
+                >
+                    Désactiver le suivi de l'utilisation
+                </f:link.action>
+            </div>
+
+        </div>
+    </div>
+</f:section>

BIN=BIN
ot_stats/Resources/Public/Icons/Extension.png


BIN=BIN
ot_stats/Resources/Public/Icons/Extension_white.png


BIN=BIN
ot_stats/Resources/Public/Icons/pie-chart.png


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 7 - 0
ot_stats/Resources/Public/assets/Backend/script/iframeResizer.min.js


+ 74 - 0
ot_stats/Resources/Public/assets/Backend/style/ot_stats.css

@@ -0,0 +1,74 @@
+
+.ot-stats {
+    margin: 20px 3%;
+}
+
+.statsConfirmationPanel {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    border: solid 1px #cccccc;
+    padding: 22px;
+    margin: 0 15%;
+}
+
+.statsConfirmationPanel > * {
+    margin: 8px 0;
+}
+
+.warning {
+    color: #800000;
+}
+
+#matomoFilters {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+}
+
+#matomoFilters > form {
+    display: flex;
+    flex-direction: row;
+}
+
+#matomoFilters > form > * {
+    margin: 0 6px;
+}
+
+#matomoReport {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+}
+
+#matomoReport .reportSection {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+}
+
+#matomoReport .reportSubSection {
+    display: flex;
+    flex-direction: column;
+}
+
+#matomoReport .reportCard {
+    display: flex;
+    flex-direction: column;
+    margin: 12px 24px;
+}
+
+#matomoReport .widgetIframe {
+}
+
+.reportFooter {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-end;
+    margin-top: 54px;
+}
+
+#disableLink {
+    color: #800000;
+    text-decoration: underline;
+}

+ 26 - 0
ot_stats/composer.json

@@ -0,0 +1,26 @@
+{
+    "name": "opentalent/ot_stats",
+    "type": "typo3-cms-extension",
+    "description": "Statistiques d'utilisation par Opentalent",
+    "authors": [
+        {
+            "name": "Olivier Massot",
+            "role": "Developer"
+        }
+    ],
+    "require": {
+        "typo3/cms-core": "^9.5 || ^10.4",
+        "fluidtypo3/vhs": "^6",
+        "fluidtypo3/flux": "^9",
+        "fluidtypo3/fluidpages": "^5"
+    },
+    "replace": {
+        "ot_stats": "self.version",
+        "typo3-ter/ot_stats": "self.version"
+    },
+    "autoload": {
+        "psr-4": {
+            "Opentalent\\OtStats\\": "Classes"
+        }
+    }
+}

+ 32 - 0
ot_stats/ext_emconf.php

@@ -0,0 +1,32 @@
+<?php
+
+/***************************************************************
+ * Extension Manager/Repository config file for ext: "ot_stats"
+ *
+ * Manual updates:
+ * Only the data in the array - anything else is removed by next write.
+ * "version" and "dependencies" must not be touched!
+ ***************************************************************/
+
+$EM_CONF[$_EXTKEY] = [
+    'title' => 'Statistics',
+    'description' => "Suivi des statistiques d'utilisation des sites Typo3 par Opentalent",
+    'category' => 'services',
+    'author' => 'Olivier Massot',
+    'author_email' => 'olivier.massot@2iopenservice.fr',
+    'state' => 'alpha',
+    'uploadfolder' => 0,
+    'createDirs' => '',
+    'clearCacheOnLoad' => 0,
+    'version' => '0.1.0',
+    'constraints' => [
+        'depends' => [
+            'typo3' => '8.7.0-10.4.99',
+            'flux'  => '9.3.0-9.4.99',
+            'vhs'  => '6.0.0-6.0.99',
+            'ot_core' => '*'
+        ],
+        'conflicts' => [],
+        'suggests' => [],
+    ],
+];

+ 29 - 0
ot_stats/ext_tables.php

@@ -0,0 +1,29 @@
+<?php
+defined('TYPO3_MODE') || die('Access denied.');
+
+// ext_tables.php contient les directives permettant de configurer le backend
+
+call_user_func(
+    function()
+    {
+        if (TYPO3_MODE === 'BE') {
+            /**
+             * Registers the statistics backend module
+             */
+            \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
+                'Opentalent.OtStats',
+                'web', // Make module a submodule of 'web'
+                'otstats', // Submodule key
+                'after:OtTemplatingOtcustomizer', // Position
+                array(
+                    'OtStats' => 'index,askForActivationConfirmation,askForDeactivationConfirmation,enableStats,disableStats'
+                ),
+                array(
+                    'access' => 'user,group',
+                    'icon' => 'EXT:ot_stats/Resources/Public/Icons/pie-chart.png',
+                    'labels' => 'LLL:EXT:ot_stats/Resources/Private/Language/locallang_mod.xlf',
+                )
+            );
+        }
+    }
+);

+ 8 - 0
ot_stats/ext_tables.sql

@@ -0,0 +1,8 @@
+# ext_tables.sql contient les directives permettant d ajouter des tables et champs à la DB
+
+#
+# Table structure for table 'pages'
+#
+CREATE TABLE pages (
+    tx_opentalent_matomo_id bigint
+);

+ 14 - 62
ot_templating/Classes/Controller/OtCustomizerController.php

@@ -2,11 +2,11 @@
 
 namespace Opentalent\OtTemplating\Controller;
 
-use Opentalent\OtTemplating\Page\OtPageRepository;
-use Opentalent\OtTemplating\Utility\OtCacheManager;
+use Opentalent\OtCore\Controller\SelectedSiteController;
+use Opentalent\OtCore\Cache\OtCacheManager;
+use Opentalent\OtTemplating\Templating\TemplateRepository;
 use PDO;
 use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -14,34 +14,22 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  *
  * @author olivier.massot
  */
-class OtCustomizerController extends ActionController {
+class OtCustomizerController extends SelectedSiteController {
 
     /**
      * Index action (default action)
      * Displays the customizer page on the backend
      */
     public function indexAction() {
+        $this->view->assign('rootPage', $this->currentRootUid);
+        $this->view->assign('templates', TemplateRepository::templates);
 
-        // Get the current root page's uid
-        $rootPageUid = $this->getCurrentRootPageUid();
-
-        // If the current page is not a root page or a subpage of one, abort
-        $pageSelected = ($rootPageUid !== null);
-        $this->view->assign('pageSelected', (int)$pageSelected);
-        if (!$pageSelected) {
-            return;
-        }
-
-        $this->view->assign('rootPage', $rootPageUid);
-        $this->view->assign('templates', OtPageRepository::templates);
-
-        $pageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
-        $this->view->assign('currentTemplate', $pageRepository->getCurrentTemplate($rootPageUid));
-        $this->view->assign('preferences', $pageRepository->getTemplatePreferences($rootPageUid));
+        $templateRepository = GeneralUtility::makeInstance(TemplateRepository::class);
+        $this->view->assign('currentTemplate', $templateRepository->getTemplate($this->currentRootUid));
+        $this->view->assign('preferences', $templateRepository->getTemplatePreferences($this->currentRootUid));
 
         $args = $this->request->getArguments();
         $this->view->assign('preferencesUpdated', $args['preferencesUpdated']);
-
     }
 
     /**
@@ -51,16 +39,13 @@ class OtCustomizerController extends ActionController {
     public function selectTemplateAction() {
         $templateKey = $this->request->getArgument('template_key');
 
-        // Get the current root page's uid
-        $rootPageUid = $this->getCurrentRootPageUid();
-
         // applies the change in the database
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
         $queryBuilder->update('pages')
             ->where(
                 $queryBuilder->expr()->eq(
                     'uid',
-                    $queryBuilder->createNamedParameter($rootPageUid, PDO::PARAM_INT)
+                    $queryBuilder->createNamedParameter($this->currentRootUid, PDO::PARAM_INT)
                 )
             )
             ->set('tx_opentalent_template', $templateKey)
@@ -68,7 +53,7 @@ class OtCustomizerController extends ActionController {
         ;
 
         // Clear the site's cache
-        OtCacheManager::clearSiteCache($rootPageUid);
+        OtCacheManager::clearSiteCache($this->currentRootUid);
 
         $this->forward('index');
     }
@@ -79,7 +64,7 @@ class OtCustomizerController extends ActionController {
     public function updatePreferencesAction() {
         $args = $this->request->getArguments();
 
-        $prefs = OtPageRepository::defaultPreferences;
+        $prefs = TemplateRepository::defaultPreferences;
 
         if (isset($args['themeColor'])) {
             $prefs['themeColor'] = $args['themeColor'];
@@ -88,16 +73,13 @@ class OtCustomizerController extends ActionController {
             $prefs['displayCarousel'] = $args['displayCarousel'];
         }
 
-        // Get the current root page's uid
-        $rootPageUid = $this->getCurrentRootPageUid();
-
         // applies the change in the database
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
         $queryBuilder->update('pages')
             ->where(
                 $queryBuilder->expr()->eq(
                     'uid',
-                    $queryBuilder->createNamedParameter($rootPageUid, PDO::PARAM_INT)
+                    $queryBuilder->createNamedParameter($this->currentRootUid, PDO::PARAM_INT)
                 )
             )
             ->set('tx_opentalent_template_preferences', json_encode($prefs))
@@ -105,7 +87,7 @@ class OtCustomizerController extends ActionController {
         ;
 
         // Clear the site's cache
-        OtCacheManager::clearSiteCache($rootPageUid);
+        OtCacheManager::clearSiteCache($this->currentRootUid);
 
         $this->forward(
             'index',
@@ -114,34 +96,4 @@ class OtCustomizerController extends ActionController {
             ['preferencesUpdated'=>'1']
         );
     }
-
-    /**
-     * Return the uid of the root page of the currently selected
-     * site, or null if no site's page is selected
-     *
-     * @return int | null
-     */
-    public function getCurrentRootPageUid() {
-        // Get the current page uid
-        $pageId = (int) GeneralUtility::_GP('id');
-
-        // Get the root page of the site
-        $otPageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
-        $rootPage = $otPageRepository->getRootPageFor($pageId);
-
-        if (!$rootPage['uid'] > 0) {
-            return null;
-        }
-
-        return (int)$rootPage['uid'];
-    }
-
-    /**
-     * Gets the backend user
-     *
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
-     */
-    protected function getBackendUser() {
-        return $GLOBALS['BE_USER'];
-    }
 }

+ 1 - 1
ot_templating/Classes/News/NewsFilter.php

@@ -3,7 +3,7 @@
 namespace Opentalent\OtTemplating\News;
 
 use GeorgRinger\News\Utility\Page;
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use Opentalent\OtCore\Page\OtPageRepository;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 class NewsFilter

+ 1 - 0
ot_templating/Classes/Page/ErrorHandler.php

@@ -2,6 +2,7 @@
 
 namespace Opentalent\OtTemplating\Page;
 
+use Opentalent\OtCore\Page\OtPageRepository;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Core\Error\PageErrorHandler\PageContentErrorHandler;

+ 83 - 0
ot_templating/Classes/Templating/TemplateRepository.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace Opentalent\OtTemplating\Templating;
+
+use Opentalent\OtCore\Page\OtPageRepository;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Class TemplateRepository
+ * Provides methods to retrieve data about the current site's template
+ *
+ * @package Opentalent\OtCore\Templating
+ */
+class TemplateRepository
+{
+    CONST templates = [
+        'Classic' => [
+            'name' => 'Classique',
+            'description' => "Le thème classique, simple et complet. C'est le thème par défaut.",
+            'picture' => 'EXT:ot_templating/Resources/Public/media/theme_classic.png'
+        ],
+        'Modern' => [
+            'name' => 'Moderne',
+            'description' => '[Nouveauté 2020] Un thème moderne et intuitif.',
+            'picture' => 'EXT:ot_templating/Resources/Public/media/theme_modern.png'
+        ]
+    ];
+
+    CONST defaultTemplate = 'Classic';
+
+    CONST defaultPreferences = [
+        'themeColor' => 'lightblue',
+        'displayCarousel' => '1'
+    ];
+
+    /**
+     * Returns the site template's name
+     *
+     * @param int $rootUid
+     * @return string
+     */
+    public function getTemplate(int $rootUid) {
+        if (!($rootUid >= 0)) {
+            return self::defaultTemplate;
+        }
+
+        $cnnPool = GeneralUtility::makeInstance(ConnectionPool::class);
+        $queryBuilder = $cnnPool->getQueryBuilderForTable('pages');
+        $templateName = $queryBuilder
+            ->select('tx_opentalent_template')
+            ->from('pages')
+            ->where($queryBuilder->expr()->eq('uid', $rootUid))
+            ->execute()
+            ->fetchColumn(0);
+
+        if ($templateName==='') {
+            return self::defaultTemplate;
+        }
+        return $templateName;
+    }
+
+    /**
+     * Returns the current site template's name
+     * @param int $rootUid
+     * @return array
+     */
+    public function getTemplatePreferences(int $rootUid) {
+        $cnnPool = GeneralUtility::makeInstance(ConnectionPool::class);
+        $queryBuilder = $cnnPool->getQueryBuilderForTable('pages');
+        $templatePreferences = $queryBuilder
+            ->select('tx_opentalent_template_preferences')
+            ->from('pages')
+            ->where($queryBuilder->expr()->eq('uid', $rootUid))
+            ->execute()
+            ->fetchColumn(0);
+
+        if ($templatePreferences==='') {
+            return self::defaultPreferences;
+        }
+        return json_decode($templatePreferences, true);
+    }
+}

+ 0 - 35
ot_templating/Classes/Utility/Tsfe.php

@@ -1,35 +0,0 @@
-<?php
-
-
-namespace Opentalent\OtTemplating\Utility;
-
-
-use TYPO3\CMS\Core\Site\Entity\SiteInterface;
-use TYPO3\CMS\Core\Site\SiteFinder;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-class Tsfe
-{
-    public function initializeFrontEndRendering($pageId = 0)
-    {
-        $siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
-        /** @var SiteInterface $site */
-        $site = $siteFinder->getSiteByPageId($pageId);
-        $GLOBALS['TSFE'] = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
-            'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController',
-            $GLOBALS['TYPO3_CONF_VARS'],
-            $site,
-            $site->getDefaultLanguage()
-        );
-        $GLOBALS['TSFE']->set_no_cache();
-        $GLOBALS['TSFE']->fe_user = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication::class);
-        $GLOBALS['TSFE']->fe_user->checkPid_value = 0;
-        $GLOBALS['TSFE']->fe_user->start();
-        $GLOBALS['TSFE']->fe_user->unpack_uc();
-        $GLOBALS['TSFE']->determineId();
-        $GLOBALS['TSFE']->getConfigArray();
-        $GLOBALS['TSFE']->cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer');
-        $GLOBALS['TSFE']->settingLanguage();
-        $GLOBALS['TSFE']->settingLocale();
-    }
-}

+ 2 - 14
ot_templating/Classes/ViewHelpers/Carousel/ImagesViewHelper.php

@@ -4,11 +4,8 @@ namespace Opentalent\OtTemplating\ViewHelpers\Carousel;
 
 use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
 use FluidTYPO3\Vhs\ViewHelpers\Page\Resources\FalViewHelper;
-use Opentalent\OtTemplating\Domain\Repository\EventRepository;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  *   This view helper provides an an array of the FAL images files
@@ -24,9 +21,8 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class ImagesViewHelper extends AbstractViewHelper implements LoggerAwareInterface {
+class ImagesViewHelper extends OtAbstractViewHelper {
 
-    use LoggerAwareTrait;
     use TemplateVariableViewHelperTrait;
 
     /**
@@ -99,12 +95,4 @@ class ImagesViewHelper extends AbstractViewHelper implements LoggerAwareInterfac
         $variables = [$as => $images, $countAs => $count];
         return $this->renderChildrenWithVariables($variables);
     }
-
-    /**
-     * @param EventRepository $eventRepository
-     */
-    public function injectEventRepository(EventRepository $eventRepository)
-    {
-        $this->eventRepository = $eventRepository;
-    }
 }

+ 4 - 9
ot_templating/Classes/ViewHelpers/Donors/GetAllViewHelper.php

@@ -3,12 +3,9 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Donors;
 
 use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
-use Opentalent\OtTemplating\Domain\Repository\DonorRepository;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+use Opentalent\OtCore\Domain\Repository\DonorRepository;
+use Opentalent\OtCore\Exception\ApiRequestException;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 
 /**
  *   This view helper give access to an ApiPagedCollection named according to the 'as' variable
@@ -23,9 +20,8 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetAllViewHelper extends AbstractViewHelper implements LoggerAwareInterface {
+class GetAllViewHelper extends OtAbstractViewHelper {
 
-    use LoggerAwareTrait;
     use TemplateVariableViewHelperTrait;
     /**
      * >> Required to prevent typo3 to escape the html output
@@ -75,7 +71,6 @@ class GetAllViewHelper extends AbstractViewHelper implements LoggerAwareInterfac
      */
     public function render()
     {
-
         // Get current settings
         $as = $this->arguments['as'];
         $organizationId = $this->arguments['organizationId'];

+ 5 - 8
ot_templating/Classes/ViewHelpers/Events/GetAllViewHelper.php

@@ -3,11 +3,9 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Events;
 
 use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
-use Opentalent\OtTemplating\Domain\Repository\EventRepository;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtCore\Domain\Repository\EventRepository;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 /**
  *   This view helper give access to an ApiPagedCollection named according to the 'as' variable
@@ -22,9 +20,8 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetAllViewHelper extends AbstractViewHelper implements LoggerAwareInterface {
+class GetAllViewHelper extends OtAbstractViewHelper {
 
-    use LoggerAwareTrait;
     use TemplateVariableViewHelperTrait;
 
     /**
@@ -71,7 +68,7 @@ class GetAllViewHelper extends AbstractViewHelper implements LoggerAwareInterfac
      * Renders the content as html
      *
      * @return string
-     * @throws ApiRequestException
+     * @throws ApiRequestException|\Exception
      */
     public function render()
     {

+ 5 - 8
ot_templating/Classes/ViewHelpers/Events/GetByIdViewHelper.php

@@ -3,12 +3,10 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Events;
 
 use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
-use Opentalent\OtTemplating\Domain\Model\Event;
-use Opentalent\OtTemplating\Domain\Repository\EventRepository;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtCore\Domain\Model\Event;
+use Opentalent\OtCore\Domain\Repository\EventRepository;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 /**
  *   This view helper returns the Event object matching the given id
@@ -22,9 +20,8 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetByIdViewHelper extends AbstractViewHelper implements LoggerAwareInterface {
+class GetByIdViewHelper extends OtAbstractViewHelper {
 
-    use LoggerAwareTrait;
     use TemplateVariableViewHelperTrait;
 
     /**

+ 5 - 11
ot_templating/Classes/ViewHelpers/Events/GetNextViewHelper.php

@@ -3,14 +3,9 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Events;
 
 use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
-use FluidTYPO3\Vhs\Utility\ErrorUtility;
-use Opentalent\OtTemplating\Domain\Repository\EventRepository;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
-use TYPO3\CMS\Core\TimeTracker\TimeTracker;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtCore\Domain\Repository\EventRepository;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 /**
  *   This view helper provides an ApiPagedCollection named according to the 'as' variable
@@ -27,9 +22,8 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetNextViewHelper extends AbstractViewHelper implements LoggerAwareInterface {
+class GetNextViewHelper extends OtAbstractViewHelper {
 
-    use LoggerAwareTrait;
     use TemplateVariableViewHelperTrait;
 
     /**
@@ -112,7 +106,7 @@ class GetNextViewHelper extends AbstractViewHelper implements LoggerAwareInterfa
         $fromChildren = $this->arguments['fromChildren'];
 
         if (!$organizationId) {
-            ErrorUtility::throwViewHelperException('Organization id is missing');
+            $this->throwException('Organization id is missing');
         }
 
         $fromDate = new \DateTime();

+ 3 - 3
ot_templating/Classes/ViewHelpers/EventsPage/GetIdViewHelper.php

@@ -3,10 +3,10 @@
 namespace Opentalent\OtTemplating\ViewHelpers\EventsPage;
 
 use Closure;
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  * Retrieves and returns the uid of the events' page of the current site
@@ -21,7 +21,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetIdViewHelper extends AbstractViewHelper
+class GetIdViewHelper extends OtAbstractViewHelper
 {
 
     /**

+ 3 - 4
ot_templating/Classes/ViewHelpers/EventsPage/GetUriViewHelper.php

@@ -2,8 +2,8 @@
 
 namespace Opentalent\OtTemplating\ViewHelpers\EventsPage;
 
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  * Retrieves and returns the Uri to the events page of the current site
@@ -18,7 +18,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetUriViewHelper extends AbstractViewHelper
+class GetUriViewHelper extends OtAbstractViewHelper
 {
     /**
      *  -- This method is expected by Fluid --
@@ -41,7 +41,6 @@ class GetUriViewHelper extends AbstractViewHelper
         }
 
         $uriBuilder = $renderingContext->getControllerContext()->getUriBuilder();
-        $uri = $uriBuilder->setTargetPageUid($pageUid)->build();
-        return $uri;
+        return $uriBuilder->setTargetPageUid($pageUid)->build();
     }
 }

+ 4 - 3
ot_templating/Classes/ViewHelpers/GetPageUidViewHelper.php

@@ -4,7 +4,8 @@ namespace Opentalent\OtTemplating\ViewHelpers;
 
 
 use Closure;
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use Opentalent\OtTemplating\ViewHelpers\RootPage\GetIdViewHelper;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
@@ -17,11 +18,11 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  *     {namespace ot=Opentalent\OtTemplating\ViewHelpers}
  *
- *     {ot:pageExists(slug: 'foo')}
+ *     {ot:getPageUid(slug: 'foo')}
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetPageUidViewHelper extends AbstractViewHelper
+class GetPageUidViewHelper extends OtAbstractViewHelper
 {
 
     /**

+ 0 - 7
ot_templating/Classes/ViewHelpers/ImagePViewHelper.php

@@ -2,14 +2,8 @@
 
 namespace Opentalent\OtTemplating\ViewHelpers;
 
-
-use Closure;
-use Opentalent\OtTemplating\Page\OtPageRepository;
-use Opentalent\OtTemplating\ViewHelpers\RootPage\GetIdViewHelper;
 use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\ViewHelpers\ImageViewHelper;
-use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
 
 /**
  * -- Wrapper for the TYPO3\CMS\Fluid\ViewHelpers\ImageViewHelper --
@@ -25,7 +19,6 @@ use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
  */
 class ImagePViewHelper extends ImageViewHelper
 {
-
     /**
      * -- This method is expected by Fluid --
      * Declares the viewhelper's parameters

+ 2 - 3
ot_templating/Classes/ViewHelpers/LoginFailedViewHelper.php

@@ -3,10 +3,9 @@
 
 namespace Opentalent\OtTemplating\ViewHelpers;
 
-
 use Closure;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  * Returns true if a login attempt just failed
@@ -17,7 +16,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class LoginFailedViewHelper extends AbstractViewHelper
+class LoginFailedViewHelper extends OtAbstractViewHelper
 {
 
     /**

+ 4 - 7
ot_templating/Classes/ViewHelpers/Members/GetAllCaViewHelper.php

@@ -3,11 +3,9 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Members;
 
 use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
-use Opentalent\OtTemplating\Domain\Repository\MemberRepository;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtCore\Domain\Repository\MemberRepository;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 /**
  *   This view helper give access to an array named according to the 'as' variable
@@ -22,9 +20,8 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetAllCaViewHelper extends AbstractViewHelper implements LoggerAwareInterface {
+class GetAllCaViewHelper extends OtAbstractViewHelper {
 
-    use LoggerAwareTrait;
     use TemplateVariableViewHelperTrait;
 
     /**

+ 4 - 7
ot_templating/Classes/ViewHelpers/Members/GetAllViewHelper.php

@@ -3,11 +3,9 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Members;
 
 use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
-use Opentalent\OtTemplating\Domain\Repository\MemberRepository;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+use Opentalent\OtCore\Domain\Repository\MemberRepository;
+use Opentalent\OtCore\Exception\ApiRequestException;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 
 /**
  *   This view helper give access to an array named according to the 'as' variable
@@ -22,9 +20,8 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetAllViewHelper extends AbstractViewHelper implements LoggerAwareInterface {
+class GetAllViewHelper extends OtAbstractViewHelper {
 
-    use LoggerAwareTrait;
     use TemplateVariableViewHelperTrait;
 
     /**

+ 5 - 8
ot_templating/Classes/ViewHelpers/Organizations/GetByIdViewHelper.php

@@ -3,12 +3,10 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Organizations;
 
 use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
-use Opentalent\OtTemplating\Domain\Model\Organization;
-use Opentalent\OtTemplating\Domain\Repository\OrganizationRepository;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtCore\Domain\Model\Organization;
+use Opentalent\OtCore\Domain\Repository\OrganizationRepository;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 /**
  *   This view helper return the Organization object matching the given id
@@ -22,9 +20,8 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetByIdViewHelper extends AbstractViewHelper implements LoggerAwareInterface {
+class GetByIdViewHelper extends OtAbstractViewHelper {
 
-    use LoggerAwareTrait;
     use TemplateVariableViewHelperTrait;
 
     /**

+ 4 - 7
ot_templating/Classes/ViewHelpers/Organizations/GetChildrenViewHelper.php

@@ -3,11 +3,9 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Organizations;
 
 use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
-use Opentalent\OtTemplating\Domain\Repository\OrganizationRepository;
-use Opentalent\OtTemplating\Exception\ApiRequestException;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtCore\Domain\Repository\OrganizationRepository;
+use Opentalent\OtCore\Exception\ApiRequestException;
 
 /**
  *   This view helper returns the organization children structures as an ApiPagedCollection
@@ -21,9 +19,8 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetChildrenViewHelper extends AbstractViewHelper implements LoggerAwareInterface {
+class GetChildrenViewHelper extends OtAbstractViewHelper {
 
-    use LoggerAwareTrait;
     use TemplateVariableViewHelperTrait;
 
     /**

+ 2 - 2
ot_templating/Classes/ViewHelpers/Request/GetArgumentViewHelper.php

@@ -3,8 +3,8 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Request;
 
 use Closure;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  *   Check if an argument with this name was passed trough the request.
@@ -16,7 +16,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetArgumentViewHelper extends AbstractViewHelper {
+class GetArgumentViewHelper extends OtAbstractViewHelper {
 
     /**
      * -- This method is expected by Fluid --

+ 2 - 2
ot_templating/Classes/ViewHelpers/Request/GetParameterViewHelper.php

@@ -3,8 +3,8 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Request;
 
 use Closure;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  *   Checks if a parameter with this name was passed trough the GET request.
@@ -16,7 +16,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetParameterViewHelper extends AbstractViewHelper {
+class GetParameterViewHelper extends OtAbstractViewHelper {
 
     /**
      * -- This method is expected by Fluid --

+ 2 - 11
ot_templating/Classes/ViewHelpers/Request/GetViewHelper.php

@@ -3,8 +3,8 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Request;
 
 use Closure;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  *   Returns the current GET request as an array.
@@ -15,16 +15,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetViewHelper extends AbstractViewHelper {
-
-    /**
-     * -- This method is expected by Fluid --
-     * Declares the viewhelper's parameters
-     */
-    public function initializeArguments()
-    {
-    }
-
+class GetViewHelper extends OtAbstractViewHelper {
     /**
      * -- This method is expected by Fluid --
      * Renders the content as html

+ 2 - 2
ot_templating/Classes/ViewHelpers/Request/WithPageViewHelper.php

@@ -3,8 +3,8 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Request;
 
 use Closure;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  *   Returns the current url with a 'page=' argument set up or updated
@@ -16,7 +16,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class WithPageViewHelper extends AbstractViewHelper {
+class WithPageViewHelper extends OtAbstractViewHelper {
 
     /**
      * -- This method is expected by Fluid --

+ 3 - 3
ot_templating/Classes/ViewHelpers/RootPage/GetIdViewHelper.php

@@ -3,10 +3,10 @@
 namespace Opentalent\OtTemplating\ViewHelpers\RootPage;
 
 use Closure;
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  * Viewhelper to retrieve the Id of the current site root page
@@ -18,7 +18,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetIdViewHelper extends AbstractViewHelper
+class GetIdViewHelper extends OtAbstractViewHelper
 {
     /**
      * -- This method is expected by Fluid --

+ 3 - 5
ot_templating/Classes/ViewHelpers/RootPage/GetUriViewHelper.php

@@ -3,12 +3,10 @@
 namespace Opentalent\OtTemplating\ViewHelpers\RootPage;
 
 use Closure;
-use FluidTYPO3\Vhs\Service\PageService;
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtCore\Page\OtPageRepository;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\Object\ObjectManager;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  * Viewhelper to retrieve the Uri of the root page of the current site
@@ -20,7 +18,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class GetUriViewHelper extends AbstractViewHelper
+class GetUriViewHelper extends OtAbstractViewHelper
 {
     /**
      * -- This method is expected by Fluid --

+ 8 - 5
ot_templating/Classes/ViewHelpers/Template/CurrentViewHelper.php

@@ -4,10 +4,11 @@ namespace Opentalent\OtTemplating\ViewHelpers\Template;
 
 
 use Closure;
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtTemplating\Templating\TemplateRepository;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  * Returns the name of the current template
@@ -18,7 +19,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers\Template
  */
-class CurrentViewHelper extends AbstractViewHelper
+class CurrentViewHelper extends OtAbstractViewHelper
 {
     /**
      * -- This method is expected by Fluid --
@@ -35,7 +36,9 @@ class CurrentViewHelper extends AbstractViewHelper
         RenderingContextInterface $renderingContext
     ) {
         $pageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
-        return $pageRepository->getCurrentTemplate();
-    }
+        $rootUid = $pageRepository->getCurrentSiteRootPageId();
 
+        $templateRepository = GeneralUtility::makeInstance(TemplateRepository::class);
+        return $templateRepository->getTemplate($rootUid);
+    }
 }

+ 9 - 4
ot_templating/Classes/ViewHelpers/Template/GetPreferenceViewHelper.php

@@ -4,10 +4,11 @@ namespace Opentalent\OtTemplating\ViewHelpers\Template;
 
 
 use Closure;
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtTemplating\Templating\TemplateRepository;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  * Returns the value of the requested preference
@@ -18,7 +19,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers\Template
  */
-class GetPreferenceViewHelper extends AbstractViewHelper
+class GetPreferenceViewHelper extends OtAbstractViewHelper
 {
     /**
      * -- This method is expected by Fluid --
@@ -49,7 +50,11 @@ class GetPreferenceViewHelper extends AbstractViewHelper
         RenderingContextInterface $renderingContext
     ) {
         $pageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
-        $preferences = $pageRepository->getTemplatePreferences();
+        $rootUid = $pageRepository->getCurrentSiteRootPageId();
+
+        $templateRepository = GeneralUtility::makeInstance(TemplateRepository::class);
+        $preferences = $templateRepository->getTemplatePreferences($rootUid);
+
         $key = $arguments['key'];
         return $preferences[$key];
     }

+ 8 - 4
ot_templating/Classes/ViewHelpers/Template/GetPreferencesViewHelper.php

@@ -3,10 +3,11 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Template;
 
 use Closure;
-use Opentalent\OtTemplating\Page\OtPageRepository;
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtTemplating\Templating\TemplateRepository;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  * Returns the recorded preferences
@@ -17,7 +18,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers\Template
  */
-class PreferencesViewHelper extends AbstractViewHelper
+class PreferencesViewHelper extends OtAbstractViewHelper
 {
     /**
      * -- This method is expected by Fluid --
@@ -34,7 +35,10 @@ class PreferencesViewHelper extends AbstractViewHelper
         RenderingContextInterface $renderingContext
     ) {
         $pageRepository = GeneralUtility::makeInstance(OtPageRepository::class);
-        return $pageRepository->getTemplatePreferences();
+        $rootUid = $pageRepository->getCurrentSiteRootPageId();
+
+        $templateRepository = GeneralUtility::makeInstance(TemplateRepository::class);
+        return $templateRepository->getTemplatePreferences($rootUid);
     }
 
 }

+ 2 - 2
ot_templating/Classes/ViewHelpers/Utilities/CountViewHelper.php

@@ -3,8 +3,8 @@
 namespace Opentalent\OtTemplating\ViewHelpers\Utilities;
 
 use Closure;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  *   Returns the number of elements of an array
@@ -15,7 +15,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class CountViewHelper extends AbstractViewHelper {
+class CountViewHelper extends OtAbstractViewHelper {
 
     /**
      * -- This method is expected by Fluid --

+ 1 - 1
ot_templating/Configuration/TypoScript/constants.txt

@@ -54,7 +54,7 @@ plugin.tx_ottemplating {
             # >> Ces paramètres doivent pouvoir être modifiés via l'onglet Page Configuration du backend
 
             # Tout afficher en statique plutôt que de faire defiler
-            static = 1
+            static = 0
         }
         news {
             limit = 5

+ 2 - 2
ot_templating/Configuration/TypoScript/setup.txt

@@ -1,7 +1,7 @@
 #### Configuration typoscript des sites
 
 # **** Options de debug ****
-[applicationContext == Development*]
+[applicationContext == "Development"]
     config.debug = 1
     config.contentObjectExceptionHandler = 0
     config.admPanel = 0
@@ -10,7 +10,7 @@
     plugin.tx_vhs.settings.asset.debug = 0
 [end]
 
-[applicationContext == Testing*]
+[applicationContext == "Testing"]
     config.debug = 1
 [end]
 

+ 6 - 4
ot_templating/Readme.md

@@ -23,11 +23,13 @@ Editer le gabarit, aller à la page 'Inclusions' et inclure les extensions suiva
 
 * Fluid Content Elements (fluid_styled_content)
 * Fluid Content Elements CSS (optional) (fluid_styled_content)
-* Flux PAGE rendering (flux)
+* Form (form)
+* News (news)
+* Frontend editing (frontend_editing)
+* Editable Fluid Styled Content v9 (frontend_editing)
 * Templating (ot_templating)
-* Connect (ot_connect)
 
-Ensuite, ajouter les lignes suivantes dans le champs constants:
+Ensuite, ajouter les lignes suivantes dans le champs `constants`:
 
     plugin.tx_ottemplating {
         settings {
@@ -35,7 +37,7 @@ Ensuite, ajouter les lignes suivantes dans le champs constants:
         }
     }
 
-Pour connaitre les variables de configuration à redéfinir ici, voir le fichier `ot_templating/Configuration/TypoScript/constants.txt`
+Pour connaitre le contenu exact, voir le fichier `ot_templating/Configuration/TypoScript/constants.txt`
 
 Enregistrer, et quitter.
 

+ 3 - 4
ot_templating/Resources/Private/Layouts/Backend/Default.html

@@ -1,9 +1,8 @@
 {namespace v=FluidTYPO3\Vhs\ViewHelpers}
 
-<f:be.container includeCssFiles="{ot_customizer: '{f:uri.resource(path:\'assets/Backend/style/ot_customizer.css\')}'}">
-    <div class="ot-templating">
-        <f:render section="content" />
-    </div>
+<f:be.container includeCssFiles="{ot_core: '{f:uri.resource(path:\'assets/Backend/style/ot_be_module.css\', extensionName:\'ot_core\')}',
+                                  ot_customizer: '{f:uri.resource(path:\'assets/Backend/style/ot_customizer.css\')}'}">
+    <f:render section="content" />
 </f:be.container>
 
 

+ 9 - 55
ot_templating/Resources/Private/Layouts/Modern/Members.html

@@ -13,64 +13,18 @@
             <div class="container">
                 <div class="row">
                     <div class="col-lg-12 col-md-12">
-                        <h1 class="text-center">Liste des adhérents</h1>
+                        <h1 class="text-center">Les Adhérents</h1>
 
-                        <ot:members.getAll as="members"
-                                           organizationId="{settings.organizationId}">
+                        <div class="ot-members">
+                            <ot:members.getAll as="members"
+                                               organizationId="{settings.organizationId}"
+                                               groupByInstruments="1">
 
-                            <f:if condition="{members -> f:count()} > 0">
-                                <f:then>
-                                    <f:for each="{members}" as="member" iteration="i">
+                                <f:render partial="Modern/MembersList"
+                                          arguments="{settings: settings, members: members}"/>
 
-                                        <f:if condition="{i.index -> v:math.modulo(b: 4)}===0">
-                                            <f:if condition="i>1">
-                                        </div>
-                                            </div>
-                                            </f:if>
-
-                                        <div class="team-3 mb-50 mt-70">
-                                            <div class="row">
-                                        </f:if>
-
-                                                <div class="col-lg-3 col-sm-6 sm-mb-30">
-                                                    <div class="team team-round full-border">
-                                                        <div class="team-photo">
-                                                            <f:if condition="{member.image}">
-                                                                <f:then>
-                                                                    <img class="img-fluid mx-auto"
-                                                                         src="{member.image}/160x0"
-                                                                         alt="{member.fullName}"/>
-                                                                </f:then>
-                                                                <f:else>
-                                                                    <f:image class="img-fluid mx-auto"
-                                                                             src="EXT:ot_templating/Resources/Public/media/unknown_user.jpg"
-                                                                             alt="{member.fullName}"/>
-                                                                </f:else>
-                                                            </f:if>
-                                                        </div>
-
-                                                        <div class="team-description">
-                                                            <div class="team-info">
-                                                                <h5><a href="team-single.html">{member.fullName}</a></h5>
-                                                                <span>{f:translate(key: member.instrument)}</span>
-                                                            </div>
-                                                        </div>
-                                                    </div>
-                                                </div>
-
-                                        <f:if condition="{i.index} === {total}">
-                                            </div>
-                                        </div>
-                                        </f:if>
-
-                                    </f:for>
-                                </f:then>
-                                <f:else>
-                                    <h5>Aucun adhérent</h5>
-                                </f:else>
-                            </f:if>
-
-                        </ot:members.getAll>
+                            </ot:members.getAll>
+                        </div>
                     </div>
                 </div>
             </div>

+ 9 - 55
ot_templating/Resources/Private/Layouts/Modern/MembersCa.html

@@ -14,64 +14,18 @@
             <div class="container">
                 <div class="row">
                     <div class="col-lg-12 col-md-12">
-                        <h1 class="text-center">Liste des membres du CA</h1>
+                        <h1 class="text-center">Membres du CA</h1>
 
-                        <ot:members.getAllCa as="membersCollection"
-                                           organizationId="{settings.organizationId}">
+                        <div class="ot-members">
+                            <ot:members.getAllCa as="members"
+                                                 organizationId="{settings.organizationId}"
+                                                 groupByMissions="1">
 
-                            <f:if condition="{members -> f:count()} > 0">
-                                <f:then>
-                                    <f:for each="{members}" as="member" iteration="i">
+                                <f:render partial="Modern/MembersList"
+                                          arguments="{settings: settings, members: members}"/>
 
-                                        <f:if condition="{i.index -> v:math.modulo(b: 4)}===0">
-                                            <f:if condition="i>1">
-                                        </div>
-                                            </div>
-                                            </f:if>
-
-                                        <div class="team-3 mb-50 mt-70">
-                                            <div class="row">
-                                        </f:if>
-
-                                                <div class="col-lg-3 col-sm-6 sm-mb-30">
-                                                    <div class="team team-round full-border">
-                                                        <div class="team-photo">
-                                                            <f:if condition="{member.image}">
-                                                                <f:then>
-                                                                    <img class="img-fluid mx-auto"
-                                                                         src="{member.image}/160x0"
-                                                                         alt="{member.fullName}"/>
-                                                                </f:then>
-                                                                <f:else>
-                                                                    <f:image class="img-fluid mx-auto"
-                                                                             src="EXT:ot_templating/Resources/Public/media/unknown_user.jpg"
-                                                                             alt="{member.fullName}"/>
-                                                                </f:else>
-                                                            </f:if>
-                                                        </div>
-
-                                                        <div class="team-description">
-                                                            <div class="team-info">
-                                                                <h5><a href="team-single.html">{member.fullName}</a></h5>
-                                                                <span>{f:translate(key: member.mission)}</span>
-                                                            </div>
-                                                        </div>
-                                                    </div>
-                                                </div>
-
-                                        <f:if condition="{i.index} === {total}">
-                                            </div>
-                                        </div>
-                                        </f:if>
-
-                                    </f:for>
-                                </f:then>
-                                <f:else>
-                                    <h5>Aucun adhérent</h5>
-                                </f:else>
-                            </f:if>
-
-                        </ot:members.getAllCa>
+                            </ot:members.getAllCa>
+                        </div>
                     </div>
 
                 </div>

+ 2 - 2
ot_templating/Resources/Private/Partials/Classic/Assets.html

@@ -49,7 +49,7 @@ Assets included with the VHS viewhelpers
 
 <v:asset.script name="classic-slick"
                 path="{assets_dir}/script/slick.min.js"
-                dependencies="jquery"
+                dependencies="classic-jquery"
                 defer="1"/>
 
 <v:asset.script name="classic-leaflet"
@@ -58,6 +58,6 @@ Assets included with the VHS viewhelpers
 
 <v:asset.script name="classic-main"
                 path="{assets_dir}/script/main.js"
-                dependencies="jquery,datepicker,slick,leaflet"
+                dependencies="classic-jquery,classic-datepicker,classic-slick,classic-leaflet"
                 standalone="1"
                 defer="1"/>

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio