From 1cc98b58ac2e7cfdc642399e80eb3c8ebcc36eb7 Mon Sep 17 00:00:00 2001 From: Stefan Froemken Date: Mon, 30 Oct 2023 20:53:57 +0100 Subject: [PATCH 1/5] Implement FlashMesageHelper to DropboxDriver --- Classes/Driver/DropboxDriver.php | 41 ++---- Classes/Helper/FlashMessageHelper.php | 179 ++++++++++++++++++++++++++ Configuration/Services.yaml | 7 + 3 files changed, 199 insertions(+), 28 deletions(-) create mode 100644 Classes/Helper/FlashMessageHelper.php diff --git a/Classes/Driver/DropboxDriver.php b/Classes/Driver/DropboxDriver.php index 9275e46..5a78f9f 100644 --- a/Classes/Driver/DropboxDriver.php +++ b/Classes/Driver/DropboxDriver.php @@ -16,13 +16,10 @@ use StefanFroemken\Dropbox\Service\AutoRefreshingDropboxTokenService; use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; -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\Resource\Driver\AbstractDriver; use TYPO3\CMS\Core\Resource\Exception\InvalidPathException; use TYPO3\CMS\Core\Resource\ResourceStorageInterface; +use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\PathUtility; @@ -35,7 +32,7 @@ class DropboxDriver extends AbstractDriver protected ?Client $dropboxClient = null; - protected FlashMessageService $flashMessageService; + protected FlashMessageHelper $flashMessageHelper; protected array $settings = []; @@ -46,6 +43,14 @@ class DropboxDriver extends AbstractDriver */ protected $supportedHashAlgorithms = ['sha1', 'md5']; + /** + * AbstractDriver contains __construct(). So inject FlashMessageHelper with setter in DI + */ + public function setFlashMessageHelper(FlashMessageHelper $flashMessageHelper): void + { + $this->flashMessageHelper = $flashMessageHelper; + } + public function processConfiguration(): void { // no need to configure something. @@ -67,8 +72,6 @@ public function initialize(): void } else { $this->dropboxClient = null; } - - $this->flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); } public function getCapabilities(): int @@ -674,6 +677,7 @@ public function resourceExists(string $identifier): bool } $identifier = $identifier === '/' ? $identifier : rtrim($identifier, '/'); + return $this->getMetaData($identifier) !== []; } @@ -686,10 +690,10 @@ protected function copyFileToTemporaryPath(string $fileIdentifier): string try { file_put_contents($temporaryPath, stream_get_contents($this->dropboxClient->download($fileIdentifier))); } catch (BadRequest $badRequest) { - $this->addFlashMessage( + $this->flashMessageHelper->addFlashMessage( 'The file meta extraction has been interrupted, because file has been removed in the meanwhile.', 'File Meta Extraction aborted', - AbstractMessage::INFO + ContextualFeedbackSeverity::INFO ); return ''; @@ -697,23 +701,4 @@ protected function copyFileToTemporaryPath(string $fileIdentifier): string return $temporaryPath; } - - public function addFlashMessage(string $message, string $title = '', int $severity = AbstractMessage::OK): void - { - // We activate storeInSession, so that messages can be displayed when click on Save&Close button. - $flashMessage = GeneralUtility::makeInstance( - FlashMessage::class, - $message, - $title, - $severity, - true - ); - - $this->getFlashMessageQueue()->enqueue($flashMessage); - } - - protected function getFlashMessageQueue(): FlashMessageQueue - { - return $this->flashMessageService->getMessageQueueByIdentifier(); - } } diff --git a/Classes/Helper/FlashMessageHelper.php b/Classes/Helper/FlashMessageHelper.php new file mode 100644 index 0000000..9dfd524 --- /dev/null +++ b/Classes/Helper/FlashMessageHelper.php @@ -0,0 +1,179 @@ +flashMessageService = $flashMessageService; + } + + public function addFlashMessage( + string $message, + string $title = '', + ContextualFeedbackSeverity $severity = ContextualFeedbackSeverity::OK + ): void { + // We activate storeInSession, so that messages can be displayed when click on Save&Close button. + $flashMessage = GeneralUtility::makeInstance( + FlashMessage::class, + $message, + $title, + $severity, + true + ); + + try { + $this->getFlashMessageQueue()->enqueue($flashMessage); + } catch (Exception $e) { + // Exception will only be thrown if $flashMessage is not instance of FlashMessage + } + } + + /** + * @return FlashMessage[] + */ + public function getAllFlashMessages(bool $flush = true): array + { + if ($flush) { + return $this->getFlashMessageQueue()->getAllMessagesAndFlush(); + } + + return $this->getFlashMessageQueue()->getAllMessages(); + } + + public function hasMessages(): bool + { + return !empty($this->getAllFlashMessages(false)); + } + + /** + * @param ContextualFeedbackSeverity $severity Must be one of the enum values in ContextualFeedbackSeverity class + * @return FlashMessage[] + */ + protected function getFlashMessagesBySeverity(ContextualFeedbackSeverity $severity): array + { + return $this->getFlashMessageQueue()->getAllMessages($severity); + } + + /** + * @param ContextualFeedbackSeverity $severity Must be one of the enum values in ContextualFeedbackSeverity class + * @return FlashMessage[] + */ + public function getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity $severity): array + { + return $this->getFlashMessageQueue()->getAllMessagesAndFlush($severity); + } + + public function hasErrorMessages(): bool + { + return !empty($this->getErrorMessages(false)); + } + + /** + * @return AbstractMessage[] + */ + public function getErrorMessages(bool $flush = true): array + { + if ($flush) { + return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::ERROR); + } + + return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::ERROR); + } + + public function hasWarningMessages(): bool + { + return !empty($this->getWarningMessages(false)); + } + + /** + * @return AbstractMessage[] + */ + public function getWarningMessages(bool $flush = true): array + { + if ($flush) { + return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::WARNING); + } + + return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::WARNING); + } + + public function hasOkMessages(): bool + { + return !empty($this->getOkMessages(false)); + } + + /** + * @return AbstractMessage[] + */ + public function getOkMessages(bool $flush = true): array + { + if ($flush) { + return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::OK); + } + + return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::OK); + } + + public function hasInfoMessages(): bool + { + return !empty($this->getInfoMessages(false)); + } + + /** + * @return AbstractMessage[] + */ + public function getInfoMessages(bool $flush = true): array + { + if ($flush) { + return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::INFO); + } + + return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::INFO); + } + + public function hasNoticeMessages(): bool + { + return !empty($this->getNoticeMessages(false)); + } + + /** + * @return AbstractMessage[] + */ + public function getNoticeMessages(bool $flush = true): array + { + if ($flush) { + return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::NOTICE); + } + + return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::NOTICE); + } + + protected function getFlashMessageQueue(): FlashMessageQueue + { + return $this->flashMessageService->getMessageQueueByIdentifier(); + } +} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 63141c5..4d40f08 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -7,6 +7,12 @@ services: StefanFroemken\Dropbox\: resource: '../Classes/*' + # Will be called by GeneralUtility::makeInstance in TYPO3 StorageRepository + StefanFroemken\Dropbox\Driver\DropboxDriver: + public: true + calls: + - setFlashMessageHelper: ['StefanFroemken\Dropbox\Helper\FlashMessageHelper'] + # Will be called by GeneralUtility::makeInstance in DropboxDriver and DropboxStatusElement StefanFroemken\Dropbox\Service\AutoRefreshingDropboxTokenService: autowire: false @@ -17,3 +23,4 @@ services: autowire: false autoconfigure: false public: true + From 10fdec2e4012705c07cf150889a8d1da22221e6c Mon Sep 17 00:00:00 2001 From: Stefan Froemken Date: Mon, 30 Oct 2023 21:05:58 +0100 Subject: [PATCH 2/5] Try refreshing AT for 401 response only --- Classes/Service/AutoRefreshingDropboxTokenService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Service/AutoRefreshingDropboxTokenService.php b/Classes/Service/AutoRefreshingDropboxTokenService.php index 487888e..808798e 100644 --- a/Classes/Service/AutoRefreshingDropboxTokenService.php +++ b/Classes/Service/AutoRefreshingDropboxTokenService.php @@ -32,14 +32,14 @@ public function __construct(string $refreshToken, string $appKey) /** * If refresh() was called, the Dropbox Client fails to process the request, - * which results in an exception you can access here from the argument $exception. + * which results in an exception which we will catch here and try to retrieve a fresh access token. * * @return bool Whether the token was refreshed or not. */ public function refresh(ClientException $exception): bool { // We only catch unauthorized exceptions to refresh the access token - if ($exception->getCode() !== 400) { + if ($exception->getCode() !== 401) { return false; } From aaf6b072d5efb2f6897b2a001b96c8bda3027de3 Mon Sep 17 00:00:00 2001 From: Stefan Froemken Date: Mon, 30 Oct 2023 21:34:37 +0100 Subject: [PATCH 3/5] Remove DI config for DropboxDriver --- Classes/Driver/DropboxDriver.php | 36 +++++++++++++++++++------------- Configuration/Services.yaml | 7 ------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Classes/Driver/DropboxDriver.php b/Classes/Driver/DropboxDriver.php index 5a78f9f..56d6031 100644 --- a/Classes/Driver/DropboxDriver.php +++ b/Classes/Driver/DropboxDriver.php @@ -13,6 +13,7 @@ use Spatie\Dropbox\Client; use Spatie\Dropbox\Exceptions\BadRequest; +use StefanFroemken\Dropbox\Helper\FlashMessageHelper; use StefanFroemken\Dropbox\Service\AutoRefreshingDropboxTokenService; use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; @@ -32,10 +33,6 @@ class DropboxDriver extends AbstractDriver protected ?Client $dropboxClient = null; - protected FlashMessageHelper $flashMessageHelper; - - protected array $settings = []; - /** * A list of all supported hash algorithms, written all lower case. * @@ -43,14 +40,6 @@ class DropboxDriver extends AbstractDriver */ protected $supportedHashAlgorithms = ['sha1', 'md5']; - /** - * AbstractDriver contains __construct(). So inject FlashMessageHelper with setter in DI - */ - public function setFlashMessageHelper(FlashMessageHelper $flashMessageHelper): void - { - $this->flashMessageHelper = $flashMessageHelper; - } - public function processConfiguration(): void { // no need to configure something. @@ -58,8 +47,7 @@ public function processConfiguration(): void public function initialize(): void { - $this->cache = GeneralUtility::makeInstance(CacheManager::class) - ->getCache('dropbox'); + $this->cache = $this->getCacheManager()->getCache('dropbox'); if (!empty($this->configuration['refreshToken']) && !empty($this->configuration['appKey'])) { $this->dropboxClient = new Client( @@ -690,7 +678,7 @@ protected function copyFileToTemporaryPath(string $fileIdentifier): string try { file_put_contents($temporaryPath, stream_get_contents($this->dropboxClient->download($fileIdentifier))); } catch (BadRequest $badRequest) { - $this->flashMessageHelper->addFlashMessage( + $this->getFlashMessageHelper()->addFlashMessage( 'The file meta extraction has been interrupted, because file has been removed in the meanwhile.', 'File Meta Extraction aborted', ContextualFeedbackSeverity::INFO @@ -701,4 +689,22 @@ protected function copyFileToTemporaryPath(string $fileIdentifier): string return $temporaryPath; } + + /** + * DropboxDriver was called with constructor arguments. So, no DI possible. + * We have to instantiate the CacheManager on our own. + */ + private function getCacheManager(): CacheManager + { + return GeneralUtility::makeInstance(CacheManager::class); + } + + /** + * DropboxDriver was called with constructor arguments. So, no DI possible. + * We have to instantiate the FlashMessageHelper on our own. + */ + private function getFlashMessageHelper(): FlashMessageHelper + { + return GeneralUtility::makeInstance(FlashMessageHelper::class); + } } diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 4d40f08..63141c5 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -7,12 +7,6 @@ services: StefanFroemken\Dropbox\: resource: '../Classes/*' - # Will be called by GeneralUtility::makeInstance in TYPO3 StorageRepository - StefanFroemken\Dropbox\Driver\DropboxDriver: - public: true - calls: - - setFlashMessageHelper: ['StefanFroemken\Dropbox\Helper\FlashMessageHelper'] - # Will be called by GeneralUtility::makeInstance in DropboxDriver and DropboxStatusElement StefanFroemken\Dropbox\Service\AutoRefreshingDropboxTokenService: autowire: false @@ -23,4 +17,3 @@ services: autowire: false autoconfigure: false public: true - From e6349673e8240dfaf7286c43de2d6b4ee512e960 Mon Sep 17 00:00:00 2001 From: Stefan Froemken Date: Mon, 30 Oct 2023 22:14:27 +0100 Subject: [PATCH 4/5] Update documentation --- .editorconfig | 2 +- Classes/Driver/DropboxDriver.php | 4 +- Classes/Helper/FlashMessageHelper.php | 43 ++--- .../Configuration/Index.rst | 134 -------------- Documentation/AdministratorManual/Index.rst | 4 +- .../Installation/Index.rst | 44 ----- .../AdministratorManual/Update/Index.rst | 3 +- Documentation/ChangeLog/Index.rst | 9 +- Documentation/Configuration/Index.rst | 163 ++++++++++++++---- Documentation/FAQ/Index.rst | 3 +- Documentation/Includes.rst.txt | 34 ++++ Documentation/Includes.txt | 17 -- Documentation/Index.rst | 2 +- Documentation/Installation/Index.rst | 51 ++++-- Documentation/Introduction/Index.rst | 4 +- Documentation/Settings.cfg | 2 +- Documentation/Sitemap.rst | 9 + Documentation/genindex.rst | 7 + composer.json | 2 +- 19 files changed, 250 insertions(+), 287 deletions(-) delete mode 100644 Documentation/AdministratorManual/Configuration/Index.rst delete mode 100644 Documentation/AdministratorManual/Installation/Index.rst create mode 100644 Documentation/Includes.rst.txt delete mode 100644 Documentation/Includes.txt create mode 100644 Documentation/Sitemap.rst create mode 100644 Documentation/genindex.rst diff --git a/.editorconfig b/.editorconfig index 293886f..72bdfe1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,7 +13,7 @@ insert_final_newline = true trim_trailing_whitespace = true # TS/JS-Files -[*.{ts,js}] +[*.{ts,js,mjs}] indent_size = 2 # JSON-Files diff --git a/Classes/Driver/DropboxDriver.php b/Classes/Driver/DropboxDriver.php index 56d6031..a9225d1 100644 --- a/Classes/Driver/DropboxDriver.php +++ b/Classes/Driver/DropboxDriver.php @@ -64,8 +64,8 @@ public function initialize(): void public function getCapabilities(): int { - // If PUBLIC is available, each file will initiate a request to Dropbox-Api to retrieve a public share link - // this is extremely slow. + // Do not allow PUBLIC here, as each file will initiate a request to Dropbox-Api to retrieve a public share + // link which is extremely slow. return ResourceStorageInterface::CAPABILITY_BROWSABLE + ResourceStorageInterface::CAPABILITY_WRITABLE; } diff --git a/Classes/Helper/FlashMessageHelper.php b/Classes/Helper/FlashMessageHelper.php index 9dfd524..0f96554 100644 --- a/Classes/Helper/FlashMessageHelper.php +++ b/Classes/Helper/FlashMessageHelper.php @@ -11,12 +11,10 @@ namespace StefanFroemken\Dropbox\Helper; -use TYPO3\CMS\Core\Exception; 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\Type\ContextualFeedbackSeverity; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -31,11 +29,8 @@ public function __construct(FlashMessageService $flashMessageService) $this->flashMessageService = $flashMessageService; } - public function addFlashMessage( - string $message, - string $title = '', - ContextualFeedbackSeverity $severity = ContextualFeedbackSeverity::OK - ): void { + public function addFlashMessage(string $message, string $title = '', int $severity = AbstractMessage::OK): void + { // We activate storeInSession, so that messages can be displayed when click on Save&Close button. $flashMessage = GeneralUtility::makeInstance( FlashMessage::class, @@ -45,11 +40,7 @@ public function addFlashMessage( true ); - try { - $this->getFlashMessageQueue()->enqueue($flashMessage); - } catch (Exception $e) { - // Exception will only be thrown if $flashMessage is not instance of FlashMessage - } + $this->getFlashMessageQueue()->enqueue($flashMessage); } /** @@ -70,19 +61,19 @@ public function hasMessages(): bool } /** - * @param ContextualFeedbackSeverity $severity Must be one of the enum values in ContextualFeedbackSeverity class + * @param int $severity Must be one of the constants in AbstractMessage class * @return FlashMessage[] */ - protected function getFlashMessagesBySeverity(ContextualFeedbackSeverity $severity): array + protected function getFlashMessagesBySeverity(int $severity): array { return $this->getFlashMessageQueue()->getAllMessages($severity); } /** - * @param ContextualFeedbackSeverity $severity Must be one of the enum values in ContextualFeedbackSeverity class + * @param int $severity Must be one of the constants in AbstractMessage class * @return FlashMessage[] */ - public function getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity $severity): array + public function getFlashMessagesBySeverityAndFlush(int $severity): array { return $this->getFlashMessageQueue()->getAllMessagesAndFlush($severity); } @@ -98,10 +89,10 @@ public function hasErrorMessages(): bool public function getErrorMessages(bool $flush = true): array { if ($flush) { - return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::ERROR); + return $this->getFlashMessagesBySeverityAndFlush(AbstractMessage::ERROR); } - return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::ERROR); + return $this->getFlashMessagesBySeverity(AbstractMessage::ERROR); } public function hasWarningMessages(): bool @@ -115,10 +106,10 @@ public function hasWarningMessages(): bool public function getWarningMessages(bool $flush = true): array { if ($flush) { - return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::WARNING); + return $this->getFlashMessagesBySeverityAndFlush(AbstractMessage::WARNING); } - return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::WARNING); + return $this->getFlashMessagesBySeverity(AbstractMessage::WARNING); } public function hasOkMessages(): bool @@ -132,10 +123,10 @@ public function hasOkMessages(): bool public function getOkMessages(bool $flush = true): array { if ($flush) { - return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::OK); + return $this->getFlashMessagesBySeverityAndFlush(AbstractMessage::OK); } - return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::OK); + return $this->getFlashMessagesBySeverity(AbstractMessage::OK); } public function hasInfoMessages(): bool @@ -149,10 +140,10 @@ public function hasInfoMessages(): bool public function getInfoMessages(bool $flush = true): array { if ($flush) { - return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::INFO); + return $this->getFlashMessagesBySeverityAndFlush(AbstractMessage::INFO); } - return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::INFO); + return $this->getFlashMessagesBySeverity(AbstractMessage::INFO); } public function hasNoticeMessages(): bool @@ -166,10 +157,10 @@ public function hasNoticeMessages(): bool public function getNoticeMessages(bool $flush = true): array { if ($flush) { - return $this->getFlashMessagesBySeverityAndFlush(ContextualFeedbackSeverity::NOTICE); + return $this->getFlashMessagesBySeverityAndFlush(AbstractMessage::NOTICE); } - return $this->getFlashMessagesBySeverity(ContextualFeedbackSeverity::NOTICE); + return $this->getFlashMessagesBySeverity(AbstractMessage::NOTICE); } protected function getFlashMessageQueue(): FlashMessageQueue diff --git a/Documentation/AdministratorManual/Configuration/Index.rst b/Documentation/AdministratorManual/Configuration/Index.rst deleted file mode 100644 index 5162b8b..0000000 --- a/Documentation/AdministratorManual/Configuration/Index.rst +++ /dev/null @@ -1,134 +0,0 @@ -.. include:: ../../Includes.txt - - -.. _configuration: - -============= -Configuration -============= - -Create File Storage -=================== - -* Go to list module and choose PID 0 (Rootpage with TYPO3 logo in front). -* Create a new record of type ``File Storage`` -* On tab ``General`` choose a name like ``Dropbox`` -* On tab ``Configuration`` you have to choose the ``Dropbox`` driver - - -Driver Configuration -==================== - -To communicate over the Dropbox-API you need an Access Token. - -#. Create an App API at Dropbox.com -#. Copy ``App Key`` and ``App Secret`` -#. Get Access Token from developer area of www.dropbox.com - or you can create an access token with help of the wizard you can reach over ``GetAccessToken`` -#. Save the record - - -Create API at dropbox.com -------------------------- - -.. rst-class:: bignums - -1. Go to Developer area of dropbox.com - - Simply visit: https://www.dropbox.com/developers - - If this link is not valid anymore go to https://www.dropbox.com/, click the upper left menu icon with the 9 dots. - Choose the App Center. In the left menu of the `App Center` you will find a link to `Develop Apps`. Now - you should be in the developer corner of Dropbox. - -2. Create new Dropbox App - - Click the `App Console` button in the upper right corner. Now you see all your apps (if you have created some). - Click the `Create app` button. - -3. Choose API - - With a free or simple Dropbox account you only have the possibility to choose the API with `Scoped access`. - The TYPO3 Dropbox extension can only work with this API. Do not choose any other API. - -4. Choose App type - - For security reasons I prefer to choose `App folder`. But if you`re sure, you also can give your app - full access to all of your Dropbox files. - -5. Give it a name - - Assign a Dropbox global unique name to your new app. Please consider, that words like `dropbox` are not allowed - as part of the name. - - Confirm your settings with button `Create App`. You will be redirected to detail view of your app. - -6. Configure your new app - - Switch over to tab `Permissions` and activate following permissions: - - * `files.metadata.read` - * `files.content.write` - * `files.content.read` - -7. Locate `App key` and `App secret` - - For next section you will need to copy `App key` and `App secret`. from tab `Settings`. - -8. Optional: Generate Access Token - - If you don`t want to use the Wizard, you can click the `Generate` button on tab `Settings`. This will generate - an access token which you can copy&paste directly into the FAL storage record. - - -Start Driver Wizard -------------------- - -While editing the ``File storage`` click on ``GetAccessToken`` to start the wizard. -Paste in the ``App Key`` and ``App Secret`` from Dropbox App explained above. -Click on ``Get AuthCode Link`` - -.. figure:: ../../Images/AdministratorManual/dropbox_insert_app_secret.jpg - :width: 500px - :align: left - :alt: Insert app key and app secret - -On the next page you have to click on the ``authorization link`` which will open a new tab -where you have to give access to your Dropbox App. - -Copy the AuthCode from Dropbox page into the AuthCode field of the Wizard. - -.. figure:: ../../Images/AdministratorManual/dropbox_wizard_access_token.jpg - :width: 500px - :align: left - :alt: Get Access Toekn from Dropbox - -With a click on ``Get AccessToken`` a further request to dropbox.com will start in the background. -On success the Access Token will automatically inserted in ``File Storage`` record and -the wizard will close. - -Save the record. On success we show you some user data. - -.. figure:: ../../Images/AdministratorManual/dropbox_connect_success.jpg - :width: 500px - :align: left - :alt: Connection successfully - -**Performance** - -.. note:: - - At the bottom of the ``Configuration`` tab you will find the - option: ``Folder for manipulated and temporary images etc.`` - If you keep the default, all temporary images will be transferred over - the Dropbox-API which is very slow. - So it would be good to move that special folder to a folder on a - fast ``file storage``. Set this to ``1:/_processed_/dropbox`` if your - fileadmin file storage has the UID 1. - -.. attention:: - - After changing the processed folder field to a local storage (f.e. 1 - for fileadmin) you have to delete all ``sys_file_processedfile`` records - where column "storage" is the UID of your dropbox storage (f.e. UID: 2). - See: https://forge.typo3.org/issues/84069 diff --git a/Documentation/AdministratorManual/Index.rst b/Documentation/AdministratorManual/Index.rst index 1bbadae..4b8b14a 100644 --- a/Documentation/AdministratorManual/Index.rst +++ b/Documentation/AdministratorManual/Index.rst @@ -1,4 +1,4 @@ -.. include:: ../Includes.txt +.. include:: /Includes.rst.txt .. _admin-manual: @@ -15,6 +15,4 @@ For administrators :maxdepth: 2 :titlesonly: - Installation/Index - Configuration/Index Update/Index diff --git a/Documentation/AdministratorManual/Installation/Index.rst b/Documentation/AdministratorManual/Installation/Index.rst deleted file mode 100644 index 955a022..0000000 --- a/Documentation/AdministratorManual/Installation/Index.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. include:: ../Includes.txt - -.. _installation: - -============ -Installation -============ - -Installation Type -================= - -Composer --------- - -You can install `dropbox` with following shell command: - -.. code-block:: bash - - composer req stefanfroemken/dropbox - - -Extensionmanager ----------------- - -If you want to install `dropbox` traditionally with Extensionmanager, follow these steps: - -#. Visit ExtensionManager - -#. Switch over to `Get Extensions` - -#. Search for `dropbox` - -#. Install extension - - -DEV Version (GIT) ------------------ - -You can install the latest DEV Version with following GIT command: - -.. code-block:: bash - - git clone https://github.com/froemken/dropbox.git - diff --git a/Documentation/AdministratorManual/Update/Index.rst b/Documentation/AdministratorManual/Update/Index.rst index cae266e..a294fb4 100644 --- a/Documentation/AdministratorManual/Update/Index.rst +++ b/Documentation/AdministratorManual/Update/Index.rst @@ -1,4 +1,5 @@ -.. include:: ../../Includes.txt +.. include:: /Includes.rst.txt + ======== Updating diff --git a/Documentation/ChangeLog/Index.rst b/Documentation/ChangeLog/Index.rst index f976106..5a9ae84 100644 --- a/Documentation/ChangeLog/Index.rst +++ b/Documentation/ChangeLog/Index.rst @@ -1,4 +1,4 @@ -.. include:: ../Includes.txt +.. include:: /Includes.rst.txt .. _changelog: @@ -7,6 +7,13 @@ ChangeLog ========= +Version 5.0.0 +============= + +* Add TYPO3 12 compatibility +* Remove TYPO3 10 compatibility +* BUGFIX: Auto refresh AccessToken + Version 4.3.0 ============= diff --git a/Documentation/Configuration/Index.rst b/Documentation/Configuration/Index.rst index 2f881c5..8ea4222 100644 --- a/Documentation/Configuration/Index.rst +++ b/Documentation/Configuration/Index.rst @@ -1,4 +1,4 @@ -.. include:: ../Includes.txt +.. include:: /Includes.rst.txt .. _configuration: @@ -7,39 +7,128 @@ Configuration ============= -Create Dropbox App -================== - -To give TYPO3 access to your Dropbox files, you need a Dropbox app. As long as this app is under development, -up to 5 devices can connect to this app: - -#. GoTo: https://www.dropbox.com/developers -#. Choose "App console" on the upper right -#. Click the blue button "Create app" -#. Choose the "Scoped Access" -#. Decide, if you want your app to work within its own folder or, if you want to have full access to all of your files -#. Give it a name -#. Save app with "Create App" -#. Open your newly created app -#. On tab "settings" you will find app key and app secret -#. Open new tab and start configuring TYPO3 - -Configure TYPO3 -=============== - -#. Create a new file storage record on pid 0 and give it a name like "Dropbox" -#. On Tab "Configuration" choose "Dropbox" (FlexForm reloads) -#. Click the + icon right of the access token field to start the wizard -#. Enter app key and app secret from your new Dropbox app -#. Click the link to retrieve a Dropbox auth code - #. It will open a new browser tab, where you have to allow TYPO3 to access your app - #. After confirmation, you will see the auth code - #. Copy auth code over to dropbox configuration wizard -#. Click next button in wizard -#. In background my extension calls dropbox API to get access token -#. On success the access token will automatically in configuration record -#. Save the configuration record -#. On success, you will see a green panel with some useful information - about your free disk space of your Dropbox account - -Have fun using your dropbox files in TYPO3. +Create File Storage +=================== + +* Go to list module and choose PID 0 (Rootpage with TYPO3 logo in front). +* Create a new record of type ``File Storage`` +* On tab ``General`` choose a name like ``Dropbox`` +* On tab ``Configuration`` you have to choose the ``Dropbox`` driver + + +Driver Configuration +==================== + +To communicate over the Dropbox-API you need an Access Token. + +#. Create an App API at Dropbox.com +#. Copy ``App Key`` and ``App Secret`` +#. Get Access Token from developer area of www.dropbox.com + or you can create an access token with help of the wizard you can reach over ``GetAccessToken`` +#. Save the record + + +Create API at dropbox.com +------------------------- + +.. rst-class:: bignums + +1. Go to Developer area of dropbox.com + + Simply visit: https://www.dropbox.com/developers + + If this link is not valid anymore go to https://www.dropbox.com/, click the upper left menu icon with the 9 dots. + Choose the App Center. In the left menu of the `App Center` you will find a link to `Develop Apps`. Now + you should be in the developer corner of Dropbox. + +2. Create new Dropbox App + + Click the `App Console` button in the upper right corner. Now you see all your apps (if you have created some). + Click the `Create app` button. + +3. Choose API + + With a free or simple Dropbox account you only have the possibility to choose the API with `Scoped access`. + The TYPO3 Dropbox extension can only work with this API. Do not choose any other API. + +4. Choose App type + + For security reasons I prefer to choose `App folder`. But if you`re sure, you also can give your app + full access to all of your Dropbox files. + +5. Give it a name + + Assign a Dropbox global unique name to your new app. Please consider, that words like `dropbox` are not allowed + as part of the name. + + Confirm your settings with button `Create App`. You will be redirected to detail view of your app. + +6. Configure your new app + + Switch over to tab `Permissions` and activate following permissions: + + * `files.metadata.read` + * `files.content.write` + * `files.content.read` + +7. Locate `App key` and `App secret` + + For next section you will need to copy `App key` and `App secret`. from tab `Settings`. + +8. Optional: Generate Access Token + + If you don`t want to use the Wizard, you can click the `Generate` button on tab `Settings`. This will generate + an access token which you can copy&paste directly into the FAL storage record. + + +Start Driver Wizard +------------------- + +While editing the ``File storage`` click on ``GetAccessToken`` to start the wizard. +Paste in the ``App Key`` and ``App Secret`` from Dropbox App explained above. +Click on ``Get AuthCode Link`` + +.. figure:: ../../Images/AdministratorManual/dropbox_insert_app_secret.jpg + :width: 500px + :align: left + :alt: Insert app key and app secret + +On the next page you have to click on the ``authorization link`` which will open a new tab +where you have to give access to your Dropbox App. + +Copy the AuthCode from Dropbox page into the AuthCode field of the Wizard. + +.. figure:: ../../Images/AdministratorManual/dropbox_wizard_access_token.jpg + :width: 500px + :align: left + :alt: Get Access Toekn from Dropbox + +With a click on ``Get AccessToken`` a further request to dropbox.com will start in the background. +On success the Access Token will automatically inserted in ``File Storage`` record and +the wizard will close. + +Save the record. On success we show you some user data. + +.. figure:: ../../Images/AdministratorManual/dropbox_connect_success.jpg + :width: 500px + :align: left + :alt: Connection successfully + +**Performance** + +.. note:: + + At the bottom of the ``Configuration`` tab you will find the + option: ``Folder for manipulated and temporary images etc.`` + If you keep the default, all temporary images will be transferred over + the Dropbox-API which is very slow. + So it would be good to move that special folder to a folder on a + fast ``file storage``. Set this to ``1:/_processed_/dropbox`` if your + fileadmin file storage has the UID 1. + +.. attention:: + + After changing the processed folder field to a local storage (f.e. 1 + for fileadmin) you have to delete all ``sys_file_processedfile`` records + where column "storage" is the UID of your dropbox storage (f.e. UID: 2). + See: https://forge.typo3.org/issues/84069 diff --git a/Documentation/FAQ/Index.rst b/Documentation/FAQ/Index.rst index 668916a..6b2f293 100644 --- a/Documentation/FAQ/Index.rst +++ b/Documentation/FAQ/Index.rst @@ -1,4 +1,5 @@ -.. include:: ../Includes.txt +.. include:: /Includes.rst.txt + .. _faq: diff --git a/Documentation/Includes.rst.txt b/Documentation/Includes.rst.txt new file mode 100644 index 0000000..210ac57 --- /dev/null +++ b/Documentation/Includes.rst.txt @@ -0,0 +1,34 @@ +.. More information about this file: + https://docs.typo3.org/m/typo3/docs-how-to-document/main/en-us/GeneralConventions/FileStructure.html#includes-rst-txt + +.. ---------- +.. text roles +.. ---------- + +.. role:: aspect(emphasis) +.. role:: bash(code) +.. role:: html(code) +.. role:: js(code) +.. role:: php(code) +.. role:: rst(code) +.. role:: sep(strong) +.. role:: sql(code) + +.. role:: tsconfig(code) + :class: typoscript + +.. role:: typoscript(code) +.. role:: xml(code) + :class: html + +.. role:: yaml(code) + +.. default-role:: code + +.. --------- +.. highlight +.. --------- + +.. By default, code blocks use PHP syntax highlighting + +.. highlight:: php diff --git a/Documentation/Includes.txt b/Documentation/Includes.txt deleted file mode 100644 index 0c0a49d..0000000 --- a/Documentation/Includes.txt +++ /dev/null @@ -1,17 +0,0 @@ -.. This is 'Includes.txt'. It is included at the very top of each and - every ReST source file in THIS documentation project (= manual). - -.. role:: aspect (emphasis) -.. role:: html(code) -.. role:: js(code) -.. role:: php(code) -.. role:: sep (strong) -.. role:: sql(code) -.. role:: typoscript(code) -.. role:: yaml(code) - -.. role:: ts(typoscript) - :class: typoscript - -.. default-role:: code -.. highlight:: php diff --git a/Documentation/Index.rst b/Documentation/Index.rst index 49a26d3..67b8dc6 100644 --- a/Documentation/Index.rst +++ b/Documentation/Index.rst @@ -59,7 +59,7 @@ Just click on "Edit me on GitHub" on the top right to submit your change request Introduction/Index Installation/Index - Configuration/Index AdministratorManual/Index + Configuration/Index FAQ/Index ChangeLog/Index diff --git a/Documentation/Installation/Index.rst b/Documentation/Installation/Index.rst index efb9c5b..5c9a231 100644 --- a/Documentation/Installation/Index.rst +++ b/Documentation/Installation/Index.rst @@ -1,4 +1,4 @@ -.. include:: ../Includes.txt +.. include:: /Includes.rst.txt .. _installation: @@ -7,30 +7,53 @@ Installation ============ +Composer +======== -Installation Type -================= +If your TYPO3 installation works in composer mode, please execute following +command: +.. code-block:: bash -Composer --------- + composer req stefanfroemken/dropbox + vendor/bin/typo3 extension:setup --extension=dropbox -You can install `dropbox` with following shell command: +If you work with DDEV please execute this command: .. code-block:: bash - composer req stefanfroemken/dropbox + ddev composer req stefanfroemken/dropbox + ddev exec vendor/bin/typo3 extension:setup --extension=dropbox + +ExtensionManager +================ + +On non composer based TYPO3 installations you can install `dropbox` still +over the ExtensionManager: + +.. rst-class:: bignums + +1. Login + + Login to backend of your TYPO3 installation as an administrator or system + maintainer. + +2. Open ExtensionManager + Click on `Extensions` from the left menu to open the ExtensionManager. -Extensionmanager ----------------- +3. Update Extensions -If you want to install `dropbox` traditionally with Extensionmanager, follow these steps: + Choose `Get Extensions` from the upper selectbox and click on + the `Update now` button at the upper right. -#. Visit ExtensionManager +4. Install `dropbox` -#. Switch over to `Get Extensions` + Use the search field to find `dropbox`. Choose the `dropbox` + line from the search result and click on the cloud icon to + install `dropbox`. -#. Search for `dropbox` +Next step +========= -#. Install extension +:ref:`Configure dropbox `. diff --git a/Documentation/Introduction/Index.rst b/Documentation/Introduction/Index.rst index 2f5b985..aeb276f 100644 --- a/Documentation/Introduction/Index.rst +++ b/Documentation/Introduction/Index.rst @@ -1,6 +1,4 @@ -.. include:: ../Includes.txt - - + Configuration/Index .. _introduction: ================ diff --git a/Documentation/Settings.cfg b/Documentation/Settings.cfg index c19821e..ec3a13f 100644 --- a/Documentation/Settings.cfg +++ b/Documentation/Settings.cfg @@ -4,7 +4,7 @@ [general] project = Dropbox FAL Driver -release = 4.3.0 +release = 5.0.0 copyright = by Stefan Froemken [html_theme_options] diff --git a/Documentation/Sitemap.rst b/Documentation/Sitemap.rst new file mode 100644 index 0000000..cd06f7d --- /dev/null +++ b/Documentation/Sitemap.rst @@ -0,0 +1,9 @@ +:template: sitemap.html + +.. include:: /Includes.rst.txt + +======= +Sitemap +======= + +.. The sitemap.html template will insert here the page tree automatically. diff --git a/Documentation/genindex.rst b/Documentation/genindex.rst new file mode 100644 index 0000000..38a804f --- /dev/null +++ b/Documentation/genindex.rst @@ -0,0 +1,7 @@ +.. include:: /Includes.rst.txt + +===== +Index +===== + +.. Sphinx will insert here the general index automatically. diff --git a/composer.json b/composer.json index b6b35e1..0562f8c 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ }, "require": { "php": "^7.4 || ^8.0", - "typo3/cms-core": "^11.5.23 || ^12.4", + "typo3/cms-core": "^11.5.30 || ^12.4.4", "spatie/dropbox-api": "^1.21.1" }, "require-dev": { From 900495d2822fc727104cf7373b80a56b7f5ac79f Mon Sep 17 00:00:00 2001 From: Stefan Froemken Date: Mon, 30 Oct 2023 22:28:55 +0100 Subject: [PATCH 5/5] Catch 400 and 401 responses --- Classes/Service/AutoRefreshingDropboxTokenService.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Classes/Service/AutoRefreshingDropboxTokenService.php b/Classes/Service/AutoRefreshingDropboxTokenService.php index 808798e..266a02d 100644 --- a/Classes/Service/AutoRefreshingDropboxTokenService.php +++ b/Classes/Service/AutoRefreshingDropboxTokenService.php @@ -38,8 +38,12 @@ public function __construct(string $refreshToken, string $appKey) */ public function refresh(ClientException $exception): bool { - // We only catch unauthorized exceptions to refresh the access token - if ($exception->getCode() !== 401) { + // We catch bad request (400) to build up first access token + // We catch unauthorized (401) to refresh the access token + if ( + $exception->getCode() !== 400 + && $exception->getCode() !== 401 + ) { return false; }