From cc3a2c351a2db4c30a2f0dc1bde73ba024e88602 Mon Sep 17 00:00:00 2001 From: Benjamin Gaussorgues Date: Tue, 9 Jan 2024 00:46:26 +0100 Subject: [PATCH] fix(share): use user timezone to parse share expiration date If an user in UTC+1 try to create a share at 00:00, it's day D for him, but D-1 for the server (UTC). This fix aims to apply the correct offset Signed-off-by: Benjamin Gaussorgues --- .../lib/Controller/ShareAPIController.php | 23 +++++-------------- apps/files_sharing/openapi.json | 2 +- apps/files_sharing/tests/ApiTest.php | 5 +++- .../Controller/ShareAPIControllerTest.php | 16 ++++++++++++- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index 98423e7dd1fb7..aa239ae8bb6b3 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -70,6 +70,7 @@ use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\IConfig; +use OCP\IDateTimeZone; use OCP\IGroupManager; use OCP\IL10N; use OCP\IPreview; @@ -124,20 +125,6 @@ class ShareAPIController extends OCSController { /** * Share20OCS constructor. - * - * @param string $appName - * @param IRequest $request - * @param IManager $shareManager - * @param IGroupManager $groupManager - * @param IUserManager $userManager - * @param IRootFolder $rootFolder - * @param IURLGenerator $urlGenerator - * @param string $userId - * @param IL10N $l10n - * @param IConfig $config - * @param IAppManager $appManager - * @param IServerContainer $serverContainer - * @param IUserStatusManager $userStatusManager */ public function __construct( string $appName, @@ -153,7 +140,8 @@ public function __construct( IAppManager $appManager, IServerContainer $serverContainer, IUserStatusManager $userStatusManager, - IPreview $previewManager + IPreview $previewManager, + private IDateTimeZone $dateTimeZone, ) { parent::__construct($appName, $request); @@ -597,7 +585,7 @@ public function deleteShare(string $id): DataResponse { * @param string $publicUpload If public uploading is allowed * @param string $password Password for the share * @param string|null $sendPasswordByTalk Send the password for the share over Talk - * @param string $expireDate Expiry date of the share + * @param string $expireDate Expiry date of the share using user timezone at 00:00. It means date in UTC timezone will be used. * @param string $note Note for the share * @param string $label Label for the share (only used in link and email) * @param string|null $attributes Additional attributes for the share @@ -1706,11 +1694,12 @@ protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool { */ private function parseDate(string $expireDate): \DateTime { try { - $date = new \DateTime(trim($expireDate, "\"")); + $date = new \DateTime(trim($expireDate, "\""), $this->dateTimeZone->getTimeZone()); } catch (\Exception $e) { throw new \Exception('Invalid date. Format must be YYYY-MM-DD'); } + $date->setTimezone(new \DateTimeZone(date_default_timezone_get())); $date->setTime(0, 0, 0); return $date; diff --git a/apps/files_sharing/openapi.json b/apps/files_sharing/openapi.json index abbc3d250a6ea..f28a9860fb7fe 100644 --- a/apps/files_sharing/openapi.json +++ b/apps/files_sharing/openapi.json @@ -1899,7 +1899,7 @@ { "name": "expireDate", "in": "query", - "description": "Expiry date of the share", + "description": "Expiry date of the share using user timezone at 00:00. It means date in UTC timezone will be used.", "schema": { "type": "string", "default": "" diff --git a/apps/files_sharing/tests/ApiTest.php b/apps/files_sharing/tests/ApiTest.php index a50bfe5bee4dd..7e916f621aa27 100644 --- a/apps/files_sharing/tests/ApiTest.php +++ b/apps/files_sharing/tests/ApiTest.php @@ -44,6 +44,7 @@ use OCP\AppFramework\OCS\OCSForbiddenException; use OCP\AppFramework\OCS\OCSNotFoundException; use OCP\IConfig; +use OCP\IDateTimeZone; use OCP\IL10N; use OCP\IPreview; use OCP\IRequest; @@ -122,6 +123,7 @@ private function createOCS($userId) { $serverContainer = $this->createMock(IServerContainer::class); $userStatusManager = $this->createMock(IUserStatusManager::class); $previewManager = $this->createMock(IPreview::class); + $dateTimeZone = $this->createMock(IDateTimeZone::class); return new ShareAPIController( self::APP_NAME, @@ -137,7 +139,8 @@ private function createOCS($userId) { $appManager, $serverContainer, $userStatusManager, - $previewManager + $previewManager, + $dateTimeZone, ); } diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index bfc6a97bd86cf..822212ae86f1c 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -47,6 +47,7 @@ use OCP\Files\NotFoundException; use OCP\Files\Storage; use OCP\IConfig; +use OCP\IDateTimeZone; use OCP\IGroup; use OCP\IGroupManager; use OCP\IL10N; @@ -117,6 +118,9 @@ class ShareAPIControllerTest extends TestCase { /** @var IPreview|\PHPUnit\Framework\MockObject\MockObject */ private $previewManager; + /** @var IDateTimeZone|\PHPUnit\Framework\MockObject\MockObject */ + private $dateTimeZone; + protected function setUp(): void { $this->shareManager = $this->createMock(IManager::class); $this->shareManager @@ -147,6 +151,7 @@ protected function setUp(): void { ->willReturnCallback(function ($fileInfo) { return $fileInfo->getMimeType() === 'mimeWithPreview'; }); + $this->dateTimeZone = $this->createMock(IDateTimeZone::class); $this->ocs = new ShareAPIController( $this->appName, @@ -162,7 +167,8 @@ protected function setUp(): void { $this->appManager, $this->serverContainer, $this->userStatusManager, - $this->previewManager + $this->previewManager, + $this->dateTimeZone, ); } @@ -186,6 +192,7 @@ private function mockFormatShare() { $this->serverContainer, $this->userStatusManager, $this->previewManager, + $this->dateTimeZone, ])->setMethods(['formatShare']) ->getMock(); } @@ -783,6 +790,7 @@ public function testGetShare(\OCP\Share\IShare $share, array $result) { $this->serverContainer, $this->userStatusManager, $this->previewManager, + $this->dateTimeZone, ])->setMethods(['canAccessShare']) ->getMock(); @@ -1407,6 +1415,7 @@ public function testGetShares(array $getSharesParameters, array $shares, array $ $this->serverContainer, $this->userStatusManager, $this->previewManager, + $this->dateTimeZone, ])->setMethods(['formatShare']) ->getMock(); @@ -1746,6 +1755,7 @@ public function testCreateShareUser() { $this->serverContainer, $this->userStatusManager, $this->previewManager, + $this->dateTimeZone, ])->setMethods(['formatShare']) ->getMock(); @@ -1840,6 +1850,7 @@ public function testCreateShareGroup() { $this->serverContainer, $this->userStatusManager, $this->previewManager, + $this->dateTimeZone, ])->setMethods(['formatShare']) ->getMock(); @@ -2249,6 +2260,7 @@ public function testCreateShareRemote() { $this->serverContainer, $this->userStatusManager, $this->previewManager, + $this->dateTimeZone, ])->setMethods(['formatShare']) ->getMock(); @@ -2315,6 +2327,7 @@ public function testCreateShareRemoteGroup() { $this->serverContainer, $this->userStatusManager, $this->previewManager, + $this->dateTimeZone, ])->setMethods(['formatShare']) ->getMock(); @@ -2554,6 +2567,7 @@ public function testCreateReshareOfFederatedMountNoDeletePermissions() { $this->serverContainer, $this->userStatusManager, $this->previewManager, + $this->dateTimeZone, ])->setMethods(['formatShare']) ->getMock();