diff --git a/app/Fileshare/ConnectionTypes/NextcloudConnection.php b/app/Fileshare/ConnectionTypes/NextcloudConnection.php new file mode 100644 index 00000000..4d4c6eb6 --- /dev/null +++ b/app/Fileshare/ConnectionTypes/NextcloudConnection.php @@ -0,0 +1,44 @@ +withBasicAuth($this->user, $this->password) + ->withHeaders(['OCS-APIRequest' => 'true']) + ->acceptJson() + ->get($this->baseUrl . '/ocs/v2.php/cloud/capabilities'); + return $response->ok(); + } catch (ConnectionException $e) { + return false; + } + } + + public static function title(): string + { + return 'Nextcloud'; + } + + public function getFilesystem(): FilesystemAdapter + { + $adapter = new WebDAVAdapter(new Client([ + 'baseUri' => $this->baseUrl . '/remote.php/dav/files/' . $this->user, + 'userName' => $this->user, + 'password' => $this->password, + ]), '/remote.php/dav/files/' . $this->user); + + return new FilesystemAdapter(new Filesystem($adapter), $adapter); + } +} diff --git a/tests/Fileshare/FileshareFilesActionTest.php b/tests/Fileshare/FileshareFilesActionTest.php index d16ce8b3..e5f3741c 100644 --- a/tests/Fileshare/FileshareFilesActionTest.php +++ b/tests/Fileshare/FileshareFilesActionTest.php @@ -2,6 +2,7 @@ namespace Tests\Fileshare; +use App\Fileshare\ConnectionTypes\NextcloudConnection; use App\Fileshare\ConnectionTypes\OwncloudConnection; use App\Fileshare\Models\Fileshare; use Tests\FileshareTestCase; @@ -10,11 +11,11 @@ class FileshareFilesActionTest extends FileshareTestCase { public function testItGetsFilesForAConnection(): void { - $this->withoutExceptionHandling()->login()->loginNami()->withOwncloudUser('badenpowell', 'secret') + $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'ieH2auj5AhKaengoD4Taeng9o') ->withDirs('badenpowell', ['/pictures', '/lala']); $connection = Fileshare::factory() - ->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'secret', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')])) + ->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'ieH2auj5AhKaengoD4Taeng9o', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')])) ->create(); $this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), [ @@ -31,11 +32,11 @@ class FileshareFilesActionTest extends FileshareTestCase public function testItGetsSubdirectories(): void { - $this->withoutExceptionHandling()->login()->loginNami()->withOwncloudUser('badenpowell', 'secret') + $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'ieH2auj5AhKaengoD4Taeng9o') ->withDirs('badenpowell', ['/pictures', '/lala', '/lala/dd', '/lala/ff']); $connection = Fileshare::factory() - ->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'secret', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')])) + ->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'ieH2auj5AhKaengoD4Taeng9o', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')])) ->create(); $this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), ['parent' => '/pictures'])->assertJsonCount(0, 'data'); @@ -51,11 +52,11 @@ class FileshareFilesActionTest extends FileshareTestCase public function testItGetsSubdirectoriesOfSubdirectory(): void { - $this->withoutExceptionHandling()->login()->loginNami()->withOwncloudUser('badenpowell', 'secret') + $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'ieH2auj5AhKaengoD4Taeng9o') ->withDirs('badenpowell', ['/lala', '/lala/dd', '/lala/dd/ee']); $connection = Fileshare::factory() - ->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'secret', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')])) + ->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'ieH2auj5AhKaengoD4Taeng9o', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')])) ->create(); $this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), ['parent' => '/lala/dd']) @@ -67,14 +68,51 @@ class FileshareFilesActionTest extends FileshareTestCase public function testItGetsFilesWithDot(): void { - $this->withoutExceptionHandling()->login()->loginNami()->withOwncloudUser('badenpowell', 'secret') + $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'ieH2auj5AhKaengoD4Taeng9o') ->withDirs('badenpowell', ['/1. aa']); $connection = Fileshare::factory() - ->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'secret', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')])) + ->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'ieH2auj5AhKaengoD4Taeng9o', 'base_url' => env('TEST_OWNCLOUD_DOMAIN')])) ->create(); $this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), ['parent' => '/']) ->assertJsonPath('data.0.name', '1. aa'); } + + public function testItGetsFilesFromNextcloudConnection(): void + { + $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'ohke5ko7ohBae8aiPh7fuu6ka') + ->withDirs('badenpowell', ['/pictures', '/lala']); + + $connection = Fileshare::factory() + ->type(NextcloudConnection::from(['user' => 'badenpowell', 'password' => 'ohke5ko7ohBae8aiPh7fuu6ka', 'base_url' => env('TEST_NEXTCLOUD_DOMAIN')])) + ->create(); + + $this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), [ + 'parent' => null, + ]) + ->assertJsonCount(2, 'data') + ->assertJsonPath('data.0.name', 'lala') + ->assertJsonPath('data.0.path', '/lala') + ->assertJsonPath('data.0.parent', '/') + ->assertJsonPath('data.1.name', 'pictures') + ->assertJsonPath('data.1.path', '/pictures') + ->assertJsonPath('data.1.parent', '/'); + } + + public function testItGetsNextcloudSubdirectoriesOfSubdirectory(): void + { + $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'ailiew7AhshiWae4va9OphieN') + ->withDirs('badenpowell', ['/lala', '/lala/dd', '/lala/dd/ee']); + + $connection = Fileshare::factory() + ->type(OwncloudConnection::from(['user' => 'badenpowell', 'password' => 'ailiew7AhshiWae4va9OphieN', 'base_url' => env('TEST_NEXTCLOUD_DOMAIN')])) + ->create(); + + $this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), ['parent' => '/lala/dd']) + ->assertJsonCount(1, 'data') + ->assertJsonPath('data.0.name', 'ee') + ->assertJsonPath('data.0.path', '/lala/dd/ee') + ->assertJsonPath('data.0.parent', '/lala/dd'); + } } diff --git a/tests/Fileshare/FileshareStoreActionTest.php b/tests/Fileshare/FileshareStoreActionTest.php index 46acf891..01980ff1 100644 --- a/tests/Fileshare/FileshareStoreActionTest.php +++ b/tests/Fileshare/FileshareStoreActionTest.php @@ -2,6 +2,7 @@ namespace Tests\Fileshare; +use App\Fileshare\ConnectionTypes\NextcloudConnection; use App\Fileshare\ConnectionTypes\OwncloudConnection; use App\Fileshare\Models\Fileshare; use Tests\FileshareTestCase; @@ -10,7 +11,7 @@ class FileshareStoreActionTest extends FileshareTestCase { public function testItStoresAConnection(): void { - $this->withoutExceptionHandling()->login()->loginNami()->withOwncloudUser('badenpowell', 'secret'); + $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'secret'); $this->post(route('fileshare.store'), [ 'name' => 'Lala', @@ -58,4 +59,25 @@ class FileshareStoreActionTest extends FileshareTestCase ] ])->assertJsonValidationErrors(['name' => 'Name ist erforderlich.']); } + + public function testItStoresNextcloudConnection(): void + { + $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'uaLeitu3eecoweePhaeGei3Oa'); + + $this->post(route('fileshare.store'), [ + 'name' => 'Lala', + 'type' => NextcloudConnection::class, + 'config' => [ + 'user' => 'badenpowell', + 'password' => 'uaLeitu3eecoweePhaeGei3Oa', + 'base_url' => env('TEST_NEXTCLOUD_DOMAIN'), + ] + ])->assertOk(); + + $connection = Fileshare::firstOrFail(); + $this->assertEquals('badenpowell', $connection->type->user); + $this->assertEquals('uaLeitu3eecoweePhaeGei3Oa', $connection->type->password); + $this->assertEquals(env('TEST_NEXTCLOUD_DOMAIN'), $connection->type->baseUrl); + $this->assertEquals('Lala', $connection->name); + } } diff --git a/tests/Fileshare/docker-compose.yml b/tests/Fileshare/docker-compose.yml index ccf241c0..3acd9c26 100644 --- a/tests/Fileshare/docker-compose.yml +++ b/tests/Fileshare/docker-compose.yml @@ -6,7 +6,8 @@ services: ports: - 5566:8080 depends_on: - - mariadb + mariadb: + condition: service_healthy environment: - OWNCLOUD_DOMAIN=http://localhost:5566 - OWNCLOUD_TRUSTED_DOMAINS= @@ -45,3 +46,36 @@ services: retries: 5 volumes: - ./oc_tmp/db:/var/lib/mysql + + nextclouddb: + image: mariadb:10.6 + command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW + healthcheck: + test: ['CMD', 'mysqladmin', 'ping', '-u', 'root', '--password=secret'] + interval: 10s + timeout: 5s + retries: 5 + volumes: + - ./oc_tmp/ncdb:/var/lib/mysql + environment: + - MYSQL_ROOT_PASSWORD=secret + - MYSQL_PASSWORD=secret + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + + app: + image: nextcloud + restart: always + depends_on: + nextclouddb: + condition: service_healthy + ports: + - 5567:80 + environment: + - MYSQL_PASSWORD=secret + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + - MYSQL_HOST=nextclouddb + - NEXTCLOUD_ADMIN_USER=admin + - NEXTCLOUD_ADMIN_PASSWORD=admin + - NEXTCLOUD_TRUSTED_DOMAINS= diff --git a/tests/FileshareTestCase.php b/tests/FileshareTestCase.php index 5aa51f15..5ab7afc2 100644 --- a/tests/FileshareTestCase.php +++ b/tests/FileshareTestCase.php @@ -2,16 +2,16 @@ namespace Tests; +use App\Fileshare\ConnectionTypes\ConnectionType; +use App\Fileshare\ConnectionTypes\NextcloudConnection; +use App\Fileshare\ConnectionTypes\OwncloudConnection; use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Http\Client\PendingRequest; use Illuminate\Support\Facades\Http; -use Illuminate\Support\Facades\Storage; -use League\Flysystem\DirectoryAttributes; use League\Flysystem\Filesystem; use League\Flysystem\WebDAV\WebDAVAdapter; use Sabre\DAV\Client; -use Throwable; abstract class FileshareTestCase extends TestCase { @@ -29,25 +29,42 @@ abstract class FileshareTestCase extends TestCase { parent::setUp(); - foreach ($this->http()->get('/ocs/v1.php/cloud/users?format=json')->json('ocs.data.users') as $user) { + foreach ($this->http(OwncloudConnection::class)->get('/ocs/v1.php/cloud/users?format=json')->json('ocs.data.users') as $user) { if ($user === $this->adminUser) { continue; } - $this->http()->delete('/ocs/v1.php/cloud/users/' . $user); + $this->http(OwncloudConnection::class)->delete('/ocs/v1.php/cloud/users/' . $user); + } + + foreach ($this->http(NextcloudConnection::class)->get('/ocs/v2.php/cloud/users')->json('ocs.data.users') as $user) { + if ($user === $this->adminUser) { + continue; + } + $this->http(NextcloudConnection::class)->delete('/ocs/v2.php/cloud/users/' . $user); } } - public function withOwncloudUser(string $username, string $password): self + public function withUser(string $username, string $password): self { $this->passwords[$username] = $password; - $this->http()->asForm()->post('/ocs/v1.php/cloud/users?format=json', ['password' => $password, 'userid' => $username]); + $this->http(OwncloudConnection::class)->asForm()->post('/ocs/v1.php/cloud/users?format=json', ['password' => $password, 'userid' => $username]); + $this->http(NextcloudConnection::class)->post('/ocs/v2.php/cloud/users', ['password' => $password, 'userid' => $username]); return $this; } - private function http(): PendingRequest + /** + * @param class-string $connection + */ + private function http(string $connection): PendingRequest { - return Http::withOptions(['base_uri' => env('TEST_OWNCLOUD_DOMAIN')])->withBasicAuth($this->adminUser, $this->adminPassword)->acceptJson(); + if ($connection === OwncloudConnection::class) { + return Http::withOptions(['base_uri' => env('TEST_OWNCLOUD_DOMAIN')])->withBasicAuth($this->adminUser, $this->adminPassword)->acceptJson(); + } + + if ($connection === NextcloudConnection::class) { + return Http::withOptions(['base_uri' => env('TEST_NEXTCLOUD_DOMAIN')])->withHeaders(['OCS-APIRequest' => 'true'])->withBasicAuth($this->adminUser, $this->adminPassword)->acceptJson(); + } } /** @@ -55,30 +72,45 @@ abstract class FileshareTestCase extends TestCase */ protected function withDirs(string $username, array $dirs): self { - $adapter = $this->adapter($username); + foreach ([NextcloudConnection::class, OwncloudConnection::class] as $connection) { + $adapter = $this->adapter($username, $connection); - foreach ($adapter->directories('/') as $directory) { - $adapter->deleteDirectory($directory); - } + foreach ($adapter->directories('/') as $directory) { + $adapter->deleteDirectory($directory); + } - foreach ($adapter->files('/') as $file) { - $adapter->delete($file); - } + foreach ($adapter->files('/') as $file) { + $adapter->delete($file); + } - foreach ($dirs as $dir) { - $adapter->makeDirectory($dir); + foreach ($dirs as $dir) { + $adapter->makeDirectory($dir); + } } return $this; } - private function adapter(string $username): FilesystemAdapter + /** + * @param class-string $connection + */ + private function adapter(string $username, string $connection): FilesystemAdapter { - $adapter = new WebDAVAdapter(new Client([ - 'baseUri' => env('TEST_OWNCLOUD_DOMAIN') . '/remote.php/dav/files/' . $username, - 'userName' => $username, - 'password' => $this->passwords[$username], - ]), '/remote.php/dav/files/' . $username); + if ($connection === OwncloudConnection::class) { + $adapter = new WebDAVAdapter(new Client([ + 'baseUri' => env('TEST_OWNCLOUD_DOMAIN') . '/remote.php/dav/files/' . $username, + 'userName' => $username, + 'password' => $this->passwords[$username], + ]), '/remote.php/dav/files/' . $username); + } + + if ($connection === NextcloudConnection::class) { + $adapter = new WebDAVAdapter(new Client([ + 'baseUri' => env('TEST_NEXTCLOUD_DOMAIN') . '/remote.php/dav/files/' . $username, + 'userName' => $username, + 'password' => $this->passwords[$username], + ]), '/remote.php/dav/files/' . $username); + } return new FilesystemAdapter(new Filesystem($adapter), $adapter); }