From f97e1de89fea9483ba538c15418794770683809b Mon Sep 17 00:00:00 2001 From: Arno Date: Thu, 31 Oct 2024 19:45:47 +0400 Subject: [PATCH 1/5] Filesystem adapter for GoogleDrive --- .../Dropbox/DropboxFileSystemAdapter.php | 4 +- .../Adapters/GoogleDrive/GoogleDriveApp.php | 183 ++++++++++++++ .../GoogleDriveFileSystemAdapter.php | 237 ++++++++++++++++++ .../GoogleDrive/TokenServiceInterface.php | 14 ++ .../Adapters/Local/LocalFileSystemAdapter.php | 9 +- src/Libraries/Storage/FileSystem.php | 4 +- .../Storage/FilesystemAdapterInterface.php | 6 +- .../Adapters/Dropbox/DropboxAppTest.php | 3 +- .../Dropbox/DropboxTokenServiceTestCase.php | 28 +++ .../GoogleDrive/GoogleDriveAppTest.php | 119 +++++++++ .../GoogleDriveFileSystemAdapterTest.php | 199 +++++++++++++++ .../GoogleDriveTokenServiceTestCase.php | 28 +++ 12 files changed, 824 insertions(+), 10 deletions(-) create mode 100644 src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php create mode 100644 src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php create mode 100644 src/Libraries/Storage/Adapters/GoogleDrive/TokenServiceInterface.php create mode 100644 tests/unit/Libraries/Storage/Adapters/Dropbox/DropboxTokenServiceTestCase.php create mode 100644 tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php create mode 100644 tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php create mode 100644 tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveTokenServiceTestCase.php diff --git a/src/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapter.php b/src/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapter.php index dbd61b49..f8d46929 100644 --- a/src/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapter.php +++ b/src/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapter.php @@ -59,7 +59,7 @@ public static function getInstance(DropboxApp $dropboxApp): DropboxFileSystemAda /** * @inheritDoc */ - public function makeDirectory(string $dirname): bool + public function makeDirectory(string $dirname, string $parentId = null): bool { try { $this->dropboxApp->rpcRequest(DropboxApp::ENDPOINT_CREATE_FOLDER, $this->dropboxApp->path($dirname)); @@ -97,7 +97,7 @@ public function get(string $filename) /** * @inheritDoc */ - public function put(string $filename, string $content) + public function put(string $filename, string $content, string $parentId = null) { try { $response = $this->dropboxApp->contentRequest(DropboxApp::ENDPOINT_UPLOAD_FILE, diff --git a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php new file mode 100644 index 00000000..cb4a876e --- /dev/null +++ b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php @@ -0,0 +1,183 @@ +appKey = $appKey; + $this->appSecret = $appSecret; + $this->tokenService = $tokenService; + $this->httpClient = $httpClient; + } + + public function getAuthUrl($redirectUrl, $accessType = "offline"): string + { + $params = [ + 'client_id' => $this->appKey, + 'response_type' => 'code', + 'state' => csrf_token(), + 'scope' => self::AUTH_SCOPE, + 'redirect_uri' => $redirectUrl, + 'access_type' => $accessType, + ]; + + return self::AUTH_URL . '?' . http_build_query($params, '', '&'); + } + + public function getAndSaveAccessToken($code, $redirectUrl = '', $byRefresh = false): object + { + $codeKey = $byRefresh ? 'refresh_token' : 'code'; + + $params = [ + $codeKey => $code, + 'grant_type' => $byRefresh ? 'refresh_token' : 'authorization_code', + 'client_id' => $this->appKey, + 'client_secret' => $this->appSecret, + ]; + + if(!$byRefresh){ + $params['redirect_uri'] = $redirectUrl; + } + + $tokenUrl = self::AUTH_TOKEN_URL; + + $response = $this->sendRequest($tokenUrl, $params); + + $this->tokenService->saveTokens($response->access_token, !$byRefresh ? $response->refresh_token : null); + + return $response; + } + + public function sendRequest(string $uri, $data = null, array $headers = [], $method = 'POST') + { + $this->httpClient + ->createRequest($uri) + ->setMethod($method) + ->setData($data) + ->setHeaders($headers) + ->start(); + + + $errors = $this->httpClient->getErrors(); + $responseBody = $this->httpClient->getResponseBody(); + + if ($errors) { + $code = $errors['code']; + + if ($code == 401) { + $prevUrl = $this->httpClient->url(); + $prevData = $this->httpClient->getData(); + $prevHeaders = $this->httpClient->getRequestHeaders(); + + $refreshToken = $this->tokenService->getRefreshToken(); + + $response = $this->getAndSaveAccessToken($refreshToken , '', true); + + $prevHeaders['Authorization'] = 'Bearer ' . $response->access_token; + + $responseBody = $this->sendRequest($prevUrl, $prevData, $prevHeaders); + + } else { + throw new Exception(json_encode($responseBody ?? $errors), E_ERROR); + } + } + + return $responseBody; + } + + /** + * Sends rpc request + * @param string $endpoint + * @param mixed $params + * @return mixed|null + * @throws Exception + */ + public function rpcRequest(string $url, $params = [], $method = 'POST', $contentType = 'application/json') + { + try { + $headers = [ + 'Authorization' => 'Bearer ' . $this->tokenService->getAccessToken(), + 'Content-Type' => $contentType + ]; + return $this->sendRequest($url, $params, $headers, $method); + }catch (Exception $e){ + throw new Exception($e->getMessage(), (int)$e->getCode()); + } + } + + /** + * Gets file information + * @param string $fileId + * @param bool $media + * @param mixed $params + * @return mixed|null + * @throws Exception + */ + public function getFileInfo(string $fileId, $media = false, $params = []){ + $queryParam = $media ? '?alt=media' : '?fields=*'; + return $this->rpcRequest(GoogleDriveApp::FILE_METADATA_URL . '/' . $fileId . $queryParam, $params, 'GET'); + } +} \ No newline at end of file diff --git a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php new file mode 100644 index 00000000..e464043b --- /dev/null +++ b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php @@ -0,0 +1,237 @@ +googleDriveApp = $googleDriveApp; + } + + /** + * Get Instance + * @param GoogleDriveApp $googleDriveApp + * @return GoogleDriveFileSystemAdapter + */ + public static function getInstance(GoogleDriveApp $googleDriveApp): GoogleDriveFileSystemAdapter + { + if (self::$instance === null) { + self::$instance = new self($googleDriveApp); + } + + return self::$instance; + } + + public function makeDirectory($dirname, $parentId = null): bool + { + try{ + $data = [ + 'name' => $dirname, + 'mimeType' => GoogleDriveApp::FOLDER_MIMETYPE, + 'parents' => $parentId ? [$parentId] : ['root'] + ]; + + $this->googleDriveApp->rpcRequest(GoogleDriveApp::FILE_METADATA_URL, $data); + return true; + } catch (Exception $e) { + return false; + } + } + + /** + * @inheritDoc + */ + public function removeDirectory(string $dirname): bool + { + return $this->remove($dirname); + } + + /** + * @inheritDoc + */ + public function get(string $filename) + { + try { + return (string)$this->googleDriveApp->getFileInfo($filename, true); + } catch (Exception $e) { + return false; + } + } + + /** + * @inheritDoc + */ + public function put(string $filename, string $content, string $parentId = null) + { + try { + if($this->isFile($filename)){ + return $this->googleDriveApp->rpcRequest(GoogleDriveApp::FILE_MEDIA_URL . '/' . $filename . '?uploadType=media', $content, 'PATCH', 'application/octet-stream'); + }else{ + $data = [ + 'name' => $filename, + 'parents' => $parentId ? [$parentId] : ['root'] + ]; + + $newFile = $this->googleDriveApp->rpcRequest(GoogleDriveApp::FILE_METADATA_URL, $data); + + return $this->put($newFile->id, $content); + } + } catch (Exception $e) { + return false; + } + } + + /** + * @inheritDoc + */ + public function append(string $filename, string $content) + { + $fileContent = $this->get($filename); + + return $this->put($filename, $fileContent . $content); + } + + /** + * @inheritDoc + */ + public function rename(string $oldName, string $newName): bool + { + try { + $data = [ + 'name' => $newName + ]; + + $this->googleDriveApp->rpcRequest(GoogleDriveApp::FILE_METADATA_URL . '/' . $oldName, $data, 'PATCH'); + return true; + } catch (Exception $e) { + return false; + } + } + + /** + * @inheritDoc + */ + public function copy(string $source, string $dest = 'root'): bool + { + try { + $data = [ + 'parents' => [$dest] + ]; + + $this->googleDriveApp->rpcRequest(GoogleDriveApp::FILE_METADATA_URL . '/' . $source . '/copy', $data); + return true; + } catch (Exception $e) { + return false; + } + } + + /** + * @inheritDoc + */ + public function exists(string $filename): bool + { + return $this->isFile($filename); + } + + /** + * @inheritDoc + */ + public function size(string $filename) + { + try { + $meta = (array)$this->googleDriveApp->getFileInfo($filename); + return $meta['size']; + } catch (Exception $e) { + return false; + } + } + + /** + * @inheritDoc + */ + public function lastModified(string $filename) + { + try { + $meta = (array)$this->googleDriveApp->getFileInfo($filename); + return !empty($meta['modifiedTime']) ? strtotime($meta['modifiedTime']) : false; + } catch (Exception $e) { + return false; + } + + } + + /** + * @inheritDoc + */ + public function remove(string $filename): bool + { + try { + $this->googleDriveApp->rpcRequest(GoogleDriveApp::FILE_METADATA_URL . '/' . $filename, [], 'DELETE'); + return true; + } catch (Exception $e) { + return false; + } + + } + + /** + * @inheritDoc + */ + public function isFile(string $filename): bool + { + try { + $meta = (array)$this->googleDriveApp->getFileInfo($filename); + + return $meta['kind'] === "drive#file" && $meta['mimeType'] != GoogleDriveApp::FOLDER_MIMETYPE; + } catch (Exception $e) { + return false; + } + } + + /** + * @inheritDoc + */ + public function isDirectory(string $dirname): bool + { + try { + $meta = (array)$this->googleDriveApp->getFileInfo($dirname); + + return $meta['kind'] === "drive#file" && $meta['mimeType'] === GoogleDriveApp::FOLDER_MIMETYPE; + } catch (Exception $e) { + return false; + } + } + + /** + * @inheritDoc + */ + public function listDirectory(string $dirname) + { + try { + $params = [ + 'q' => "'$dirname' in parents and trashed = false", + 'fields' => '*' + ]; + $response = (array)$this->googleDriveApp->rpcRequest(GoogleDriveApp::FILE_METADATA_URL . '?' . http_build_query($params), [], 'GET'); + return $response["files"]; + } catch (Exception $e) { + return false; + } + } +} \ No newline at end of file diff --git a/src/Libraries/Storage/Adapters/GoogleDrive/TokenServiceInterface.php b/src/Libraries/Storage/Adapters/GoogleDrive/TokenServiceInterface.php new file mode 100644 index 00000000..b4fe71cf --- /dev/null +++ b/src/Libraries/Storage/Adapters/GoogleDrive/TokenServiceInterface.php @@ -0,0 +1,14 @@ +shouldReceive('getRefreshToken')->andReturnUsing(function () { + $this->currentResponse = (object)$this->tokensGrantResponse; + return 'ref_tok_1234'; + }); + + $tokenServiceMock->shouldReceive('getAccessToken')->andReturn('acc_tok_1234'); + + $tokenServiceMock->shouldReceive('saveTokens')->andReturnUsing(function ($tokens) { + $this->currentResponse = (object)$this->profileDataResponse; + return true; + }); + + return $tokenServiceMock; + } +} \ No newline at end of file diff --git a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php new file mode 100644 index 00000000..e35835f9 --- /dev/null +++ b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php @@ -0,0 +1,119 @@ + "sl.BYEQ1_VadTz6nBU36WPBBVwokc3zWVMXGjcOKxV4Tadms8ZlEPM85aHVFa_k1sfjilCWOnl79RUncPZzJ3GhrqhLGIBFFRCH0rKMa_ZtcqkerJn-f5lu10Ki5PSw4fxYM80V4PL_", + "refresh_token" => "-3S067m3M5kAAAAAAAAAAcQF8zVqFUuhK-PFkFqiOfFTgiazWj5NyU-1EGWIh0ZS" + ]; + + private $fileMetadataResponse = [ + "id" => "file1", + "kind" => "drive#file", + "name" => "myFile", + "mimeType" => "text/plain" + ]; + + private $fileContentResponse = 'Some plain text!'; + private $errorResponse = [ + 'code' => 401, + 'message' => 'Invalid access token', + ]; + + public function setUp(): void + { + parent::setUp(); + + $tokenServiceMock = $this->mockTokenService(); + + $httpClientMock = $this->mockHttpClient(); + + $this->googleDriveApp = new GoogleDriveApp($this->appKey, $this->appSecret, $tokenServiceMock, $httpClientMock); + } + + public function testGoogleDriveGetAuthUrl() + { + $authUrl = $this->googleDriveApp->getAuthUrl($this->redirectUrl); + + $this->assertIsString($authUrl); + + $this->assertStringContainsString('client_id', $authUrl); + + $this->assertStringContainsString('access_type', $authUrl); + } + + public function testGoogleDriveFetchTokens() + { + $this->currentResponse = (object)$this->tokensGrantResponse; + + $response = $this->googleDriveApp->getAndSaveAccessToken($this->authCode, $this->redirectUrl); + + $this->assertIsObject($response); + + $this->assertTrue(property_exists($response, 'access_token')); + + $this->assertTrue(property_exists($response, 'refresh_token')); + } + + public function testGoogleDriveRpcRequest() + { + $this->currentResponse = (object)$this->fileMetadataResponse; + + $response = $this->googleDriveApp->rpcRequest(GoogleDriveApp::FILE_METADATA_URL . '/' . $this->fileMetadataResponse['id']); + + $this->assertIsObject($response); + + $this->assertTrue(property_exists($response, 'id')); + + $this->assertTrue(property_exists($response, 'kind')); + + $this->assertTrue(property_exists($response, 'name')); + + $this->assertTrue(property_exists($response, 'mimeType')); + } + + public function testGoogleDriveGetFileInfo() + { + $this->currentResponse = $this->fileContentResponse; + + $response = $this->googleDriveApp->getFileInfo($this->fileMetadataResponse['id'], true); + + $this->assertIsString($response); + + $this->assertEquals('Some plain text!', $response); + } + + public function testGoogleDriveRequestWithAccessTokenExpired() + { + $this->currentErrors = ["code" => 401]; + + $this->currentResponse = (object)$this->errorResponse; + + $response = $this->googleDriveApp->sendRequest(GoogleDriveApp::FILE_METADATA_URL . '/' . $this->fileMetadataResponse['id']); + + $this->assertIsObject($response); + + $this->assertEquals((object)$this->fileMetadataResponse, $response); + } + +} diff --git a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php new file mode 100644 index 00000000..b291e569 --- /dev/null +++ b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php @@ -0,0 +1,199 @@ +makePartial(); + + $googleDrive->shouldReceive('rpcRequest')->andReturnUsing(function ($endpoint, $params) { + if(str_contains($endpoint, '?alt=media')){ + return self::$response[array_key_last(self::$response)]; + } + self::$response = array_merge(self::$response, (array)$params); + return (object)self::$response; + }); + + $this->fs = GoogleDriveFileSystemAdapter::getInstance($googleDrive); + } + + public function tearDown(): void + { + self::$response = []; + } + + public function testGoogleDriveMakeCheckRemoveDirectory() + { + $this->assertFalse($this->fs->isDirectory($this->dirname)); + + self::$response['kind'] = 'drive#file'; + + $this->fs->makeDirectory($this->dirname); + + $this->assertTrue($this->fs->isDirectory($this->dirname)); + + $this->fs->removeDirectory($this->dirname); + + self::$response = []; + + $this->assertFalse($this->fs->isDirectory($this->dirname)); + } + + public function testGoogleDriveCreateGetCheckRemoveFile() + { + $this->assertFalse($this->fs->isFile($this->filename)); + + self::$response['kind'] = 'drive#file'; + self::$response['mimeType'] = 'text/plain'; + + $this->fs->put($this->filename, $this->content); + + $this->assertTrue($this->fs->isFile($this->filename)); + + $this->assertTrue($this->fs->exists($this->filename)); + + $this->assertEquals($this->content, $this->fs->get($this->filename)); + + $this->fs->remove($this->filename); + + self::$response = []; + + $this->assertFalse($this->fs->exists($this->filename)); + } + + public function testGoogleDriveFileAppend() + { + self::$response['kind'] = 'drive#file'; + self::$response['mimeType'] = 'text/plain'; + + $this->fs->put($this->filename, $this->content); + + $this->assertTrue($this->fs->exists($this->filename)); + + $moreContent = 'The sun is shining'; + + $this->fs->append($this->filename, $moreContent); + + $this->assertEquals($this->content . $moreContent, $this->fs->get($this->filename)); + } + + public function testGoogleDriveFileRename() + { + $this->fs->put($this->filename, $this->content); + + $newFilename = 'new_name.txt'; + + $this->assertFalse($this->fs->exists($newFilename)); + + self::$response['kind'] = 'drive#file'; + self::$response['mimeType'] = 'text/plain'; + + $this->fs->rename($this->filename, $newFilename); + + $this->assertTrue($this->fs->exists($newFilename)); + + $this->fs->remove($newFilename); + } + + public function testGoogleDriveFileCopy() + { + $dirName = 'testing'; + + $this->fs->makeDirectory($dirName); + + $this->fs->put($this->filename, $this->content); + + $this->assertFalse($this->fs->exists($dirName . '/' . $this->filename)); + + self::$response['kind'] = 'drive#file'; + self::$response['mimeType'] = 'text/plain'; + + $this->fs->copy($this->filename, $dirName . '/' . $this->filename); + + $this->assertTrue($this->fs->exists($dirName . '/' . $this->filename)); + + $this->fs->remove($dirName . '/' . $this->filename); + + $this->fs->removeDirectory($dirName); + } + + public function testGoogleDriveFileSize() + { + $text = 'some bytes'; + + $this->fs->put($this->filename, $text); + + self::$response['size'] = strlen($text); + + $this->assertEquals(10, $this->fs->size($this->filename)); + } + + public function testGoogleDriveFileLastModified() + { + $modified = '2023-02-12T15:50:38Z'; + + $this->fs->put($this->filename, $this->content); + + self::$response['modifiedTime'] = $modified; + + $this->assertIsInt($this->fs->lastModified($this->filename)); + + $this->assertEquals(strtotime($modified), $this->fs->lastModified($this->filename)); + } + + public function testGoogleDriveListDirectory() + { + self::$response['files'] = [ + [ + "kind" => "drive#file", + "mimeType" => 'application/vnd.google-apps.folder', + "name" => "empty", + "id" => "SziOaBdnr3oAAAAAAAAAWQ", + ], + [ + "kind" => "drive#file", + "mimeType" => 'image/png', + "name" => "logo.png", + "id" => "SziOaBdnr3oAAAAAAAAAVQ", + "modifiedTime" => "2023-02-24T15:34:44Z", + "size" => 3455, + ], + [ + "kind" => "drive#file", + "mimeType" => 'image/jpeg', + "name" => "Image 19.jpg", + "id" => "SziOaBdnr3oAAAAAAAAAVw", + "modifiedTime" => "2023-03-01T17:12:58Z", + "size" => 2083432, + ] + ]; + + $entries = $this->fs->listDirectory('test'); + + $this->assertIsArray($entries); + + $this->assertIsArray(current($entries)); + + self::$response = []; + + $this->assertFalse($this->fs->listDirectory('test')); + + } + +} + diff --git a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveTokenServiceTestCase.php b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveTokenServiceTestCase.php new file mode 100644 index 00000000..8710725c --- /dev/null +++ b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveTokenServiceTestCase.php @@ -0,0 +1,28 @@ +shouldReceive('getRefreshToken')->andReturnUsing(function () { + $this->currentResponse = (object)$this->tokensGrantResponse; + return 'ref_tok_1234'; + }); + + $tokenServiceMock->shouldReceive('getAccessToken')->andReturn('acc_tok_1234'); + + $tokenServiceMock->shouldReceive('saveTokens')->andReturnUsing(function ($tokens) { + $this->currentResponse = (object)$this->fileMetadataResponse; + return true; + }); + + return $tokenServiceMock; + } +} \ No newline at end of file From 4f755e6fefb828c6cebc3878ad498b6203dcd6ff Mon Sep 17 00:00:00 2001 From: Arno Date: Fri, 1 Nov 2024 15:09:01 +0400 Subject: [PATCH 2/5] Code cleanup and minor fixes --- .../Dropbox/DropboxFileSystemAdapter.php | 4 ++-- .../Adapters/GoogleDrive/GoogleDriveApp.php | 20 +++++++++++++++---- .../GoogleDriveFileSystemAdapter.php | 8 ++++---- .../Adapters/Local/LocalFileSystemAdapter.php | 4 ++-- src/Libraries/Storage/FileSystem.php | 4 ++-- .../Storage/FilesystemAdapterInterface.php | 4 ++-- .../GoogleDrive/GoogleDriveAppTest.php | 6 +++--- .../GoogleDriveFileSystemAdapterTest.php | 16 +++++++-------- 8 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapter.php b/src/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapter.php index f8d46929..0bbdc9f4 100644 --- a/src/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapter.php +++ b/src/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapter.php @@ -59,7 +59,7 @@ public static function getInstance(DropboxApp $dropboxApp): DropboxFileSystemAda /** * @inheritDoc */ - public function makeDirectory(string $dirname, string $parentId = null): bool + public function makeDirectory(string $dirname, ?string $parentId = null): bool { try { $this->dropboxApp->rpcRequest(DropboxApp::ENDPOINT_CREATE_FOLDER, $this->dropboxApp->path($dirname)); @@ -97,7 +97,7 @@ public function get(string $filename) /** * @inheritDoc */ - public function put(string $filename, string $content, string $parentId = null) + public function put(string $filename, string $content, ?string $parentId = null) { try { $response = $this->dropboxApp->contentRequest(DropboxApp::ENDPOINT_UPLOAD_FILE, diff --git a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php index cb4a876e..97dd212f 100644 --- a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php +++ b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php @@ -38,6 +38,16 @@ class GoogleDriveApp */ const FOLDER_MIMETYPE = 'application/vnd.google-apps.folder'; + /** + * Kind/Type of drive file + */ + const DRIVE_FILE_KIND = 'drive#file'; + + /** + * Error code for invalid token + */ + const INVALID_TOKEN_ERROR_CODE = 401; + /** * @var HttpClient */ @@ -87,7 +97,7 @@ public function getAuthUrl($redirectUrl, $accessType = "offline"): string return self::AUTH_URL . '?' . http_build_query($params, '', '&'); } - public function getAndSaveAccessToken($code, $redirectUrl = '', $byRefresh = false): object + public function fetchTokens($code, $redirectUrl = '', $byRefresh = false): object { $codeKey = $byRefresh ? 'refresh_token' : 'code'; @@ -127,14 +137,14 @@ public function sendRequest(string $uri, $data = null, array $headers = [], $met if ($errors) { $code = $errors['code']; - if ($code == 401) { + if ($code == self::INVALID_TOKEN_ERROR_CODE) { $prevUrl = $this->httpClient->url(); $prevData = $this->httpClient->getData(); $prevHeaders = $this->httpClient->getRequestHeaders(); $refreshToken = $this->tokenService->getRefreshToken(); - $response = $this->getAndSaveAccessToken($refreshToken , '', true); + $response = $this->fetchTokens($refreshToken , '', true); $prevHeaders['Authorization'] = 'Bearer ' . $response->access_token; @@ -150,8 +160,10 @@ public function sendRequest(string $uri, $data = null, array $headers = [], $met /** * Sends rpc request - * @param string $endpoint + * @param string $url * @param mixed $params + * @param string $method + * @param string $contentType * @return mixed|null * @throws Exception */ diff --git a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php index e464043b..02edbfba 100644 --- a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php +++ b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php @@ -38,7 +38,7 @@ public static function getInstance(GoogleDriveApp $googleDriveApp): GoogleDriveF return self::$instance; } - public function makeDirectory($dirname, $parentId = null): bool + public function makeDirectory(string $dirname, ?string $parentId = null): bool { try{ $data = [ @@ -77,7 +77,7 @@ public function get(string $filename) /** * @inheritDoc */ - public function put(string $filename, string $content, string $parentId = null) + public function put(string $filename, string $content, ?string $parentId = null) { try { if($this->isFile($filename)){ @@ -198,7 +198,7 @@ public function isFile(string $filename): bool try { $meta = (array)$this->googleDriveApp->getFileInfo($filename); - return $meta['kind'] === "drive#file" && $meta['mimeType'] != GoogleDriveApp::FOLDER_MIMETYPE; + return $meta['kind'] === GoogleDriveApp::DRIVE_FILE_KIND && $meta['mimeType'] != GoogleDriveApp::FOLDER_MIMETYPE; } catch (Exception $e) { return false; } @@ -212,7 +212,7 @@ public function isDirectory(string $dirname): bool try { $meta = (array)$this->googleDriveApp->getFileInfo($dirname); - return $meta['kind'] === "drive#file" && $meta['mimeType'] === GoogleDriveApp::FOLDER_MIMETYPE; + return $meta['kind'] === GoogleDriveApp::DRIVE_FILE_KIND && $meta['mimeType'] === GoogleDriveApp::FOLDER_MIMETYPE; } catch (Exception $e) { return false; } diff --git a/src/Libraries/Storage/Adapters/Local/LocalFileSystemAdapter.php b/src/Libraries/Storage/Adapters/Local/LocalFileSystemAdapter.php index fd35b432..5e93ca2a 100644 --- a/src/Libraries/Storage/Adapters/Local/LocalFileSystemAdapter.php +++ b/src/Libraries/Storage/Adapters/Local/LocalFileSystemAdapter.php @@ -47,7 +47,7 @@ public static function getInstance(): ?LocalFileSystemAdapter * @param string|null $parentId * @inheritDoc */ - public function makeDirectory(string $dirname, string $parentId = null): bool + public function makeDirectory(string $dirname, ?string $parentId = null): bool { return mkdir($dirname); } @@ -96,7 +96,7 @@ public function getJson(string $filename) * @param string|null $parentId * @inheritDoc */ - public function put(string $filename, string $content, string $parentId = null) + public function put(string $filename, string $content, ?string $parentId = null) { return file_put_contents($filename, $content, LOCK_EX); } diff --git a/src/Libraries/Storage/FileSystem.php b/src/Libraries/Storage/FileSystem.php index 85ef731c..55c3e622 100644 --- a/src/Libraries/Storage/FileSystem.php +++ b/src/Libraries/Storage/FileSystem.php @@ -21,10 +21,10 @@ /** * Class FileSystem * @package Quantum\Libraries\Storage - * @method bool makeDirectory(string $dirname, string $parentId = null) + * @method bool makeDirectory(string $dirname, ?string $parentId = null) * @method bool removeDirectory(string $dirname) * @method string|false get(string $filename) - * @method int|false put(string $filename, string $content, string $parentId = null) + * @method int|false put(string $filename, string $content, ?string $parentId = null) * @method int|false append(string $filename, string $content) * @method bool rename(string $oldName, string $newName) * @method bool copy(string $source, string $dest) diff --git a/src/Libraries/Storage/FilesystemAdapterInterface.php b/src/Libraries/Storage/FilesystemAdapterInterface.php index 23701549..aa153a3d 100644 --- a/src/Libraries/Storage/FilesystemAdapterInterface.php +++ b/src/Libraries/Storage/FilesystemAdapterInterface.php @@ -26,7 +26,7 @@ interface FilesystemAdapterInterface * @param string|null $parentId * @return bool */ - public function makeDirectory(string $dirname, string $parentId = null): bool; + public function makeDirectory(string $dirname, ?string $parentId = null): bool; /** * Removes the directory @@ -49,7 +49,7 @@ public function get(string $filename); * @param string|null $parentId * @return int|false */ - public function put(string $filename, string $content, string $parentId = null); + public function put(string $filename, string $content, ?string $parentId = null); /** * Appends the content at the end of the file diff --git a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php index e35835f9..27ac0dc0 100644 --- a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php +++ b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php @@ -29,14 +29,14 @@ class GoogleDriveAppTest extends AppTestCase private $fileMetadataResponse = [ "id" => "file1", - "kind" => "drive#file", + "kind" => GoogleDriveApp::DRIVE_FILE_KIND, "name" => "myFile", "mimeType" => "text/plain" ]; private $fileContentResponse = 'Some plain text!'; private $errorResponse = [ - 'code' => 401, + 'code' => GoogleDriveApp::INVALID_TOKEN_ERROR_CODE, 'message' => 'Invalid access token', ]; @@ -66,7 +66,7 @@ public function testGoogleDriveFetchTokens() { $this->currentResponse = (object)$this->tokensGrantResponse; - $response = $this->googleDriveApp->getAndSaveAccessToken($this->authCode, $this->redirectUrl); + $response = $this->googleDriveApp->fetchTokens($this->authCode, $this->redirectUrl); $this->assertIsObject($response); diff --git a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php index b291e569..28ab71f0 100644 --- a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php +++ b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php @@ -41,7 +41,7 @@ public function testGoogleDriveMakeCheckRemoveDirectory() { $this->assertFalse($this->fs->isDirectory($this->dirname)); - self::$response['kind'] = 'drive#file'; + self::$response['kind'] = GoogleDriveApp::DRIVE_FILE_KIND; $this->fs->makeDirectory($this->dirname); @@ -58,7 +58,7 @@ public function testGoogleDriveCreateGetCheckRemoveFile() { $this->assertFalse($this->fs->isFile($this->filename)); - self::$response['kind'] = 'drive#file'; + self::$response['kind'] = GoogleDriveApp::DRIVE_FILE_KIND; self::$response['mimeType'] = 'text/plain'; $this->fs->put($this->filename, $this->content); @@ -78,7 +78,7 @@ public function testGoogleDriveCreateGetCheckRemoveFile() public function testGoogleDriveFileAppend() { - self::$response['kind'] = 'drive#file'; + self::$response['kind'] = GoogleDriveApp::DRIVE_FILE_KIND; self::$response['mimeType'] = 'text/plain'; $this->fs->put($this->filename, $this->content); @@ -100,7 +100,7 @@ public function testGoogleDriveFileRename() $this->assertFalse($this->fs->exists($newFilename)); - self::$response['kind'] = 'drive#file'; + self::$response['kind'] = GoogleDriveApp::DRIVE_FILE_KIND; self::$response['mimeType'] = 'text/plain'; $this->fs->rename($this->filename, $newFilename); @@ -120,7 +120,7 @@ public function testGoogleDriveFileCopy() $this->assertFalse($this->fs->exists($dirName . '/' . $this->filename)); - self::$response['kind'] = 'drive#file'; + self::$response['kind'] = GoogleDriveApp::DRIVE_FILE_KIND; self::$response['mimeType'] = 'text/plain'; $this->fs->copy($this->filename, $dirName . '/' . $this->filename); @@ -160,13 +160,13 @@ public function testGoogleDriveListDirectory() { self::$response['files'] = [ [ - "kind" => "drive#file", + "kind" => GoogleDriveApp::DRIVE_FILE_KIND, "mimeType" => 'application/vnd.google-apps.folder', "name" => "empty", "id" => "SziOaBdnr3oAAAAAAAAAWQ", ], [ - "kind" => "drive#file", + "kind" => GoogleDriveApp::DRIVE_FILE_KIND, "mimeType" => 'image/png', "name" => "logo.png", "id" => "SziOaBdnr3oAAAAAAAAAVQ", @@ -174,7 +174,7 @@ public function testGoogleDriveListDirectory() "size" => 3455, ], [ - "kind" => "drive#file", + "kind" => GoogleDriveApp::DRIVE_FILE_KIND, "mimeType" => 'image/jpeg', "name" => "Image 19.jpg", "id" => "SziOaBdnr3oAAAAAAAAAVw", From 7d543079d631205a4b173c7f8a722baf4d9324f2 Mon Sep 17 00:00:00 2001 From: Arno Date: Fri, 1 Nov 2024 15:18:28 +0400 Subject: [PATCH 3/5] Adding question mark from fetchTokens() response type since it can also be null --- src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php index 97dd212f..5a338978 100644 --- a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php +++ b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php @@ -97,7 +97,7 @@ public function getAuthUrl($redirectUrl, $accessType = "offline"): string return self::AUTH_URL . '?' . http_build_query($params, '', '&'); } - public function fetchTokens($code, $redirectUrl = '', $byRefresh = false): object + public function fetchTokens($code, $redirectUrl = '', $byRefresh = false): ?object { $codeKey = $byRefresh ? 'refresh_token' : 'code'; From e4f578c4963a4a52f71cd5378ff23214cc86a301 Mon Sep 17 00:00:00 2001 From: Arno Date: Fri, 1 Nov 2024 17:48:51 +0400 Subject: [PATCH 4/5] Adding variable types and doc blocks --- .../Storage/Adapters/Dropbox/DropboxApp.php | 11 ++-- .../Adapters/GoogleDrive/GoogleDriveApp.php | 56 +++++++++++++------ .../GoogleDriveFileSystemAdapter.php | 6 ++ .../Adapters/Dropbox/DropboxAppTest.php | 27 +++++++++ .../Dropbox/DropboxFileSystemAdapterTest.php | 20 +++++++ .../GoogleDrive/GoogleDriveAppTest.php | 30 +++++++++- .../GoogleDriveFileSystemAdapterTest.php | 49 +++++++++++----- .../Local/LocalFileSystemAdapterTest.php | 15 +++++ 8 files changed, 179 insertions(+), 35 deletions(-) diff --git a/src/Libraries/Storage/Adapters/Dropbox/DropboxApp.php b/src/Libraries/Storage/Adapters/Dropbox/DropboxApp.php index 5ce6292a..81810d49 100644 --- a/src/Libraries/Storage/Adapters/Dropbox/DropboxApp.php +++ b/src/Libraries/Storage/Adapters/Dropbox/DropboxApp.php @@ -96,17 +96,17 @@ class DropboxApp /** * @var string */ - private $appKey = null; + private $appKey; /** * @var string */ - private $appSecret = null; + private $appSecret; /** * @var TokenServiceInterface */ - private $tokenService = null; + private $tokenService; /** * DropboxApp constructor @@ -125,8 +125,11 @@ public function __construct(string $appKey, string $appSecret, TokenServiceInter /** * Gets the auth URL - * @throws CryptorException + * @param string $redirectUrl + * @param string $tokenAccessType + * @return string * @throws AppException + * @throws CryptorException * @throws DatabaseException */ public function getAuthUrl(string $redirectUrl, string $tokenAccessType = 'offline'): string diff --git a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php index 5a338978..02eb125c 100644 --- a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php +++ b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php @@ -2,8 +2,10 @@ namespace Quantum\Libraries\Storage\Adapters\GoogleDrive; +use Quantum\Exceptions\AppException; +use Quantum\Exceptions\CryptorException; +use Quantum\Exceptions\DatabaseException; use Quantum\Libraries\Curl\HttpClient; -use Quantum\Http\Response; use Exception; class GoogleDriveApp @@ -56,17 +58,17 @@ class GoogleDriveApp /** * @var string */ - private $appKey = null; + private $appKey; /** * @var string */ - private $appSecret = null; + private $appSecret; /** * @var TokenServiceInterface */ - private $tokenService = null; + private $tokenService; /** * GoogleDriveApp constructor @@ -83,7 +85,16 @@ public function __construct(string $appKey, string $appSecret, TokenServiceInter $this->httpClient = $httpClient; } - public function getAuthUrl($redirectUrl, $accessType = "offline"): string + /** + * Gets Auth URL + * @param string $redirectUrl + * @param string $accessType + * @return object|null + * @throws AppException + * @throws CryptorException + * @throws DatabaseException + */ + public function getAuthUrl(string $redirectUrl, string $accessType = "offline"): string { $params = [ 'client_id' => $this->appKey, @@ -97,7 +108,15 @@ public function getAuthUrl($redirectUrl, $accessType = "offline"): string return self::AUTH_URL . '?' . http_build_query($params, '', '&'); } - public function fetchTokens($code, $redirectUrl = '', $byRefresh = false): ?object + /** + * Fetch tokens + * @param string $code + * @param string $redirectUrl + * @param bool $byRefresh + * @return object|null + * @throws Exception + */ + public function fetchTokens(string $code, string $redirectUrl = '', bool $byRefresh = false): ?object { $codeKey = $byRefresh ? 'refresh_token' : 'code'; @@ -112,16 +131,23 @@ public function fetchTokens($code, $redirectUrl = '', $byRefresh = false): ?obje $params['redirect_uri'] = $redirectUrl; } - $tokenUrl = self::AUTH_TOKEN_URL; - - $response = $this->sendRequest($tokenUrl, $params); + $response = $this->sendRequest(self::AUTH_TOKEN_URL, $params); $this->tokenService->saveTokens($response->access_token, !$byRefresh ? $response->refresh_token : null); return $response; } - public function sendRequest(string $uri, $data = null, array $headers = [], $method = 'POST') + /** + * Sends rpc request + * @param string $uri + * @param null $data + * @param array $headers + * @param string $method + * @return mixed|null + * @throws Exception + */ + public function sendRequest(string $uri, $data = null, array $headers = [], string $method = 'POST') { $this->httpClient ->createRequest($uri) @@ -130,11 +156,9 @@ public function sendRequest(string $uri, $data = null, array $headers = [], $met ->setHeaders($headers) ->start(); - - $errors = $this->httpClient->getErrors(); $responseBody = $this->httpClient->getResponseBody(); - if ($errors) { + if ($errors = $this->httpClient->getErrors()) { $code = $errors['code']; if ($code == self::INVALID_TOKEN_ERROR_CODE) { @@ -167,7 +191,7 @@ public function sendRequest(string $uri, $data = null, array $headers = [], $met * @return mixed|null * @throws Exception */ - public function rpcRequest(string $url, $params = [], $method = 'POST', $contentType = 'application/json') + public function rpcRequest(string $url, $params = [], string $method = 'POST', string $contentType = 'application/json') { try { $headers = [ @@ -184,11 +208,11 @@ public function rpcRequest(string $url, $params = [], $method = 'POST', $content * Gets file information * @param string $fileId * @param bool $media - * @param mixed $params + * @param array $params * @return mixed|null * @throws Exception */ - public function getFileInfo(string $fileId, $media = false, $params = []){ + public function getFileInfo(string $fileId, bool $media = false, array $params = []){ $queryParam = $media ? '?alt=media' : '?fields=*'; return $this->rpcRequest(GoogleDriveApp::FILE_METADATA_URL . '/' . $fileId . $queryParam, $params, 'GET'); } diff --git a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php index 02edbfba..6d82efb9 100644 --- a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php +++ b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapter.php @@ -13,6 +13,9 @@ class GoogleDriveFileSystemAdapter implements FilesystemAdapterInterface */ private static $instance = null; + /** + * @var GoogleDriveApp + */ private $googleDriveApp; /** @@ -38,6 +41,9 @@ public static function getInstance(GoogleDriveApp $googleDriveApp): GoogleDriveF return self::$instance; } + /** + * @inheritDoc + */ public function makeDirectory(string $dirname, ?string $parentId = null): bool { try{ diff --git a/tests/unit/Libraries/Storage/Adapters/Dropbox/DropboxAppTest.php b/tests/unit/Libraries/Storage/Adapters/Dropbox/DropboxAppTest.php index 4d6b0a14..be7a0e72 100644 --- a/tests/unit/Libraries/Storage/Adapters/Dropbox/DropboxAppTest.php +++ b/tests/unit/Libraries/Storage/Adapters/Dropbox/DropboxAppTest.php @@ -12,16 +12,34 @@ class DropboxAppTest extends AppTestCase use DropboxTokenServiceTestCase; use HttpClientTestCase; + /** + * @var DropboxApp + */ private $dropboxApp; + /** + * @var string + */ private $appKey = 'x0hwm8wy63rrynm'; + /** + * @var string + */ private $appSecret = 'xxx123yyy'; + /** + * @var string + */ private $authCode = 'd4k29ovC7-UAAAAAAAA3Q45go2mLgjMhJSeJNBOo-EA'; + /** + * @var string + */ private $redirectUrl = 'http://localhost/confirm'; + /** + * @var array + */ private $tokensGrantResponse = [ "access_token" => "sl.BYEQ1_VadTz6nBU36WPBBVwokc3zWVMXGjcOKxV4Tadms8ZlEPM85aHVFa_k1sfjilCWOnl79RUncPZzJ3GhrqhLGIBFFRCH0rKMa_ZtcqkerJn-f5lu10Ki5PSw4fxYM80V4PL_", "token_type" => "bearer", @@ -32,6 +50,9 @@ class DropboxAppTest extends AppTestCase "account_id" => "dbid:AAC9tDKbzTQlyNms0ZcB_iH3wLv7yNn-iyE" ]; + /** + * @var array + */ private $profileDataResponse = [ "account_id" => "dbid:AAH4f99T0taONIb-OurWxbNQ6ywGRopQngc", "disabled" => false, @@ -48,6 +69,9 @@ class DropboxAppTest extends AppTestCase "profile_photo_url" => "https://dl-web.dropbox.com/account_photo/get/69330102&size=128x128" ]; + /** + * @var array + */ private $errorResponse = [ "error" => [ ".tag" => "no_account" @@ -55,6 +79,9 @@ class DropboxAppTest extends AppTestCase "error_summary" => "no_account/..." ]; + /** + * @var string + */ private $fileContentResponse = 'Some plain text!'; public function setUp(): void diff --git a/tests/unit/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapterTest.php b/tests/unit/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapterTest.php index 3eb2fb47..02457446 100644 --- a/tests/unit/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapterTest.php +++ b/tests/unit/Libraries/Storage/Adapters/Dropbox/DropboxFileSystemAdapterTest.php @@ -9,10 +9,30 @@ class DropboxFileSystemAdapterTest extends AppTestCase { + + /** + * @var DropboxFileSystemAdapter + */ private $fs; + + /** + * @var string + */ private $dirname = 'common'; + + /** + * @var string + */ private $filename = 'sample.txt'; + + /** + * @var string + */ private $content = 'This file was created via dropbox api'; + + /** + * @var array + */ private static $response = []; public function setUp(): void diff --git a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php index 27ac0dc0..63fde36d 100644 --- a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php +++ b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveAppTest.php @@ -12,21 +12,42 @@ class GoogleDriveAppTest extends AppTestCase use GoogleDriveTokenServiceTestCase; use HttpClientTestCase; + /** + * @var GoogleDriveApp + */ private $googleDriveApp; - private $appKey = 'x0hwm8wy63rrynm'; + /** + * @var string + */ + private $appKey = 'x0hwm8wy63rrynm'; + /** + * @var string + */ private $appSecret = 'xxx123yyy'; + /** + * @var string + */ private $authCode = 'd4k29ovC7-UAAAAAAAA3Q45go2mLgjMhJSeJNBOo-EA'; + /** + * @var string + */ private $redirectUrl = 'http://localhost/confirm'; + /** + * @var array + */ private $tokensGrantResponse = [ "access_token" => "sl.BYEQ1_VadTz6nBU36WPBBVwokc3zWVMXGjcOKxV4Tadms8ZlEPM85aHVFa_k1sfjilCWOnl79RUncPZzJ3GhrqhLGIBFFRCH0rKMa_ZtcqkerJn-f5lu10Ki5PSw4fxYM80V4PL_", "refresh_token" => "-3S067m3M5kAAAAAAAAAAcQF8zVqFUuhK-PFkFqiOfFTgiazWj5NyU-1EGWIh0ZS" ]; + /** + * @var array + */ private $fileMetadataResponse = [ "id" => "file1", "kind" => GoogleDriveApp::DRIVE_FILE_KIND, @@ -34,7 +55,14 @@ class GoogleDriveAppTest extends AppTestCase "mimeType" => "text/plain" ]; + /** + * @var string + */ private $fileContentResponse = 'Some plain text!'; + + /** + * @var string + */ private $errorResponse = [ 'code' => GoogleDriveApp::INVALID_TOKEN_ERROR_CODE, 'message' => 'Invalid access token', diff --git a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php index 28ab71f0..0c6f905f 100644 --- a/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php +++ b/tests/unit/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveFileSystemAdapterTest.php @@ -9,10 +9,35 @@ class GoogleDriveFileSystemAdapterTest extends AppTestCase { + + /** + * @var GoogleDriveFileSystemAdapter + */ private $fs; + + /** + * @var string + */ private $dirname = 'common'; + + /** + * @var string + */ private $filename = 'sample.txt'; + + /** + * @var string + */ + private $newFilename = 'new_name.txt'; + + /** + * @var string + */ private $content = 'This file was created via dropbox api'; + + /** + * @var array + */ private static $response = []; public function setUp(): void @@ -96,40 +121,36 @@ public function testGoogleDriveFileRename() { $this->fs->put($this->filename, $this->content); - $newFilename = 'new_name.txt'; - - $this->assertFalse($this->fs->exists($newFilename)); + $this->assertFalse($this->fs->exists($this->newFilename)); self::$response['kind'] = GoogleDriveApp::DRIVE_FILE_KIND; self::$response['mimeType'] = 'text/plain'; - $this->fs->rename($this->filename, $newFilename); + $this->fs->rename($this->filename, $this->newFilename); - $this->assertTrue($this->fs->exists($newFilename)); + $this->assertTrue($this->fs->exists($this->newFilename)); - $this->fs->remove($newFilename); + $this->fs->remove($this->newFilename); } public function testGoogleDriveFileCopy() { - $dirName = 'testing'; - - $this->fs->makeDirectory($dirName); + $this->fs->makeDirectory($this->dirname); $this->fs->put($this->filename, $this->content); - $this->assertFalse($this->fs->exists($dirName . '/' . $this->filename)); + $this->assertFalse($this->fs->exists($this->dirname . '/' . $this->filename)); self::$response['kind'] = GoogleDriveApp::DRIVE_FILE_KIND; self::$response['mimeType'] = 'text/plain'; - $this->fs->copy($this->filename, $dirName . '/' . $this->filename); + $this->fs->copy($this->filename, $this->dirname . '/' . $this->filename); - $this->assertTrue($this->fs->exists($dirName . '/' . $this->filename)); + $this->assertTrue($this->fs->exists($this->dirname . '/' . $this->filename)); - $this->fs->remove($dirName . '/' . $this->filename); + $this->fs->remove($this->dirname . '/' . $this->filename); - $this->fs->removeDirectory($dirName); + $this->fs->removeDirectory($this->dirname); } public function testGoogleDriveFileSize() diff --git a/tests/unit/Libraries/Storage/Adapters/Local/LocalFileSystemAdapterTest.php b/tests/unit/Libraries/Storage/Adapters/Local/LocalFileSystemAdapterTest.php index 367f07a6..00aa3ce3 100644 --- a/tests/unit/Libraries/Storage/Adapters/Local/LocalFileSystemAdapterTest.php +++ b/tests/unit/Libraries/Storage/Adapters/Local/LocalFileSystemAdapterTest.php @@ -8,9 +8,24 @@ class LocalFileSystemAdapterTest extends AppTestCase { + /** + * @var LocalFileSystemAdapter + */ private $fs; + + /** + * @var string + */ private $dirname; + + /** + * @var string + */ private $filename; + + /** + * @var string + */ private $content = 'Hello world'; public function setUp(): void From b6c7dfdfd986559943d997557a37d39a1ed188ed Mon Sep 17 00:00:00 2001 From: Arno Date: Fri, 1 Nov 2024 20:07:50 +0400 Subject: [PATCH 5/5] Correcting google drive app code to corresponds to Dropbox app principles --- .../Adapters/GoogleDrive/GoogleDriveApp.php | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php index 02eb125c..57a84486 100644 --- a/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php +++ b/src/Libraries/Storage/Adapters/GoogleDrive/GoogleDriveApp.php @@ -89,7 +89,7 @@ public function __construct(string $appKey, string $appSecret, TokenServiceInter * Gets Auth URL * @param string $redirectUrl * @param string $accessType - * @return object|null + * @return string * @throws AppException * @throws CryptorException * @throws DatabaseException @@ -116,32 +116,50 @@ public function getAuthUrl(string $redirectUrl, string $accessType = "offline"): * @return object|null * @throws Exception */ - public function fetchTokens(string $code, string $redirectUrl = '', bool $byRefresh = false): ?object + public function fetchTokens(string $code, string $redirectUrl = ''): ?object { - $codeKey = $byRefresh ? 'refresh_token' : 'code'; $params = [ - $codeKey => $code, - 'grant_type' => $byRefresh ? 'refresh_token' : 'authorization_code', + 'code' => $code, + 'grant_type' => 'authorization_code', 'client_id' => $this->appKey, 'client_secret' => $this->appSecret, + 'redirect_uri' => $redirectUrl ]; - if(!$byRefresh){ - $params['redirect_uri'] = $redirectUrl; - } - $response = $this->sendRequest(self::AUTH_TOKEN_URL, $params); - $this->tokenService->saveTokens($response->access_token, !$byRefresh ? $response->refresh_token : null); + $this->tokenService->saveTokens($response->access_token, $response->refresh_token); return $response; } + /** + * Fetches the access token by refresh token + * @param string $refreshToken + * @return string + * @throws Exception + */ + private function fetchAccessTokenByRefreshToken(string $refreshToken): string + { + $params = [ + 'refresh_token' => $refreshToken, + 'grant_type' => 'refresh_token', + 'client_id' => $this->appKey, + 'client_secret' => $this->appSecret + ]; + + $response = $this->sendRequest(self::AUTH_TOKEN_URL, $params); + + $this->tokenService->saveTokens($response->access_token); + + return $response->access_token; + } + /** * Sends rpc request * @param string $uri - * @param null $data + * @param mixed|null $data * @param array $headers * @param string $method * @return mixed|null @@ -161,16 +179,16 @@ public function sendRequest(string $uri, $data = null, array $headers = [], stri if ($errors = $this->httpClient->getErrors()) { $code = $errors['code']; - if ($code == self::INVALID_TOKEN_ERROR_CODE) { + if ($this->accessTokenNeedsRefresh($code)) { $prevUrl = $this->httpClient->url(); $prevData = $this->httpClient->getData(); $prevHeaders = $this->httpClient->getRequestHeaders(); $refreshToken = $this->tokenService->getRefreshToken(); - $response = $this->fetchTokens($refreshToken , '', true); + $accessToken = $this->fetchAccessTokenByRefreshToken($refreshToken); - $prevHeaders['Authorization'] = 'Bearer ' . $response->access_token; + $prevHeaders['Authorization'] = 'Bearer ' . $accessToken; $responseBody = $this->sendRequest($prevUrl, $prevData, $prevHeaders); @@ -216,4 +234,18 @@ public function getFileInfo(string $fileId, bool $media = false, array $params = $queryParam = $media ? '?alt=media' : '?fields=*'; return $this->rpcRequest(GoogleDriveApp::FILE_METADATA_URL . '/' . $fileId . $queryParam, $params, 'GET'); } + + /** + * Checks if the access token need refresh + * @param int $code + * @return bool + */ + private function accessTokenNeedsRefresh(int $code): bool + { + if ($code != 401) { + return false; + } + + return true; + } } \ No newline at end of file