Changeset View
Changeset View
Standalone View
Standalone View
src/tests/Feature/Controller/FsTest.php
- This file was moved from src/tests/Feature/Controller/FilesTest.php.
<?php | <?php | ||||
namespace Tests\Feature\Controller; | namespace Tests\Feature\Controller; | ||||
use App\Backends\Storage; | use App\Backends\Storage; | ||||
use App\Fs\Item; | use App\Fs\Item; | ||||
use App\Fs\Property; | use App\Fs\Property; | ||||
use App\User; | use App\User; | ||||
use Illuminate\Support\Facades\Cache; | |||||
use Illuminate\Support\Facades\Storage as LaravelStorage; | use Illuminate\Support\Facades\Storage as LaravelStorage; | ||||
use Tests\TestCase; | use Tests\TestCase; | ||||
/** | /** | ||||
* @group files | * @group files | ||||
*/ | */ | ||||
class FilesTest extends TestCase | class FsTest extends TestCase | ||||
{ | { | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public function setUp(): void | public function setUp(): void | ||||
{ | { | ||||
parent::setUp(); | parent::setUp(); | ||||
Item::query()->delete(); | Item::query()->delete(); | ||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public function tearDown(): void | public function tearDown(): void | ||||
{ | { | ||||
Item::query()->delete(); | Item::query()->delete(); | ||||
$disk = LaravelStorage::disk('files'); | $disk = LaravelStorage::disk(\config('filesystems.default')); | ||||
foreach ($disk->listContents('') as $dir) { | foreach ($disk->listContents('') as $dir) { | ||||
$disk->deleteDirectory($dir->path()); | $disk->deleteDirectory($dir->path()); | ||||
} | } | ||||
parent::tearDown(); | parent::tearDown(); | ||||
} | } | ||||
/** | /** | ||||
* Test deleting files (DELETE /api/v4/files/<file-id>) | * Test deleting items (DELETE /api/v4/fs/<item-id>) | ||||
*/ | */ | ||||
public function testDelete(): void | public function testDelete(): void | ||||
{ | { | ||||
$john = $this->getTestUser('john@kolab.org'); | $john = $this->getTestUser('john@kolab.org'); | ||||
$jack = $this->getTestUser('jack@kolab.org'); | $jack = $this->getTestUser('jack@kolab.org'); | ||||
$file = $this->getTestFile($john, 'teśt.txt', 'Teśt content', ['mimetype' => 'plain/text']); | $file = $this->getTestFile($john, 'teśt.txt', 'Teśt content', ['mimetype' => 'plain/text']); | ||||
// Unauth access | // Unauth access | ||||
$response = $this->delete("api/v4/files/{$file->id}"); | $response = $this->delete("api/v4/fs/{$file->id}"); | ||||
$response->assertStatus(401); | $response->assertStatus(401); | ||||
// Unauth access | // Unauth access | ||||
$response = $this->actingAs($jack)->delete("api/v4/files/{$file->id}"); | $response = $this->actingAs($jack)->delete("api/v4/fs/{$file->id}"); | ||||
$response->assertStatus(403); | $response->assertStatus(403); | ||||
// Non-existing file | // Non-existing file | ||||
$response = $this->actingAs($john)->delete("api/v4/files/123"); | $response = $this->actingAs($john)->delete("api/v4/fs/123"); | ||||
$response->assertStatus(404); | $response->assertStatus(404); | ||||
// File owner access | // File owner access | ||||
$response = $this->actingAs($john)->delete("api/v4/files/{$file->id}"); | $response = $this->actingAs($john)->delete("api/v4/fs/{$file->id}"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('success', $json['status']); | $this->assertSame('success', $json['status']); | ||||
$this->assertSame("File deleted successfully.", $json['message']); | $this->assertSame("File deleted successfully.", $json['message']); | ||||
$this->assertSame(null, Item::find($file->id)); | $this->assertSame(null, Item::find($file->id)); | ||||
// Note: The file is expected to stay still in the filesystem, we're not testing this here. | // Note: The file is expected to stay still in the filesystem, we're not testing this here. | ||||
// TODO: Test acting as another user with permissions | // TODO: Test acting as another user with permissions | ||||
} | } | ||||
/** | /** | ||||
* Test file downloads (GET /api/v4/files/downloads/<id>) | * Test file downloads (GET /api/v4/fs/downloads/<id>) | ||||
*/ | */ | ||||
public function testDownload(): void | public function testDownload(): void | ||||
{ | { | ||||
$john = $this->getTestUser('john@kolab.org'); | $john = $this->getTestUser('john@kolab.org'); | ||||
$jack = $this->getTestUser('jack@kolab.org'); | $jack = $this->getTestUser('jack@kolab.org'); | ||||
$file = $this->getTestFile($john, 'teśt.txt', 'Teśt content', ['mimetype' => 'plain/text']); | $file = $this->getTestFile($john, 'teśt.txt', 'Teśt content', ['mimetype' => 'plain/text']); | ||||
// Unauth access | // Unauth access | ||||
$response = $this->get("api/v4/files/{$file->id}?downloadUrl=1"); | $response = $this->get("api/v4/fs/{$file->id}?downloadUrl=1"); | ||||
$response->assertStatus(401); | $response->assertStatus(401); | ||||
$response = $this->actingAs($jack)->get("api/v4/files/{$file->id}?downloadUrl=1"); | $response = $this->actingAs($jack)->get("api/v4/fs/{$file->id}?downloadUrl=1"); | ||||
$response->assertStatus(403); | $response->assertStatus(403); | ||||
// Non-existing file | // Non-existing file | ||||
$response = $this->actingAs($john)->get("api/v4/files/123456?downloadUrl=1"); | $response = $this->actingAs($john)->get("api/v4/fs/123456?downloadUrl=1"); | ||||
$response->assertStatus(404); | $response->assertStatus(404); | ||||
// Get downloadLink for the file | // Get downloadLink for the file | ||||
$response = $this->actingAs($john)->get("api/v4/files/{$file->id}?downloadUrl=1"); | $response = $this->actingAs($john)->get("api/v4/fs/{$file->id}?downloadUrl=1"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame($file->id, $json['id']); | $this->assertSame($file->id, $json['id']); | ||||
$link = $json['downloadUrl']; | $link = $json['downloadUrl']; | ||||
// Fetch the file content | // Fetch the file content | ||||
$response = $this->get(substr($link, strpos($link, '/api/') + 1)); | $response = $this->get(substr($link, strpos($link, '/api/') + 1)); | ||||
$response->assertStatus(200) | $response->assertStatus(200) | ||||
->assertHeader('Content-Disposition', "attachment; filename=test.txt; filename*=utf-8''te%C5%9Bt.txt") | ->assertHeader('Content-Disposition', "attachment; filename=test.txt; filename*=utf-8''te%C5%9Bt.txt") | ||||
// ->assertHeader('Content-Length', $file->getProperty('size')) | |||||
->assertHeader('Content-Type', $file->getProperty('mimetype')); | ->assertHeader('Content-Type', $file->getProperty('mimetype')); | ||||
$this->assertSame('Teśt content', $response->streamedContent()); | $this->assertSame('Teśt content', $response->streamedContent()); | ||||
// Test acting as another user with read permission | // Test acting as another user with read permission | ||||
$permission = $this->getTestFilePermission($file, $jack, 'r'); | $permission = $this->getTestFilePermission($file, $jack, 'r'); | ||||
$response = $this->actingAs($jack)->get("api/v4/files/{$permission->key}?downloadUrl=1"); | $response = $this->actingAs($jack)->get("api/v4/fs/{$permission->key}?downloadUrl=1"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame($file->id, $json['id']); | $this->assertSame($file->id, $json['id']); | ||||
$link = $json['downloadUrl']; | $link = $json['downloadUrl']; | ||||
// Fetch the file content | // Fetch the file content | ||||
$response = $this->get(substr($link, strpos($link, '/api/') + 1)); | $response = $this->get(substr($link, strpos($link, '/api/') + 1)); | ||||
$response->assertStatus(200) | $response->assertStatus(200) | ||||
->assertHeader('Content-Disposition', "attachment; filename=test.txt; filename*=utf-8''te%C5%9Bt.txt") | ->assertHeader('Content-Disposition', "attachment; filename=test.txt; filename*=utf-8''te%C5%9Bt.txt") | ||||
// ->assertHeader('Content-Length', $file->getProperty('size')) | |||||
->assertHeader('Content-Type', $file->getProperty('mimetype')); | ->assertHeader('Content-Type', $file->getProperty('mimetype')); | ||||
$this->assertSame('Teśt content', $response->streamedContent()); | $this->assertSame('Teśt content', $response->streamedContent()); | ||||
// Test downloading a multi-chunk file | // Test downloading a multi-chunk file | ||||
$file = $this->getTestFile($john, 'test2.txt', ['T1', 'T2'], ['mimetype' => 'plain/text']); | $file = $this->getTestFile($john, 'test2.txt', ['T1', 'T2'], ['mimetype' => 'plain/text']); | ||||
$response = $this->actingAs($john)->get("api/v4/files/{$file->id}?downloadUrl=1"); | $response = $this->actingAs($john)->get("api/v4/fs/{$file->id}?downloadUrl=1"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame($file->id, $json['id']); | $this->assertSame($file->id, $json['id']); | ||||
$link = $json['downloadUrl']; | $link = $json['downloadUrl']; | ||||
// Fetch the file content | // Fetch the file content | ||||
$response = $this->get(substr($link, strpos($link, '/api/') + 1)); | $response = $this->get(substr($link, strpos($link, '/api/') + 1)); | ||||
$response->assertStatus(200) | $response->assertStatus(200) | ||||
->assertHeader('Content-Disposition', "attachment; filename=test2.txt") | ->assertHeader('Content-Disposition', "attachment; filename=test2.txt") | ||||
// ->assertHeader('Content-Length', $file->getProperty('size')) | |||||
->assertHeader('Content-Type', $file->getProperty('mimetype')); | ->assertHeader('Content-Type', $file->getProperty('mimetype')); | ||||
$this->assertSame('T1T2', $response->streamedContent()); | $this->assertSame('T1T2', $response->streamedContent()); | ||||
} | } | ||||
/** | /** | ||||
* Test fetching/creating/updaing/deleting file permissions (GET|POST|PUT /api/v4/files/<file-id>/permissions) | * Test fetching/creating/updaing/deleting file permissions (GET|POST|PUT /api/v4/fs/<file-id>/permissions) | ||||
*/ | */ | ||||
public function testPermissions(): void | public function testPermissions(): void | ||||
{ | { | ||||
$john = $this->getTestUser('john@kolab.org'); | $john = $this->getTestUser('john@kolab.org'); | ||||
$jack = $this->getTestUser('jack@kolab.org'); | $jack = $this->getTestUser('jack@kolab.org'); | ||||
$file = $this->getTestFile($john, 'test1.txt', []); | $file = $this->getTestFile($john, 'test1.txt', []); | ||||
// Unauth access not allowed | // Unauth access not allowed | ||||
$response = $this->get("api/v4/files/{$file->id}/permissions"); | $response = $this->get("api/v4/fs/{$file->id}/permissions"); | ||||
$response->assertStatus(401); | $response->assertStatus(401); | ||||
$response = $this->post("api/v4/files/{$file->id}/permissions", []); | $response = $this->post("api/v4/fs/{$file->id}/permissions", []); | ||||
$response->assertStatus(401); | $response->assertStatus(401); | ||||
// Non-existing file | // Non-existing file | ||||
$response = $this->actingAs($john)->get("api/v4/files/1234/permissions"); | $response = $this->actingAs($john)->get("api/v4/fs/1234/permissions"); | ||||
$response->assertStatus(404); | $response->assertStatus(404); | ||||
$response = $this->actingAs($john)->post("api/v4/files/1234/permissions", []); | $response = $this->actingAs($john)->post("api/v4/fs/1234/permissions", []); | ||||
$response->assertStatus(404); | $response->assertStatus(404); | ||||
// No permissions to the file | // No permissions to the file | ||||
$response = $this->actingAs($jack)->get("api/v4/files/{$file->id}/permissions"); | $response = $this->actingAs($jack)->get("api/v4/fs/{$file->id}/permissions"); | ||||
$response->assertStatus(403); | $response->assertStatus(403); | ||||
$response = $this->actingAs($jack)->post("api/v4/files/{$file->id}/permissions", []); | $response = $this->actingAs($jack)->post("api/v4/fs/{$file->id}/permissions", []); | ||||
$response->assertStatus(403); | $response->assertStatus(403); | ||||
// Expect an empty list of permissions | // Expect an empty list of permissions | ||||
$response = $this->actingAs($john)->get("api/v4/files/{$file->id}/permissions"); | $response = $this->actingAs($john)->get("api/v4/fs/{$file->id}/permissions"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertCount(2, $json); | $this->assertCount(2, $json); | ||||
$this->assertSame([], $json['list']); | $this->assertSame([], $json['list']); | ||||
$this->assertSame(0, $json['count']); | $this->assertSame(0, $json['count']); | ||||
// Empty input | // Empty input | ||||
$response = $this->actingAs($john)->post("api/v4/files/{$file->id}/permissions", []); | $response = $this->actingAs($john)->post("api/v4/fs/{$file->id}/permissions", []); | ||||
$response->assertStatus(422); | $response->assertStatus(422); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('error', $json['status']); | $this->assertSame('error', $json['status']); | ||||
$this->assertCount(2, $json['errors']); | $this->assertCount(2, $json['errors']); | ||||
$this->assertSame(["The user field is required."], $json['errors']['user']); | $this->assertSame(["The user field is required."], $json['errors']['user']); | ||||
$this->assertSame(["The permissions field is required."], $json['errors']['permissions']); | $this->assertSame(["The permissions field is required."], $json['errors']['permissions']); | ||||
// Test more input validation | // Test more input validation | ||||
$post = ['user' => 'user', 'permissions' => 'read']; | $post = ['user' => 'user', 'permissions' => 'read']; | ||||
$response = $this->actingAs($john)->post("api/v4/files/{$file->id}/permissions", $post); | $response = $this->actingAs($john)->post("api/v4/fs/{$file->id}/permissions", $post); | ||||
$response->assertStatus(422); | $response->assertStatus(422); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('error', $json['status']); | $this->assertSame('error', $json['status']); | ||||
$this->assertCount(2, $json['errors']); | $this->assertCount(2, $json['errors']); | ||||
$this->assertSame(["The user must be a valid email address."], $json['errors']['user']); | $this->assertSame(["The user must be a valid email address."], $json['errors']['user']); | ||||
$this->assertSame("The file permission is invalid.", $json['errors']['permissions']); | $this->assertSame("The file permission is invalid.", $json['errors']['permissions']); | ||||
// Let's add some permission | // Let's add some permission | ||||
$post = ['user' => 'jack@kolab.org', 'permissions' => 'read-only']; | $post = ['user' => 'jack@kolab.org', 'permissions' => 'read-only']; | ||||
$response = $this->actingAs($john)->post("api/v4/files/{$file->id}/permissions", $post); | $response = $this->actingAs($john)->post("api/v4/fs/{$file->id}/permissions", $post); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('success', $json['status']); | $this->assertSame('success', $json['status']); | ||||
$this->assertSame("File permissions created successfully.", $json['message']); | $this->assertSame("File permissions created successfully.", $json['message']); | ||||
$permission = $file->properties()->where('key', 'like', 'share-%')->orderBy('value')->first(); | $permission = $file->properties()->where('key', 'like', 'share-%')->orderBy('value')->first(); | ||||
$this->assertSame("{$jack->email}:r", $permission->value); | $this->assertSame("{$jack->email}:r", $permission->value); | ||||
$this->assertSame($permission->key, $json['id']); | $this->assertSame($permission->key, $json['id']); | ||||
$this->assertSame($jack->email, $json['user']); | $this->assertSame($jack->email, $json['user']); | ||||
$this->assertSame('read-only', $json['permissions']); | $this->assertSame('read-only', $json['permissions']); | ||||
$this->assertSame(\App\Utils::serviceUrl('file/' . $permission->key), $json['link']); | $this->assertSame(\App\Utils::serviceUrl('file/' . $permission->key), $json['link']); | ||||
// Error handling on use of the same user | // Error handling on use of the same user | ||||
$post = ['user' => 'jack@kolab.org', 'permissions' => 'read-only']; | $post = ['user' => 'jack@kolab.org', 'permissions' => 'read-only']; | ||||
$response = $this->actingAs($john)->post("api/v4/files/{$file->id}/permissions", $post); | $response = $this->actingAs($john)->post("api/v4/fs/{$file->id}/permissions", $post); | ||||
$response->assertStatus(422); | $response->assertStatus(422); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('error', $json['status']); | $this->assertSame('error', $json['status']); | ||||
$this->assertSame("File permission already exists.", $json['errors']['user']); | $this->assertSame("File permission already exists.", $json['errors']['user']); | ||||
// Test update | // Test update | ||||
$response = $this->actingAs($john)->put("api/v4/files/{$file->id}/permissions/1234", $post); | $response = $this->actingAs($john)->put("api/v4/fs/{$file->id}/permissions/1234", $post); | ||||
$response->assertStatus(404); | $response->assertStatus(404); | ||||
$post = ['user' => 'jack@kolab.org', 'permissions' => 'read-write']; | $post = ['user' => 'jack@kolab.org', 'permissions' => 'read-write']; | ||||
$response = $this->actingAs($john)->put("api/v4/files/{$file->id}/permissions/{$permission->key}", $post); | $response = $this->actingAs($john)->put("api/v4/fs/{$file->id}/permissions/{$permission->key}", $post); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('success', $json['status']); | $this->assertSame('success', $json['status']); | ||||
$this->assertSame("File permissions updated successfully.", $json['message']); | $this->assertSame("File permissions updated successfully.", $json['message']); | ||||
$permission->refresh(); | $permission->refresh(); | ||||
$this->assertSame("{$jack->email}:rw", $permission->value); | $this->assertSame("{$jack->email}:rw", $permission->value); | ||||
$this->assertSame($permission->key, $json['id']); | $this->assertSame($permission->key, $json['id']); | ||||
$this->assertSame($jack->email, $json['user']); | $this->assertSame($jack->email, $json['user']); | ||||
$this->assertSame('read-write', $json['permissions']); | $this->assertSame('read-write', $json['permissions']); | ||||
$this->assertSame(\App\Utils::serviceUrl('file/' . $permission->key), $json['link']); | $this->assertSame(\App\Utils::serviceUrl('file/' . $permission->key), $json['link']); | ||||
// Input validation on update | // Input validation on update | ||||
$post = ['user' => 'jack@kolab.org', 'permissions' => 'read']; | $post = ['user' => 'jack@kolab.org', 'permissions' => 'read']; | ||||
$response = $this->actingAs($john)->put("api/v4/files/{$file->id}/permissions/{$permission->key}", $post); | $response = $this->actingAs($john)->put("api/v4/fs/{$file->id}/permissions/{$permission->key}", $post); | ||||
$response->assertStatus(422); | $response->assertStatus(422); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('error', $json['status']); | $this->assertSame('error', $json['status']); | ||||
$this->assertSame("The file permission is invalid.", $json['errors']['permissions']); | $this->assertSame("The file permission is invalid.", $json['errors']['permissions']); | ||||
// Test GET with existing permissions | // Test GET with existing permissions | ||||
$response = $this->actingAs($john)->get("api/v4/files/{$file->id}/permissions"); | $response = $this->actingAs($john)->get("api/v4/fs/{$file->id}/permissions"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertCount(2, $json); | $this->assertCount(2, $json); | ||||
$this->assertCount(1, $json['list']); | $this->assertCount(1, $json['list']); | ||||
$this->assertSame(1, $json['count']); | $this->assertSame(1, $json['count']); | ||||
$this->assertSame($permission->key, $json['list'][0]['id']); | $this->assertSame($permission->key, $json['list'][0]['id']); | ||||
$this->assertSame($jack->email, $json['list'][0]['user']); | $this->assertSame($jack->email, $json['list'][0]['user']); | ||||
$this->assertSame('read-write', $json['list'][0]['permissions']); | $this->assertSame('read-write', $json['list'][0]['permissions']); | ||||
$this->assertSame(\App\Utils::serviceUrl('file/' . $permission->key), $json['list'][0]['link']); | $this->assertSame(\App\Utils::serviceUrl('file/' . $permission->key), $json['list'][0]['link']); | ||||
// Delete permission | // Delete permission | ||||
$response = $this->actingAs($john)->delete("api/v4/files/{$file->id}/permissions/1234"); | $response = $this->actingAs($john)->delete("api/v4/fs/{$file->id}/permissions/1234"); | ||||
$response->assertStatus(404); | $response->assertStatus(404); | ||||
$response = $this->actingAs($john)->delete("api/v4/files/{$file->id}/permissions/{$permission->key}"); | $response = $this->actingAs($john)->delete("api/v4/fs/{$file->id}/permissions/{$permission->key}"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('success', $json['status']); | $this->assertSame('success', $json['status']); | ||||
$this->assertSame("File permissions deleted successfully.", $json['message']); | $this->assertSame("File permissions deleted successfully.", $json['message']); | ||||
$this->assertCount(0, $file->properties()->where('key', 'like', 'share-%')->get()); | $this->assertCount(0, $file->properties()->where('key', 'like', 'share-%')->get()); | ||||
} | } | ||||
/** | /** | ||||
* Test fetching files/folders list (GET /api/v4/files) | * Test fetching file/folders list (GET /api/v4/fs) | ||||
*/ | */ | ||||
public function testIndex(): void | public function testIndex(): void | ||||
{ | { | ||||
// Unauth access not allowed | // Unauth access not allowed | ||||
$response = $this->get("api/v4/files"); | $response = $this->get("api/v4/fs"); | ||||
$response->assertStatus(401); | $response->assertStatus(401); | ||||
$user = $this->getTestUser('john@kolab.org'); | $user = $this->getTestUser('john@kolab.org'); | ||||
// Expect an empty list | // Expect an empty list | ||||
$response = $this->actingAs($user)->get("api/v4/files"); | $response = $this->actingAs($user)->get("api/v4/fs"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertCount(3, $json); | $this->assertCount(3, $json); | ||||
$this->assertSame([], $json['list']); | $this->assertSame([], $json['list']); | ||||
$this->assertSame(0, $json['count']); | $this->assertSame(0, $json['count']); | ||||
$this->assertSame(false, $json['hasMore']); | $this->assertSame(false, $json['hasMore']); | ||||
// Create some files and test again | // Create some files and test again | ||||
$file1 = $this->getTestFile($user, 'test1.txt', [], ['mimetype' => 'text/plain', 'size' => 12345]); | $file1 = $this->getTestFile($user, 'test1.txt', [], ['mimetype' => 'text/plain', 'size' => 12345]); | ||||
$file2 = $this->getTestFile($user, 'test2.gif', [], ['mimetype' => 'image/gif', 'size' => 10000]); | $file2 = $this->getTestFile($user, 'test2.gif', [], ['mimetype' => 'image/gif', 'size' => 10000]); | ||||
$response = $this->actingAs($user)->get("api/v4/files"); | $response = $this->actingAs($user)->get("api/v4/fs"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertCount(3, $json); | $this->assertCount(3, $json); | ||||
$this->assertSame(2, $json['count']); | $this->assertSame(2, $json['count']); | ||||
$this->assertSame(false, $json['hasMore']); | $this->assertSame(false, $json['hasMore']); | ||||
$this->assertCount(2, $json['list']); | $this->assertCount(2, $json['list']); | ||||
$this->assertSame('test1.txt', $json['list'][0]['name']); | $this->assertSame('test1.txt', $json['list'][0]['name']); | ||||
$this->assertSame($file1->id, $json['list'][0]['id']); | $this->assertSame($file1->id, $json['list'][0]['id']); | ||||
$this->assertSame('test2.gif', $json['list'][1]['name']); | $this->assertSame('test2.gif', $json['list'][1]['name']); | ||||
$this->assertSame($file2->id, $json['list'][1]['id']); | $this->assertSame($file2->id, $json['list'][1]['id']); | ||||
// Searching | // Searching | ||||
$response = $this->actingAs($user)->get("api/v4/files?search=t2"); | $response = $this->actingAs($user)->get("api/v4/fs?search=t2"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertCount(3, $json); | $this->assertCount(3, $json); | ||||
$this->assertSame(1, $json['count']); | $this->assertSame(1, $json['count']); | ||||
$this->assertSame(false, $json['hasMore']); | $this->assertSame(false, $json['hasMore']); | ||||
$this->assertCount(1, $json['list']); | $this->assertCount(1, $json['list']); | ||||
$this->assertSame('test2.gif', $json['list'][0]['name']); | $this->assertSame('test2.gif', $json['list'][0]['name']); | ||||
$this->assertSame($file2->id, $json['list'][0]['id']); | $this->assertSame($file2->id, $json['list'][0]['id']); | ||||
// TODO: Test paging | // TODO: Test paging | ||||
// Make sure incomplete files are skipped | // Make sure incomplete files are skipped | ||||
$file1->type |= Item::TYPE_INCOMPLETE; | $file1->type |= Item::TYPE_INCOMPLETE; | ||||
$file1->save(); | $file1->save(); | ||||
$response = $this->actingAs($user)->get("api/v4/files"); | $response = $this->actingAs($user)->get("api/v4/fs"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertCount(3, $json); | $this->assertCount(3, $json); | ||||
$this->assertSame(1, $json['count']); | $this->assertSame(1, $json['count']); | ||||
} | } | ||||
/** | /** | ||||
* Test fetching file metadata (GET /api/v4/files/<file-id>) | * Test fetching file metadata (GET /api/v4/fs/<file-id>) | ||||
*/ | */ | ||||
public function testShow(): void | public function testShow(): void | ||||
{ | { | ||||
// Unauth access not allowed | // Unauth access not allowed | ||||
$response = $this->get("api/v4/files/1234"); | $response = $this->get("api/v4/fs/1234"); | ||||
$response->assertStatus(401); | $response->assertStatus(401); | ||||
$john = $this->getTestUser('john@kolab.org'); | $john = $this->getTestUser('john@kolab.org'); | ||||
$jack = $this->getTestUser('jack@kolab.org'); | $jack = $this->getTestUser('jack@kolab.org'); | ||||
$file = $this->getTestFile($john, 'teśt.txt', 'Teśt content', ['mimetype' => 'plain/text']); | $file = $this->getTestFile($john, 'teśt.txt', 'Teśt content', ['mimetype' => 'plain/text']); | ||||
// Non-existing file | // Non-existing file | ||||
$response = $this->actingAs($jack)->get("api/v4/files/1234"); | $response = $this->actingAs($jack)->get("api/v4/fs/1234"); | ||||
$response->assertStatus(404); | $response->assertStatus(404); | ||||
// Unauthorized access | // Unauthorized access | ||||
$response = $this->actingAs($jack)->get("api/v4/files/{$file->id}"); | $response = $this->actingAs($jack)->get("api/v4/fs/{$file->id}"); | ||||
$response->assertStatus(403); | $response->assertStatus(403); | ||||
// Get file metadata | // Get file metadata | ||||
$response = $this->actingAs($john)->get("api/v4/files/{$file->id}"); | $response = $this->actingAs($john)->get("api/v4/fs/{$file->id}"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame($file->id, $json['id']); | $this->assertSame($file->id, $json['id']); | ||||
$this->assertSame($file->getProperty('mimetype'), $json['mimetype']); | $this->assertSame($file->getProperty('mimetype'), $json['mimetype']); | ||||
$this->assertSame((int) $file->getProperty('size'), $json['size']); | $this->assertSame((int) $file->getProperty('size'), $json['size']); | ||||
$this->assertSame($file->getProperty('name'), $json['name']); | $this->assertSame($file->getProperty('name'), $json['name']); | ||||
$this->assertSame(true, $json['isOwner']); | $this->assertSame(true, $json['isOwner']); | ||||
$this->assertSame(true, $json['canUpdate']); | $this->assertSame(true, $json['canUpdate']); | ||||
$this->assertSame(true, $json['canDelete']); | $this->assertSame(true, $json['canDelete']); | ||||
// Get file content | // Get file content | ||||
$response = $this->actingAs($john)->get("api/v4/files/{$file->id}?download=1"); | $response = $this->actingAs($john)->get("api/v4/fs/{$file->id}?download=1"); | ||||
$response->assertStatus(200) | $response->assertStatus(200) | ||||
->assertHeader('Content-Disposition', "attachment; filename=test.txt; filename*=utf-8''te%C5%9Bt.txt") | ->assertHeader('Content-Disposition', "attachment; filename=test.txt; filename*=utf-8''te%C5%9Bt.txt") | ||||
// ->assertHeader('Content-Length', $file->getProperty('size')) | |||||
->assertHeader('Content-Type', $file->getProperty('mimetype')); | ->assertHeader('Content-Type', $file->getProperty('mimetype')); | ||||
$this->assertSame('Teśt content', $response->streamedContent()); | $this->assertSame('Teśt content', $response->streamedContent()); | ||||
// Test acting as a user with file permissions | // Test acting as a user with file permissions | ||||
$permission = $this->getTestFilePermission($file, $jack, 'r'); | $permission = $this->getTestFilePermission($file, $jack, 'r'); | ||||
$response = $this->actingAs($jack)->get("api/v4/files/{$permission->key}"); | $response = $this->actingAs($jack)->get("api/v4/fs/{$permission->key}"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame($file->id, $json['id']); | $this->assertSame($file->id, $json['id']); | ||||
$this->assertSame(false, $json['isOwner']); | $this->assertSame(false, $json['isOwner']); | ||||
$this->assertSame(false, $json['canUpdate']); | $this->assertSame(false, $json['canUpdate']); | ||||
$this->assertSame(false, $json['canDelete']); | $this->assertSame(false, $json['canDelete']); | ||||
} | } | ||||
/** | /** | ||||
* Test creating files (POST /api/v4/files) | * Test creating files (POST /api/v4/fs) | ||||
*/ | */ | ||||
public function testStore(): void | public function testStore(): void | ||||
{ | { | ||||
// Unauth access not allowed | // Unauth access not allowed | ||||
$response = $this->post("api/v4/files"); | $response = $this->post("api/v4/fs"); | ||||
$response->assertStatus(401); | $response->assertStatus(401); | ||||
$john = $this->getTestUser('john@kolab.org'); | $john = $this->getTestUser('john@kolab.org'); | ||||
// Test input validation | // Test input validation | ||||
$response = $this->sendRawBody($john, 'POST', "api/v4/files", [], ''); | $response = $this->sendRawBody($john, 'POST', "api/v4/fs", [], ''); | ||||
$response->assertStatus(422); | $response->assertStatus(422); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('error', $json['status']); | $this->assertSame('error', $json['status']); | ||||
$this->assertSame(["The name field is required."], $json['errors']['name']); | $this->assertSame(["The name field is required."], $json['errors']['name']); | ||||
$response = $this->sendRawBody($john, 'POST', "api/v4/files?name=*.txt", [], ''); | $response = $this->sendRawBody($john, 'POST', "api/v4/fs?name=*.txt", [], ''); | ||||
$response->assertStatus(422); | $response->assertStatus(422); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('error', $json['status']); | $this->assertSame('error', $json['status']); | ||||
$this->assertSame(["The file name is invalid."], $json['errors']['name']); | $this->assertSame(["The file name is invalid."], $json['errors']['name']); | ||||
// Create a file - the simple method | // Create a file - the simple method | ||||
$body = "test content"; | $body = "test content"; | ||||
$headers = []; | $headers = []; | ||||
$response = $this->sendRawBody($john, 'POST', "api/v4/files?name=test.txt", $headers, $body); | $response = $this->sendRawBody($john, 'POST', "api/v4/fs?name=test.txt", $headers, $body); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('success', $json['status']); | $this->assertSame('success', $json['status']); | ||||
$this->assertSame("File created successfully.", $json['message']); | $this->assertSame("File created successfully.", $json['message']); | ||||
$this->assertMatchesRegularExpression('|^[a-z]+/[a-z-]+$|', $json['mimetype']); | $this->assertMatchesRegularExpression('|^[a-z]+/[a-z-]+$|', $json['mimetype']); | ||||
$this->assertSame(strlen($body), $json['size']); | $this->assertSame(strlen($body), $json['size']); | ||||
$this->assertSame('test.txt', $json['name']); | $this->assertSame('test.txt', $json['name']); | ||||
$file = Item::find($json['id']); | $file = Item::find($json['id']); | ||||
$this->assertSame(Item::TYPE_FILE, $file->type); | $this->assertSame(Item::TYPE_FILE, $file->type); | ||||
$this->assertSame($json['mimetype'], $file->getProperty('mimetype')); | $this->assertSame($json['mimetype'], $file->getProperty('mimetype')); | ||||
$this->assertSame($json['size'], (int) $file->getProperty('size')); | $this->assertSame($json['size'], (int) $file->getProperty('size')); | ||||
$this->assertSame($json['name'], $file->getProperty('name')); | $this->assertSame($json['name'], $file->getProperty('name')); | ||||
$this->assertSame($body, $this->getTestFileContent($file)); | $this->assertSame($body, $this->getTestFileContent($file)); | ||||
} | } | ||||
/** | /** | ||||
* Test creating files - resumable (POST /api/v4/files) | * Test creating files - resumable (POST /api/v4/fs) | ||||
*/ | */ | ||||
public function testStoreResumable(): void | public function testStoreResumable(): void | ||||
{ | { | ||||
$john = $this->getTestUser('john@kolab.org'); | $john = $this->getTestUser('john@kolab.org'); | ||||
$response = $this->actingAs($john)->post("api/v4/files?name=test2.txt&media=resumable&size=400"); | $response = $this->actingAs($john)->post("api/v4/fs?name=test2.txt&media=resumable&size=400"); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame(0, $json['uploaded']); | $this->assertSame(0, $json['uploaded']); | ||||
$this->assertMatchesRegularExpression( | $this->assertMatchesRegularExpression( | ||||
'/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', | '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', | ||||
$json['uploadId'] | $json['uploadId'] | ||||
); | ); | ||||
$upload = Cache::get('upload:' . $json['uploadId']); | |||||
$file = Item::find($upload['fileId']); | |||||
$this->assertSame(Item::TYPE_INCOMPLETE | Item::TYPE_FILE, $file->type); | |||||
$uploadId = $json['uploadId']; | $uploadId = $json['uploadId']; | ||||
$size = 0; | $size = 0; | ||||
$fileContent = ''; | $fileContent = ''; | ||||
for ($x = 0; $x <= 2; $x++) { | for ($x = 0; $x <= 2; $x++) { | ||||
$body = str_repeat("$x", 100); | $body = str_repeat("$x", 100); | ||||
$response = $this->sendRawBody(null, 'POST', "api/v4/files/uploads/{$uploadId}?from={$size}", [], $body); | $response = $this->sendRawBody(null, 'POST', "api/v4/fs/uploads/{$uploadId}?from={$size}", [], $body); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$size += 100; | $size += 100; | ||||
$fileContent .= $body; | $fileContent .= $body; | ||||
$this->assertSame($size, $json['uploaded']); | $this->assertSame($size, $json['uploaded']); | ||||
$this->assertSame($uploadId, $json['uploadId']); | $this->assertSame($uploadId, $json['uploadId']); | ||||
} | } | ||||
$body = str_repeat("$x", 100); | $body = str_repeat("$x", 100); | ||||
$response = $this->sendRawBody(null, 'POST', "api/v4/files/uploads/{$uploadId}?from={$size}", [], $body); | $response = $this->sendRawBody(null, 'POST', "api/v4/fs/uploads/{$uploadId}?from={$size}", [], $body); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$size += 100; | $size += 100; | ||||
$fileContent .= $body; | $fileContent .= $body; | ||||
$this->assertSame('success', $json['status']); | $this->assertSame('success', $json['status']); | ||||
// $this->assertSame("", $json['message']); | // $this->assertSame("", $json['message']); | ||||
$this->assertMatchesRegularExpression('|^[a-z]+/[a-z-]+$|', $json['mimetype']); | $this->assertMatchesRegularExpression('|^[a-z]+/[a-z-]+$|', $json['mimetype']); | ||||
$this->assertSame($size, $json['size']); | $this->assertSame($size, $json['size']); | ||||
$this->assertSame('test2.txt', $json['name']); | $this->assertSame('test2.txt', $json['name']); | ||||
$file = Item::find($json['id']); | $file = Item::find($json['id']); | ||||
$this->assertSame(Item::TYPE_FILE, $file->type); | $this->assertSame(Item::TYPE_FILE, $file->type); | ||||
$this->assertSame($json['mimetype'], $file->getProperty('mimetype')); | $this->assertSame($json['mimetype'], $file->getProperty('mimetype')); | ||||
$this->assertSame($json['size'], (int) $file->getProperty('size')); | $this->assertSame($json['size'], (int) $file->getProperty('size')); | ||||
$this->assertSame($json['name'], $file->getProperty('name')); | $this->assertSame($json['name'], $file->getProperty('name')); | ||||
$this->assertSame($fileContent, $this->getTestFileContent($file)); | $this->assertSame($fileContent, $this->getTestFileContent($file)); | ||||
} | } | ||||
/** | /** | ||||
* Test updating files (PUT /api/v4/files/<file-id>) | * Test updating files (PUT /api/v4/fs/<file-id>) | ||||
*/ | */ | ||||
public function testUpdate(): void | public function testUpdate(): void | ||||
{ | { | ||||
// Unauth access not allowed | // Unauth access not allowed | ||||
$response = $this->put("api/v4/files/1234"); | $response = $this->put("api/v4/fs/1234"); | ||||
$response->assertStatus(401); | $response->assertStatus(401); | ||||
$john = $this->getTestUser('john@kolab.org'); | $john = $this->getTestUser('john@kolab.org'); | ||||
$jack = $this->getTestUser('jack@kolab.org'); | $jack = $this->getTestUser('jack@kolab.org'); | ||||
$file = $this->getTestFile($john, 'teśt.txt', 'Teśt content', ['mimetype' => 'plain/text']); | $file = $this->getTestFile($john, 'teśt.txt', 'Teśt content', ['mimetype' => 'plain/text']); | ||||
// Non-existing file | // Non-existing file | ||||
$response = $this->actingAs($john)->put("api/v4/files/1234", []); | $response = $this->actingAs($john)->put("api/v4/fs/1234", []); | ||||
$response->assertStatus(404); | $response->assertStatus(404); | ||||
// Unauthorized access | // Unauthorized access | ||||
$response = $this->actingAs($jack)->put("api/v4/files/{$file->id}", []); | $response = $this->actingAs($jack)->put("api/v4/fs/{$file->id}", []); | ||||
$response->assertStatus(403); | $response->assertStatus(403); | ||||
// Test name validation | // Test name validation | ||||
$post = ['name' => 'test/test.txt']; | $post = ['name' => 'test/test.txt']; | ||||
$response = $this->actingAs($john)->put("api/v4/files/{$file->id}", $post); | $response = $this->actingAs($john)->put("api/v4/fs/{$file->id}", $post); | ||||
$response->assertStatus(422); | $response->assertStatus(422); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('error', $json['status']); | $this->assertSame('error', $json['status']); | ||||
$this->assertSame(["The file name is invalid."], $json['errors']['name']); | $this->assertSame(["The file name is invalid."], $json['errors']['name']); | ||||
$post = ['name' => 'new name.txt', 'media' => 'test']; | $post = ['name' => 'new name.txt', 'media' => 'test']; | ||||
$response = $this->actingAs($john)->put("api/v4/files/{$file->id}", $post); | $response = $this->actingAs($john)->put("api/v4/fs/{$file->id}", $post); | ||||
$response->assertStatus(422); | $response->assertStatus(422); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('error', $json['status']); | $this->assertSame('error', $json['status']); | ||||
$this->assertSame("The specified media is invalid.", $json['errors']['media']); | $this->assertSame("The specified media is invalid.", $json['errors']['media']); | ||||
// Rename a file | // Rename a file | ||||
$post = ['name' => 'new namś.txt']; | $post = ['name' => 'new namś.txt']; | ||||
$response = $this->actingAs($john)->put("api/v4/files/{$file->id}", $post); | $response = $this->actingAs($john)->put("api/v4/fs/{$file->id}", $post); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('success', $json['status']); | $this->assertSame('success', $json['status']); | ||||
$this->assertSame("File updated successfully.", $json['message']); | $this->assertSame("File updated successfully.", $json['message']); | ||||
$file->refresh(); | $file->refresh(); | ||||
$this->assertSame($post['name'], $file->getProperty('name')); | $this->assertSame($post['name'], $file->getProperty('name')); | ||||
// Update file content | // Update file content | ||||
$body = "Test1\nTest2"; | $body = "Test1\nTest2"; | ||||
$response = $this->sendRawBody($john, 'PUT', "api/v4/files/{$file->id}?media=content", [], $body); | $response = $this->sendRawBody($john, 'PUT', "api/v4/fs/{$file->id}?media=content", [], $body); | ||||
$response->assertStatus(200); | $response->assertStatus(200); | ||||
$json = $response->json(); | $json = $response->json(); | ||||
$this->assertSame('success', $json['status']); | $this->assertSame('success', $json['status']); | ||||
$this->assertSame("File updated successfully.", $json['message']); | $this->assertSame("File updated successfully.", $json['message']); | ||||
$file->refresh(); | $file->refresh(); | ||||
Show All 13 Lines | class FsTest extends TestCase | ||||
* @param string $name File name | * @param string $name File name | ||||
* @param string|array $content File content | * @param string|array $content File content | ||||
* @param array $props Extra file properties | * @param array $props Extra file properties | ||||
* | * | ||||
* @return \App\Fs\Item | * @return \App\Fs\Item | ||||
*/ | */ | ||||
protected function getTestFile(User $user, string $name, $content = [], $props = []): Item | protected function getTestFile(User $user, string $name, $content = [], $props = []): Item | ||||
{ | { | ||||
$disk = LaravelStorage::disk('files'); | $disk = LaravelStorage::disk(\config('filesystems.default')); | ||||
$file = $user->fsItems()->create(['type' => Item::TYPE_FILE]); | $file = $user->fsItems()->create(['type' => Item::TYPE_FILE]); | ||||
$size = 0; | $size = 0; | ||||
if (is_array($content) && empty($content)) { | if (is_array($content) && empty($content)) { | ||||
// do nothing, we don't need the body here | // do nothing, we don't need the body here | ||||
} else { | } else { | ||||
foreach ((array) $content as $idx => $chunk) { | foreach ((array) $content as $idx => $chunk) { | ||||
Show All 19 Lines | protected function getTestFile(User $user, string $name, $content = [], $props = []): Item | ||||
]; | ]; | ||||
$file->setProperties($props + $properties); | $file->setProperties($props + $properties); | ||||
return $file; | return $file; | ||||
} | } | ||||
/** | /** | ||||
* Create a test collection. | |||||
* | |||||
* @param \App\User $user File owner | |||||
* @param string $name File name | |||||
* @param array $props Extra collection properties | |||||
* | |||||
* @return \App\Fs\Item | |||||
*/ | |||||
protected function getTestCollection(User $user, string $name, $props = []): Item | |||||
{ | |||||
$collection = $user->fsItems()->create(['type' => Item::TYPE_COLLECTION]); | |||||
$properties = [ | |||||
'name' => $name, | |||||
]; | |||||
$collection->setProperties($props + $properties); | |||||
return $collection; | |||||
} | |||||
/** | |||||
* Get contents of a test file. | * Get contents of a test file. | ||||
* | * | ||||
* @param \App\Fs\Item $file File record | * @param \App\Fs\Item $file File record | ||||
* | * | ||||
* @return string | * @return string | ||||
*/ | */ | ||||
protected function getTestFileContent(Item $file): string | protected function getTestFileContent(Item $file): string | ||||
{ | { | ||||
$content = ''; | $content = ''; | ||||
$file->chunks()->orderBy('sequence')->get()->each(function ($chunk) use ($file, &$content) { | $file->chunks()->orderBy('sequence')->get()->each(function ($chunk) use ($file, &$content) { | ||||
$disk = LaravelStorage::disk('files'); | $disk = LaravelStorage::disk(\config('filesystems.default')); | ||||
$path = Storage::chunkLocation($chunk->chunk_id, $file); | $path = Storage::chunkLocation($chunk->chunk_id, $file); | ||||
$content .= $disk->read($path); | $content .= $disk->read($path); | ||||
}); | }); | ||||
return $content; | return $content; | ||||
} | } | ||||
Show All 36 Lines | protected function sendRawBody(?User $user, string $method, string $uri, array $headers, string $content) | ||||
if ($user) { | if ($user) { | ||||
return $this->actingAs($user)->call($method, $uri, [], $cookies, [], $server, $content); | return $this->actingAs($user)->call($method, $uri, [], $cookies, [], $server, $content); | ||||
} else { | } else { | ||||
// TODO: Make sure this does not use "acting user" set earlier | // TODO: Make sure this does not use "acting user" set earlier | ||||
return $this->call($method, $uri, [], $cookies, [], $server, $content); | return $this->call($method, $uri, [], $cookies, [], $server, $content); | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Test creating collections (POST /api/v4/fs?type=collection) | |||||
*/ | |||||
public function testStoreCollection(): void | |||||
{ | |||||
$john = $this->getTestUser('john@kolab.org'); | |||||
$params = [ | |||||
'name' => "MyTestCollection", | |||||
'deviceId' => "myDeviceId", | |||||
]; | |||||
$response = $this->actingAs($john)->post("api/v4/fs?type=collection", $params); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$this->assertSame('success', $json['status']); | |||||
$collection = Item::find($json['id']); | |||||
$this->assertSame(Item::TYPE_COLLECTION, $collection->type); | |||||
$this->assertSame($params['name'], $collection->getProperty('name')); | |||||
$this->assertSame($params['deviceId'], $collection->getProperty('deviceId')); | |||||
} | |||||
/** | |||||
* Test creating collections (POST /api/v4/fs?type=collection) | |||||
*/ | |||||
public function testStoreCollectionMetadata(): void | |||||
{ | |||||
$john = $this->getTestUser('john@kolab.org'); | |||||
$params = [ | |||||
'name' => "MyTestCollection", | |||||
'deviceId' => "myDeviceId", | |||||
'collectionType' => "photoalbum", | |||||
'deduplicate-property' => "localId", | |||||
'deduplicate-value' => "myDeviceId:localId", | |||||
'property-localId' => "myDeviceId:localId", | |||||
]; | |||||
$response = $this->actingAs($john)->post("api/v4/fs?type=collection", $params); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$this->assertSame('success', $json['status']); | |||||
$collection = Item::find($json['id']); | |||||
$this->assertSame(Item::TYPE_COLLECTION, $collection->type); | |||||
$this->assertSame($params['name'], $collection->getProperty('name')); | |||||
$this->assertSame($params['deviceId'], $collection->getProperty('deviceId')); | |||||
$this->assertSame($params['collectionType'], $collection->getProperty('collectionType')); | |||||
$this->assertSame($params['property-localId'], $collection->getProperty('localId')); | |||||
// Deduplicate but update the name and parent | |||||
$parent = $this->getTestCollection($john, 'Parent'); | |||||
$params = [ | |||||
'name' => "MyTestCollection2", | |||||
'deviceId' => "myDeviceId", | |||||
'parent' => $parent->id, | |||||
'collectionType' => "photoalbum", | |||||
'deduplicate-property' => "localId", | |||||
'deduplicate-value' => "myDeviceId:localId", | |||||
]; | |||||
$response = $this->actingAs($john)->post("api/v4/fs?type=collection", $params); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$this->assertSame('success', $json['status']); | |||||
$this->assertSame($collection->id, $json['id']); | |||||
$this->assertSame($params['name'], $collection->getProperty('name')); | |||||
// Deduplicate again, but without changes | |||||
$parent = $this->getTestCollection($john, 'Parent'); | |||||
$response = $this->actingAs($john)->post("api/v4/fs?type=collection", $params); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$this->assertSame('success', $json['status']); | |||||
} | |||||
/** | |||||
* Test deleting collections (DELETE /api/v4/fs/<collection-id>) | |||||
*/ | |||||
public function testDeleteCollection(): void | |||||
{ | |||||
$john = $this->getTestUser('john@kolab.org'); | |||||
$collection = $this->getTestCollection($john, 'Teśt content'); | |||||
// File owner access | |||||
$response = $this->actingAs($john)->delete("api/v4/fs/{$collection->id}"); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$this->assertSame('success', $json['status']); | |||||
$this->assertSame("Collection deleted successfully.", $json['message']); | |||||
$this->assertSame(null, Item::find($collection->id)); | |||||
} | |||||
/** | |||||
* Test store item relations (POST /api/v4/fs) | |||||
*/ | |||||
public function testStoreRelation(): void | |||||
{ | |||||
$john = $this->getTestUser('john@kolab.org'); | |||||
$collection = $this->getTestCollection($john, 'My Test Collection'); | |||||
$body = "test content"; | |||||
$headers = ["X-Kolab-Parents" => implode(',', [$collection->id])]; | |||||
$response = $this->sendRawBody($john, 'POST', "api/v4/fs?name=test.txt", $headers, $body); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$newItem = Item::find($json['id']); | |||||
$this->assertNotNull($newItem); | |||||
$this->assertSame(1, $newItem->parents()->count()); | |||||
$this->assertSame($collection->id, $newItem->parents()->first()->id); | |||||
$collection2 = $this->getTestCollection($john, 'My Test Collection2'); | |||||
$headers = ["X-Kolab-Parents" => implode(',', [$collection->id, $collection2->id])]; | |||||
$response = $this->sendRawBody($john, 'POST', "api/v4/fs?name=test2.txt", $headers, $body); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$newItem = Item::find($json['id']); | |||||
$this->assertNotNull($newItem); | |||||
$this->assertSame(2, $newItem->parents()->count()); | |||||
} | |||||
/** | |||||
* Test store item relations (POST /api/v4/fs) | |||||
*/ | |||||
public function testStoreRelationParameter(): void | |||||
{ | |||||
$john = $this->getTestUser('john@kolab.org'); | |||||
$collection = $this->getTestCollection($john, 'My Test Collection'); | |||||
$body = "test content"; | |||||
$response = $this->sendRawBody($john, 'POST', "api/v4/fs?name=test.txt&parent={$collection->id}", [], $body); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$newItem = Item::find($json['id']); | |||||
$this->assertNotNull($newItem); | |||||
$this->assertSame(1, $newItem->parents()->count()); | |||||
$this->assertSame($collection->id, $newItem->parents()->first()->id); | |||||
} | |||||
/** | |||||
* Test update item relations (PUT /api/v4/fs/$itemid) | |||||
* Add/Remove/Set | |||||
*/ | |||||
public function testUpdateRelation(): void | |||||
{ | |||||
$john = $this->getTestUser('john@kolab.org'); | |||||
$file = $this->getTestFile($john, 'test1.txt', 'Teśt content1', ['mimetype' => 'plain/text']); | |||||
$collection1 = $this->getTestCollection($john, 'My Test Collection'); | |||||
$collection2 = $this->getTestCollection($john, 'My Test Collection2'); | |||||
// Add parents | |||||
$headers = ["X-Kolab-Add-Parents" => implode(',', [$collection1->id])]; | |||||
$response = $this->sendRawBody($john, 'PUT', "api/v4/fs/{$file->id}", $headers, ''); | |||||
$response->assertStatus(200); | |||||
$this->assertSame('success', $response->json()['status']); | |||||
$parents = $file->parents()->get(); | |||||
$this->assertSame(1, count($parents)); | |||||
$this->assertSame($collection1->id, $parents->first()->id); | |||||
// Set parents | |||||
$headers = ["X-Kolab-Parents" => implode(',', [$collection1->id, $collection2->id])]; | |||||
$response = $this->sendRawBody($john, 'PUT', "api/v4/fs/{$file->id}", $headers, ''); | |||||
$response->assertStatus(200); | |||||
$this->assertSame('success', $response->json()['status']); | |||||
$parents = $file->parents()->get(); | |||||
$this->assertSame(2, count($parents)); | |||||
// Remove parents | |||||
$headers = ["X-Kolab-Remove-Parents" => implode(',', [$collection1->id])]; | |||||
$response = $this->sendRawBody($john, 'PUT', "api/v4/fs/{$file->id}", $headers, ''); | |||||
$response->assertStatus(200); | |||||
$this->assertSame('success', $response->json()['status']); | |||||
$parents = $file->parents()->get(); | |||||
$this->assertSame(1, count($parents)); | |||||
$this->assertSame($collection2->id, $parents->first()->id); | |||||
} | |||||
public function testListChildren(): void | |||||
{ | |||||
$john = $this->getTestUser('john@kolab.org'); | |||||
$file1 = $this->getTestFile($john, 'test1.txt', 'Teśt content1', ['mimetype' => 'plain/text']); | |||||
$file2 = $this->getTestFile($john, 'test2.txt', 'Teśt content2', ['mimetype' => 'plain/text']); | |||||
$collection = $this->getTestCollection($john, 'My Test Collection'); | |||||
$collection->children()->attach($file1); | |||||
// List files in collection | |||||
$response = $this->actingAs($john)->get("api/v4/fs?parent={$collection->id}"); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$list = $json['list']; | |||||
$this->assertSame(1, count($list)); | |||||
$this->assertSame($file1->id, $list[0]['id']); | |||||
// List files not in a collection | |||||
$response = $this->actingAs($john)->get("api/v4/fs?type=file"); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$list = $json['list']; | |||||
$this->assertSame(1, count($list)); | |||||
$this->assertSame($file2->id, $list[0]['id']); | |||||
// Remove from collection | |||||
$collection->children()->detach($file1); | |||||
$response = $this->actingAs($john)->get("api/v4/fs?parent={$collection->id}"); | |||||
$response->assertStatus(200); | |||||
$json = $response->json(); | |||||
$this->assertSame(0, count($response->json()['list'])); | |||||
} | |||||
} | } |