From a4d3d53036d4a953197034b4da46ce9e7bf772b5 Mon Sep 17 00:00:00 2001
From: Andreas Fernandez <a.fernandez@scripting-base.de>
Date: Wed, 6 Apr 2022 11:30:23 +0200
Subject: [PATCH] [TASK] Render notification when saving a record succeeded
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

To improve both, UX and acceptance tests (incl. automated screenshots
for docs), a notification is now dispatched when records were saved via
EditDocumentController.

Resolves: #95271
Releases: main
Change-Id: I98b43bb9ecf643d634740ffc4241943a49a5a87f
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/74196
Tested-by: core-ci <typo3@b13.com>
Tested-by: Björn Jacob <bjoern.jacob@tritum.de>
Tested-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Björn Jacob <bjoern.jacob@tritum.de>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
---
 .../Controller/EditDocumentController.php     | 40 ++++++++++++++++++-
 .../Private/Language/locallang_alt_doc.xlf    |  9 +++++
 .../core/Classes/DataHandling/DataHandler.php | 12 +++++-
 3 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php
index 876085349d0d..c9fb98c5012e 100644
--- a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php
+++ b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php
@@ -50,6 +50,9 @@ use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Messaging\AbstractMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
+use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException;
 use TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException;
@@ -636,6 +639,42 @@ class EditDocumentController
             // Recompile the store* values since editconf changed...
             $this->compileStoreData($request);
         }
+
+        // Explicitly require a save operation
+        if ($this->doSave) {
+            $erroneousRecords = $tce->printLogErrorMessages();
+            $messages = [];
+            $table = (string)key($this->editconf);
+            $uidList = GeneralUtility::intExplode(',', (string)key($this->editconf[$table]));
+
+            foreach ($uidList as $uid) {
+                $uid = (int)abs($uid);
+                if (!in_array($table . '.' . $uid, $erroneousRecords, true)) {
+                    $realUidInPayload = ($tceSubstId = array_search($uid, $tce->substNEWwithIDs, true)) !== false ? $tceSubstId : $uid;
+                    $row = $this->data[$table][$uid] ?? $this->data[$table][$realUidInPayload] ?? null;
+                    if ($row !== null) {
+                        $recordTitle = GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $row), $this->getBackendUser()->uc['titleLen']);
+                        $messages[] = sprintf($this->getLanguageService()->getLL('notification.record_saved.message'), $recordTitle);
+                    }
+                }
+            }
+
+            // Add messages to the flash message container only if the request is a save action (excludes "duplicate")
+            if ($messages !== []) {
+                $title = count($messages) === 1 ? 'notification.record_saved.title.singular' : 'notification.record_saved.title.plural';
+                $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
+                $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier(FlashMessageQueue::NOTIFICATION_QUEUE);
+                $flashMessage = GeneralUtility::makeInstance(
+                    FlashMessage::class,
+                    implode(LF, $messages),
+                    $this->getLanguageService()->getLL($title),
+                    AbstractMessage::OK,
+                    true
+                );
+                $defaultFlashMessageQueue->enqueue($flashMessage);
+            }
+        }
+
         // If a document should be duplicated.
         if (isset($parsedBody['_duplicatedoc']) && is_array($this->editconf)) {
             $this->closeDocument(self::DOCUMENT_CLOSE_MODE_NO_REDIRECT, $request);
@@ -693,7 +732,6 @@ class EditDocumentController
             // Inform the user of the duplication
             $view->addFlashMessage($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.recordDuplicated'));
         }
-        $tce->printLogErrorMessages();
 
         if ($this->closeDoc < self::DOCUMENT_CLOSE_MODE_DEFAULT
             || isset($parsedBody['_saveandclosedok'])
diff --git a/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf b/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf
index 39115e454701..767025a2cfe6 100644
--- a/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf
+++ b/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf
@@ -144,6 +144,15 @@
 			<trans-unit id="buttons.pageTsConfig" resname="buttons.pageTsConfig">
 				<source>PageTS Config</source>
 			</trans-unit>
+			<trans-unit id="notification.record_saved.title.singular" resname="notification.record_saved.title.singular">
+				<source>Record saved</source>
+			</trans-unit>
+			<trans-unit id="notification.record_saved.title.plural" resname="notification.record_saved.title.plural">
+				<source>Records saved</source>
+			</trans-unit>
+			<trans-unit id="notification.record_saved.message" resname="notification.record_saved.message">
+				<source>Record "%s" has been successfully saved.</source>
+			</trans-unit>
 		</body>
 	</file>
 </xliff>
diff --git a/typo3/sysext/core/Classes/DataHandling/DataHandler.php b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
index 4ec85c1ede9f..fa05d4eb079b 100644
--- a/typo3/sysext/core/Classes/DataHandling/DataHandler.php
+++ b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
@@ -9181,10 +9181,13 @@ class DataHandler implements LoggerAwareInterface
     }
 
     /**
-     * Print log error messages from the operations of this script instance
+     * Print log error messages from the operations of this script instance and return a list of the erroneous records
+     *
      * @internal should only be used from within TYPO3 Core
+     *
+     * @return non-empty-string[]
      */
-    public function printLogErrorMessages()
+    public function printLogErrorMessages(): array
     {
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_log');
         $queryBuilder->getRestrictions()->removeAll();
@@ -9205,7 +9208,10 @@ class DataHandler implements LoggerAwareInterface
             )
             ->executeQuery();
 
+        $affectedRecords = [];
         while ($row = $result->fetchAssociative()) {
+            $affectedRecords[] = $row['tablename'] . '.' . $row['recuid'];
+
             $msg = $this->formatLogDetails($row['details'], $row['log_data'] ?? '');
             $msg = $row['error'] . ': ' . $msg;
             $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $msg, '', $row['error'] === SystemLogErrorClassification::WARNING ? FlashMessage::WARNING : FlashMessage::ERROR, true);
@@ -9213,6 +9219,8 @@ class DataHandler implements LoggerAwareInterface
             $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
             $defaultFlashMessageQueue->enqueue($flashMessage);
         }
+
+        return $affectedRecords;
     }
 
     /*****************************
-- 
GitLab