diff --git a/README.md b/README.md index 9d7a9f2..6792652 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,19 @@ $fileDelete = $client->deleteFile([ $fileList = $client->listFiles([ 'BucketId' => '4d2dbbe08e1e983c5e6f0d12' ]); + +// Retrieve file versions from a bucket. Returns an array. +$fileVersions = $client->listFileVersions([ + 'BucketId' => '4d2dbbe08e1e983c5e6f0d12', + + // Optional Parameters + // 'StartFileName' => 'my-start-file-name', + // 'StartFileId' => 'my-start-file-id', + // 'MaxFileCount' => 'max-files-to-return', + // 'Prefix' => 'my-file-prefix', + // 'Delimiter' => 'my-delimiter', + +]); ``` ## Installation diff --git a/src/Client.php b/src/Client.php index 55bbfd6..fa23afb 100644 --- a/src/Client.php +++ b/src/Client.php @@ -400,6 +400,75 @@ public function deleteFile(array $options) return true; } + /** + * Get available versions of a file. + * + * @param array $options + * @return array + * @throws ValidationException + */ + public function listFileVersions(array $options) + { + if (!isset($options['BucketId']) && isset($options['BucketName'])) { + $options['BucketId'] = $this->getBucketIdFromName($options['BucketName']); + } + + // The maximum number of files to return from this call - 0 defaults to 100. + $maxFileCount = isset($options['MaxFileCount']) ? (int) $options['MaxFileCount'] : 0; + + // Files returned will be limited to those within the top folder, or any one subfolder. + $delimiter = isset($options['Delimiter']) ? $options['Delimiter'] : null; + + // The first file name to return. + $startFileName = isset($options['StartFileName']) ? $options['StartFileName'] : null; + + // The first file ID to return. + $startFileId = isset($options['StartFileId']) ? $options['StartFileId'] : null; + + // StartFileName must also be provided if StartFileId is specified. + if (isset($startFileId) && !isset($startFileName)) { + throw new ValidationException('StartFileName must be provided when StartFileId field is specified'); + } + + // Files returned will be limited to those with the given prefix. + $prefix = isset($options['Prefix']) ? $options['Prefix'] : null; + + $response = $this->client->request('POST', $this->apiUrl.'/b2_list_file_versions', [ + 'headers' => [ + 'Authorization' => $this->authToken + ], + 'json' => [ + 'bucketId' => $options['BucketId'], + 'startFileName' => $startFileName, + 'startFileId' => $startFileId, + 'maxFileCount' => $maxFileCount, + 'prefix' => $prefix, + 'delimiter' => $delimiter, + ] + ]); + + if (!empty($response['files'])) { + $files = []; + foreach ($response['files'] as $file) { + $files[] = new File( + $file['fileId'], + $file['fileName'], + $file['contentSha1'], + $file['contentLength'], + $file['contentType'], + $file['fileInfo'], + $options['BucketId'], + $file['action'], + $file['uploadTimestamp'] + ); + } + + $response['files'] = $files; + } + + return $response; + } + /** * Authorize the B2 account in order to get an auth token and API/download URLs. * diff --git a/tests/ClientTest.php b/tests/ClientTest.php index f58ae19..d5303e2 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -524,4 +524,38 @@ public function testDeletingNonExistentFileThrowsException() 'FileName' => 'fileName' ])); } + + public function testListFileVersions() + { + $guzzle = $this->buildGuzzleFromResponses([ + $this->buildResponseFromStub(200, [], 'authorize_account.json'), + $this->buildResponseFromStub(200, [], 'get_file_versions.json'), + ]); + + $client = new Client('testId', 'testKey', ['client' => $guzzle]); + + $versions = $client->listFileVersions([ + 'BucketId' => 'bucketId', + ]); + + $this->assertInternalType('array', $versions); + $this->assertInstanceOf(File::class, $versions['files'][0]); + $this->assertCount(2, $versions['files']); + } + public function testListFileVersionsWithStartFileIdButNoStartFileNameThrowsException() + { + $this->setExpectedException(ValidationException::class); + + $guzzle = $this->buildGuzzleFromResponses([ + $this->buildResponseFromStub(200, [], 'authorize_account.json'), + $this->buildResponseFromStub(200, [], 'get_file_versions.json'), + ]); + + $client = new Client('testId', 'testKey', ['client' => $guzzle]); + + $versions = $client->listFileVersions([ + 'BucketId' => 'bucketId', + 'StartFileId' => 123, + ]); + } } diff --git a/tests/responses/get_file_versions.json b/tests/responses/get_file_versions.json new file mode 100644 index 0000000..2b74818 --- /dev/null +++ b/tests/responses/get_file_versions.json @@ -0,0 +1,32 @@ +{ + "files":[ + { + "action":"upload", + "contentLength":583049, + "contentSha1":"b374a67d3ec3d344b65293cb4f664867015e6515", + "contentType":"application\/zip", + "fileId":"4_zed3392ffe89c50eb52800811_f1029791cfa55df24_d20161113_m213120_c001_v0001032_t0019", + "fileInfo":{ + "src_last_modified_millis":"1479072679808" + }, + "fileName":"ee3c47a2-6f2c-4fa8-87fe-7ad3c5773285.zip", + "size":583049, + "uploadTimestamp":1479072680000 + }, + { + "action":"upload", + "contentLength":583049, + "contentSha1":"d0e984801ff29436eda34ea67cac62eff5c439d1", + "contentType":"application\/zip", + "fileId":"4_zed3392ffe89c50eb52800811_f119c18b3bed17a4a_d20161113_m213048_c001_v0001032_t0010", + "fileInfo":{ + "src_last_modified_millis":"1479072647649" + }, + "fileName":"ee3c47a2-6f2c-4fa8-87fe-7ad3c5773285.zip", + "size":583049, + "uploadTimestamp":1479072648000 + } + ], + "nextFileId":null, + "nextFileName":null +} \ No newline at end of file