From 713f9a6aa3b129b12f2da480ab802a35ba53ace8 Mon Sep 17 00:00:00 2001
From: Georgi Mateev <gmateev@exactag.com>
Date: Tue, 11 Jan 2022 19:53:52 +0200
Subject: [PATCH] [BUGFIX] Fix version handling and add new settings to fix
 multilanguage and/or multi-site configurations #192

---
 Classes/Hook/HandleVersionChange.php          | 16 +++--
 .../Service/StaticFileGenerationService.php   |  2 +
 .../tx_sgcookieoptin_domain_model_optin.php   | 14 ++++-
 .../Private/Language/de.locallang_db.xlf      |  8 +++
 Resources/Private/Language/locallang_db.xlf   |  6 ++
 Resources/Public/JavaScript/cookieOptin.js    | 58 ++++++++++++++-----
 ext_tables.sql                                |  1 +
 7 files changed, 81 insertions(+), 24 deletions(-)

diff --git a/Classes/Hook/HandleVersionChange.php b/Classes/Hook/HandleVersionChange.php
index f50ab70a..432a5225 100644
--- a/Classes/Hook/HandleVersionChange.php
+++ b/Classes/Hook/HandleVersionChange.php
@@ -56,16 +56,14 @@ class HandleVersionChange {
 	) {
 		if (isset($fieldArray['update_version_checkbox']) && $fieldArray['update_version_checkbox']) {
 			$id = (int) $id;
-			$currentVersion = VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version);
-			$sqlQuery = "UPDATE $table SET version = version + 1 WHERE uid = $id OR l10n_parent = $id";
 
-			if ($currentVersion < 8000000) {
-				$GLOBALS['TYPO3_DB']->sql_query($sqlQuery);
-			} else {
-				$connection = GeneralUtility::makeInstance(ConnectionPool::class)
-					->getConnectionForTable($table);
-				$connection->executeQuery($sqlQuery);
-			}
+			$currentVersionQuery = "SELECT max(IFNULL(version, 0)), pid FROM $table
+				WHERE deleted = 0 AND pid = (SELECT pid FROM $table WHERE uid = $id)";
+			$connection = GeneralUtility::makeInstance(ConnectionPool::class)
+				->getConnectionForTable($table);
+			list($currentVersion, $pid) = array_values($connection->executeQuery($currentVersionQuery)->fetchAssociative());
+			$sqlQuery = "UPDATE $table SET version = $currentVersion + 1 WHERE pid = $pid AND deleted = 0";
+			$connection->executeQuery($sqlQuery);
 
 			$fieldArray['update_version_checkbox'] = 0;
 		}
diff --git a/Classes/Service/StaticFileGenerationService.php b/Classes/Service/StaticFileGenerationService.php
index 79b70cd1..200a1197 100644
--- a/Classes/Service/StaticFileGenerationService.php
+++ b/Classes/Service/StaticFileGenerationService.php
@@ -803,11 +803,13 @@ class StaticFileGenerationService implements SingletonInterface {
 			'cookiebanner_whitelist_regex' => (string) $translatedData['cookiebanner_whitelist_regex'],
 			'banner_show_again_interval' => (int) $translatedData['banner_show_again_interval'],
 			'identifier' => $this->siteRoot,
+			'language' => $languageUid,
 			'render_assets_inline' => (int) $translatedData['render_assets_inline'],
 			'consider_do_not_track' => (int) $translatedData['consider_do_not_track'],
 			'domains_to_delete_cookies_for' => (string) $translatedData['domains_to_delete_cookies_for'],
 			'subdomain_support' => (boolean) $translatedData['subdomain_support'],
 			'overwrite_baseurl' => (string) $translatedData['overwrite_baseurl'],
+			'unified_cookie_name' => (boolean) $translatedData['unified_cookie_name'],
 		];
 
 		$textEntries = [
diff --git a/Configuration/TCA/tx_sgcookieoptin_domain_model_optin.php b/Configuration/TCA/tx_sgcookieoptin_domain_model_optin.php
index 4c7f1d47..30a26251 100644
--- a/Configuration/TCA/tx_sgcookieoptin_domain_model_optin.php
+++ b/Configuration/TCA/tx_sgcookieoptin_domain_model_optin.php
@@ -71,7 +71,7 @@ $configuration = [
 				--div--;LLL:EXT:sg_cookie_optin/Resources/Private/Language/locallang_db.xlf:tx_sgcookieoptin_domain_model_optin.tab.group,
 					groups,
 				--div--;LLL:EXT:sg_cookie_optin/Resources/Private/Language/locallang_db.xlf:tx_sgcookieoptin_domain_model_optin.tab.settings,
-					--palette--;;cookie_lifetime_settings, overwrite_baseurl, minify_generated_data, activate_testing_mode, disable_for_this_language, render_assets_inline, consider_do_not_track, --palette--;;multidomain, cookiebanner_whitelist_regex, banner_show_again_interval',
+					unified_cookie_name, --palette--;;cookie_lifetime_settings, overwrite_baseurl, minify_generated_data, activate_testing_mode, disable_for_this_language, render_assets_inline, consider_do_not_track, --palette--;;multidomain, cookiebanner_whitelist_regex, banner_show_again_interval',
 		],
 	],
 	'palettes' => [
@@ -1593,6 +1593,16 @@ $configuration = [
 				'default' => '0',
 			],
 		],
+		'unified_cookie_name' => [
+			'exclude' => TRUE,
+			'l10n_mode' => 'exclude',
+			'label' => 'LLL:EXT:sg_cookie_optin/Resources/Private/Language/locallang_db.xlf:tx_sgcookieoptin_domain_model_optin.unified_cookie_name',
+			'description' => 'LLL:EXT:sg_cookie_optin/Resources/Private/Language/locallang_db.xlf:tx_sgcookieoptin_domain_model_optin.unified_cookie_name.description',
+			'config' => [
+				'type' => 'check',
+				'default' => '1',
+			],
+		],
 	],
 ];
 
@@ -1670,7 +1680,7 @@ if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo
 		. 'banner_button_accept_text, banner_button_settings_text, banner_description, show_button_close,'
 		. 'activate_testing_mode, color_full_box, color_full_headline, color_full_text, color_full_button_close,'
 		. 'color_full_button_close_hover, color_full_button_close_text, color_table_header, save_confirmation_text,'
-		. 'color_confirmation_background, color_confirmation_text, session_only_essential_cookies, iframe_whitelist, iframe_whitelist_overwritten, iframe_whitelist_selection, iframe_whitelist_regex, subdomain_support, set_cookie_for_domain, domains_to_delete_cookies_for, cookiebanner_whitelist_regex, disable_powered_by, disable_for_this_language, render_assets_inline, consider_do_not_track, banner_show_again_interval, version';
+		. 'color_confirmation_background, color_confirmation_text, session_only_essential_cookies, iframe_whitelist, iframe_whitelist_overwritten, iframe_whitelist_selection, iframe_whitelist_regex, subdomain_support, set_cookie_for_domain, domains_to_delete_cookies_for, cookiebanner_whitelist_regex, disable_powered_by, disable_for_this_language, render_assets_inline, consider_do_not_track, banner_show_again_interval, version, unified_cookie_name';
 }
 
 return $configuration;
diff --git a/Resources/Private/Language/de.locallang_db.xlf b/Resources/Private/Language/de.locallang_db.xlf
index f8907e38..99b49d43 100644
--- a/Resources/Private/Language/de.locallang_db.xlf
+++ b/Resources/Private/Language/de.locallang_db.xlf
@@ -801,6 +801,14 @@ Ohne diese Einstellung gilt diese Konfiguration nur für die Domäne, in der sie
 				<source><![CDATA[When a group is not accepted, also delete cookies from the following domains separated by newline. Cookies from the current domain are always automatically deleted.]]></source>
 				<target><![CDATA[Wenn eine Gruppe nicht akzeptiert wird, Cookies auch von den nachfolgenden, per Zeilenumbruch separierten, Domains löschen. Cookies von der aktuellen Domain werden immer automatisch gelöscht.]]></target>
 			</trans-unit>
+			<trans-unit id="tx_sgcookieoptin_domain_model_optin.unified_cookie_name" approved="yes">
+				<source><![CDATA[Unified Cookie Name]]></source>
+				<target><![CDATA[Einheitlicher Cookie-Name]]></target>
+			</trans-unit>
+			<trans-unit id="tx_sgcookieoptin_domain_model_optin.unified_cookie_name.description" approved="yes">
+				<source><![CDATA[Unchecking this box would lead to having separate configurations for each language and site root. This would lead to visitors having to select their preferences for each different language and site root.]]></source>
+				<target><![CDATA[Das Deaktivieren dieses Häkchens würde dazu führen, dass für jede Sprache und jedes Site-Root separate Konfigurationen vorhanden sind. Dies würde dazu führen, dass die Besucher ihre Präferenzen für jede Sprache und jedes Site-Root auswählen müssten.]]></target>
+			</trans-unit>
 		</body>
 	</file>
 </xliff>
diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf
index 44f0f000..fd71e437 100644
--- a/Resources/Private/Language/locallang_db.xlf
+++ b/Resources/Private/Language/locallang_db.xlf
@@ -590,6 +590,12 @@ Without this setting, this configuration only applies to the domain where it is
 			<trans-unit id="tx_sgcookieoptin_domain_model_optin.domains_to_delete_cookies_for" approved="yes">
 				<source><![CDATA[When a group is not accepted, also delete cookies from the following domains separated by newline. Cookies from the current domain are always automatically deleted.]]></source>
 			</trans-unit>
+			<trans-unit id="tx_sgcookieoptin_domain_model_optin.unified_cookie_name" approved="yes">
+				<source><![CDATA[Unified Cookie Name]]></source>
+			</trans-unit>
+			<trans-unit id="tx_sgcookieoptin_domain_model_optin.unified_cookie_name.description" approved="yes">
+				<source><![CDATA[Unchecking this box would lead to having separate configurations for each language and site root. This would lead to visitors having to select their preferences for each different language and site root.]]></source>
+			</trans-unit>
 		</body>
 	</file>
 </xliff>
diff --git a/Resources/Public/JavaScript/cookieOptin.js b/Resources/Public/JavaScript/cookieOptin.js
index 5dd3ff7a..a7c3af9e 100644
--- a/Resources/Public/JavaScript/cookieOptin.js
+++ b/Resources/Public/JavaScript/cookieOptin.js
@@ -41,6 +41,7 @@ var SgCookieOptin = {
 
 		SgCookieOptin.jsonData = JSON.parse(document.getElementById('cookieOptinData').innerHTML);
 		if (SgCookieOptin.jsonData) {
+			SgCookieOptin.checkLanguageSettings();
 			// https://plainjs.com/javascript/events/running-code-when-the-document-is-ready-15/
 			document.addEventListener('DOMContentLoaded', function() {
 				SgCookieOptin.initialize();
@@ -82,6 +83,18 @@ var SgCookieOptin = {
 		}
 	},
 
+	/**
+	 * Checks if we will have different settings per language
+	 */
+	checkLanguageSettings: function() {
+		if (!SgCookieOptin.jsonData.settings.unified_cookie_name) {
+			SgCookieOptin.COOKIE_NAME += '_' + SgCookieOptin.jsonData.settings.identifier + '_'
+				+ SgCookieOptin.jsonData.settings.language;
+			SgCookieOptin.LAST_PREFERENCES_COOKIE_NAME += '_' + SgCookieOptin.jsonData.settings.identifier + '_'
+				+ SgCookieOptin.jsonData.settings.language;
+		}
+	},
+
 	/**
 	 * Checks if the external cookie group has been accepted
 	 * @returns {boolean}
@@ -686,7 +699,24 @@ var SgCookieOptin = {
 	 * @param cookieName
 	 */
 	deleteGroupCookie: function(cookieName) {
-		document.cookie = cookieName + '=; path=/; Max-Age=-99999999;';
+		var cookie = cookieName + '=; path=/; Max-Age=-99999999;';
+		document.cookie = cookie; // This is important in case the configuration that we test below has been changed
+
+		if (SgCookieOptin.jsonData.settings.set_cookie_for_domain && SgCookieOptin.jsonData.settings.set_cookie_for_domain.length > 0) {
+					cookie += ';domain=' + SgCookieOptin.jsonData.settings.set_cookie_for_domain;
+		} else if (SgCookieOptin.jsonData.settings.subdomain_support) {
+			var domainParts = currentHost.split('.');
+			if (domainParts.length > 2) {
+				domainParts.shift();
+				var hostnameToFirstDot = '.' + domainParts.join('.');
+				cookie +=  ';domain=' + hostnameToFirstDot;
+			}
+		} else {
+			cookie +=  ';domain=' + currentHost;
+		}
+
+		document.cookie = cookie;
+
 		var additionalDomains = SgCookieOptin.jsonData.settings.domains_to_delete_cookies_for.trim()
 			.split(/\r?\n/).map(function (value) {
 				return value.trim();
@@ -1641,20 +1671,21 @@ var SgCookieOptin = {
 
 		var currentHost = window.location.hostname;
 		var cookieStringEnd = ';expires=' + d.toUTCString() + '; SameSite=None; Secure';
-		document.cookie = cookie + cookieStringEnd;
 
-		if (SgCookieOptin.jsonData.settings.subdomain_support) {
+		if (SgCookieOptin.jsonData.settings.set_cookie_for_domain && SgCookieOptin.jsonData.settings.set_cookie_for_domain.length > 0) {
+					cookie += ';domain=' + SgCookieOptin.jsonData.settings.set_cookie_for_domain;
+		} else if (SgCookieOptin.jsonData.settings.subdomain_support) {
 			var domainParts = currentHost.split('.');
 			if (domainParts.length > 2) {
 				domainParts.shift();
 				var hostnameToFirstDot = '.' + domainParts.join('.');
-				document.cookie = cookie +  ';domain=' + hostnameToFirstDot + cookieStringEnd;
+				cookie +=  ';domain=' + hostnameToFirstDot;
 			}
+		} else {
+			cookie +=  ';domain=' + currentHost;
 		}
 
-		if (SgCookieOptin.jsonData.settings.set_cookie_for_domain && SgCookieOptin.jsonData.settings.set_cookie_for_domain.length > 0) {
-			document.cookie = cookie + ';domain=' + SgCookieOptin.jsonData.settings.set_cookie_for_domain + cookieStringEnd;
-		}
+		document.cookie = cookie + cookieStringEnd;
 	},
 
 	/**
@@ -1668,20 +1699,21 @@ var SgCookieOptin = {
 
 		var currentHost = window.location.hostname;
 		var cookieStringEnd = ';SameSite=None; Secure';
-		document.cookie = cookie + cookieStringEnd;
 
-		if (SgCookieOptin.jsonData.settings.subdomain_support) {
+		if (SgCookieOptin.jsonData.settings.set_cookie_for_domain && SgCookieOptin.jsonData.settings.set_cookie_for_domain.length > 0) {
+			cookie += ';domain=' + SgCookieOptin.jsonData.settings.set_cookie_for_domain;
+		} else if (SgCookieOptin.jsonData.settings.subdomain_support) {
 			var domainParts = currentHost.split('.');
 			if (domainParts.length > 2) {
 				domainParts.shift();
 				var hostnameToFirstDot = '.' + domainParts.join('.');
-				document.cookie = cookie +  ';domain=' + hostnameToFirstDot + cookieStringEnd;
+				cookie +=  ';domain=' + hostnameToFirstDot;
 			}
+		} else {
+			cookie +=  ';domain=' + currentHost;
 		}
 
-		if (SgCookieOptin.jsonData.settings.set_cookie_for_domain && SgCookieOptin.jsonData.settings.set_cookie_for_domain.length > 0) {
-			document.cookie = cookie + ';domain=' + SgCookieOptin.jsonData.settings.set_cookie_for_domain + cookieStringEnd;
-		}
+		document.cookie = cookie + cookieStringEnd;
 	},
 
 	/**
diff --git a/ext_tables.sql b/ext_tables.sql
index b15a1528..e32a3ceb 100644
--- a/ext_tables.sql
+++ b/ext_tables.sql
@@ -143,6 +143,7 @@ CREATE TABLE tx_sgcookieoptin_domain_model_optin (
     domains_to_delete_cookies_for TEXT,
 	subdomain_support tinyint(4) DEFAULT '0',
 	overwrite_baseurl TEXT,
+	unified_cookie_name tinyint(4) DEFAULT '1',
 
 	-- TYPO3 related columns
 	tstamp int(11) unsigned DEFAULT '0' NOT NULL,
-- 
GitLab