From e66cb258807a696047bd8584f7e383db84dd3165 Mon Sep 17 00:00:00 2001
From: Benni Mack <benni@typo3.org>
Date: Mon, 23 Mar 2020 17:17:17 +0100
Subject: [PATCH] [TASK] Allow workspace preview links independent of backend
 users

Current implementation for defining a maximum lifetime of a workspace-related
previewlink is based on userTSconfig - which actually relies on the user configuration
that creates the preview link. This can lead to massive side effects.

The option is therefore added to each workspace with a default value of "48 hours",
to properly define the lifetime on a per-workspace and not on a
"per-user-who-generated the links" basis.

Actual features will be to add a GUI to the workspace module and see currently
working preview links. The UserTSconfig option should be marked as
deprecated in further iterations together with the new GUI feature.

Resolves: #66948
Releases: master
Change-Id: I76c2dabef81d5e1b3fc2d88e049c9df09381cb6f
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63881
Tested-by: Susanne Moog <look@susi.dev>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
---
 .../Classes/Preview/PreviewUriBuilder.php     | 21 ++++++-----------
 .../Classes/Service/WorkspaceService.php      | 23 +++++++++++++++++++
 .../Configuration/TCA/sys_workspace.php       | 11 ++++++++-
 .../Private/Language/locallang_db.xlf         |  3 +++
 typo3/sysext/workspaces/ext_tables.sql        |  1 +
 5 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/typo3/sysext/workspaces/Classes/Preview/PreviewUriBuilder.php b/typo3/sysext/workspaces/Classes/Preview/PreviewUriBuilder.php
index 44648030511e..d86b2c8b3069 100644
--- a/typo3/sysext/workspaces/Classes/Preview/PreviewUriBuilder.php
+++ b/typo3/sysext/workspaces/Classes/Preview/PreviewUriBuilder.php
@@ -48,9 +48,15 @@ class PreviewUriBuilder
      */
     protected $workspaceService;
 
+    /**
+     * @var int
+     */
+    protected $previewLinkLifetime;
+
     public function __construct()
     {
         $this->workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
+        $this->previewLinkLifetime = $this->workspaceService->getPreviewLinkLifetime();
     }
 
     /**
@@ -63,7 +69,7 @@ class PreviewUriBuilder
     public function buildUriForPage(int $uid, int $languageId = 0): string
     {
         $previewKeyword = $this->compilePreviewKeyword(
-            $this->getPreviewLinkLifetime() * 3600,
+            $this->previewLinkLifetime * 3600,
             $this->workspaceService->getCurrentWorkspace()
         );
 
@@ -223,19 +229,6 @@ class PreviewUriBuilder
         return $keyword;
     }
 
-    /**
-     * easy function to just return the number of hours
-     * a preview link is valid, based on the TSconfig value "options.workspaces.previewLinkTTLHours"
-     * by default, it's 48hs
-     *
-     * @return int The hours as a number
-     */
-    protected function getPreviewLinkLifetime(): int
-    {
-        $ttlHours = (int)($this->getBackendUser()->getTSConfig()['options.']['workspaces.']['previewLinkTTLHours'] ?? 0);
-        return $ttlHours ?: 24 * 2;
-    }
-
     /**
      * Find the Live-Uid for a given page,
      * the results are cached at run-time to avoid too many database-queries
diff --git a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php
index 8faa0b3d5b10..63005013ec72 100644
--- a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php
+++ b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php
@@ -100,6 +100,29 @@ class WorkspaceService implements SingletonInterface
         return $workspaceId;
     }
 
+    /**
+     * easy function to just return the number of hours.
+     *
+     * a preview link is valid, based on the workspaces' custom value (default to 48 hours)
+     * or falls back to the users' TSconfig value "options.workspaces.previewLinkTTLHours".
+     *
+     * by default, it's 48hs.
+     *
+     * @return int The hours as a number
+     */
+    public function getPreviewLinkLifetime(): int
+    {
+        $workspaceId = $GLOBALS['BE_USER']->workspace;
+        if ($workspaceId > 0) {
+            $wsRecord = BackendUtility::getRecord('sys_workspace', $workspaceId, '*');
+            if (($wsRecord['previewlink_lifetime'] ?? 0) > 0) {
+                return (int)$wsRecord['previewlink_lifetime'];
+            }
+        }
+        $ttlHours = (int)($GLOBALS['BE_USER']->getTSConfig()['options.']['workspaces.']['previewLinkTTLHours'] ?? 0);
+        return $ttlHours ?: 24 * 2;
+    }
+
     /**
      * Find the title for the requested workspace.
      *
diff --git a/typo3/sysext/workspaces/Configuration/TCA/sys_workspace.php b/typo3/sysext/workspaces/Configuration/TCA/sys_workspace.php
index b2dc144490b0..f132b694206b 100644
--- a/typo3/sysext/workspaces/Configuration/TCA/sys_workspace.php
+++ b/typo3/sysext/workspaces/Configuration/TCA/sys_workspace.php
@@ -137,6 +137,15 @@ return [
                 ]
             ]
         ],
+        'previewlink_lifetime' => [
+            'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.previewlink_lifetime',
+            'config' => [
+                'type' => 'input',
+                'eval' => 'int',
+                'size' => 10,
+                'default' => 48,
+            ]
+        ],
         'stagechg_notification' => [
             'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.stagechg_notification',
             'config' => [
@@ -311,7 +320,7 @@ return [
             --div--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:tabs.mountpoints,
                 db_mountpoints,file_mountpoints,
             --div--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:tabs.publish_access,
-                live_edit,swap_modes,publish_access,publish_time,
+                previewlink_lifetime,live_edit,swap_modes,publish_access,publish_time,
             --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,
                 description,
             --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended,
diff --git a/typo3/sysext/workspaces/Resources/Private/Language/locallang_db.xlf b/typo3/sysext/workspaces/Resources/Private/Language/locallang_db.xlf
index e87227a963ff..093a125cc777 100644
--- a/typo3/sysext/workspaces/Resources/Private/Language/locallang_db.xlf
+++ b/typo3/sysext/workspaces/Resources/Private/Language/locallang_db.xlf
@@ -120,6 +120,9 @@
 			<trans-unit id="sys_workspace.stagechg_notification" resname="sys_workspace.stagechg_notification">
 				<source>Notification settings during state change</source>
 			</trans-unit>
+			<trans-unit id="sys_workspace.previewlink_lifetime" resname="sys_workspace.previewlink_lifetime">
+				<source>Lifetime in hours on how long a preview link will be valid</source>
+			</trans-unit>
 			<trans-unit id="sys_workspace.stagechg_notification.0" resname="sys_workspace.stagechg_notification.0">
 				<source>Disable notifications</source>
 			</trans-unit>
diff --git a/typo3/sysext/workspaces/ext_tables.sql b/typo3/sysext/workspaces/ext_tables.sql
index b49f10f0415c..7c7148ef1229 100644
--- a/typo3/sysext/workspaces/ext_tables.sql
+++ b/typo3/sysext/workspaces/ext_tables.sql
@@ -23,6 +23,7 @@ CREATE TABLE sys_workspace (
 	live_edit tinyint(3) DEFAULT '0' NOT NULL,
 	swap_modes tinyint(3) DEFAULT '0' NOT NULL,
 	publish_access tinyint(3) DEFAULT '0' NOT NULL,
+	previewlink_lifetime int(11) DEFAULT '0' NOT NULL,
 	custom_stages int(11) DEFAULT '0' NOT NULL,
 	stagechg_notification tinyint(3) DEFAULT '0' NOT NULL,
 	edit_notification_defaults varchar(255) DEFAULT '' NOT NULL,
-- 
GitLab