Add nextcloud connections
continuous-integration/drone/push Build was killed Details

This commit is contained in:
philipp lang 2024-07-13 22:30:34 +02:00
parent 74867cb09f
commit 2b48f42734
5 changed files with 204 additions and 34 deletions

View File

@ -0,0 +1,44 @@
<?php
namespace App\Fileshare\ConnectionTypes;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Http;
use League\Flysystem\Filesystem;
use League\Flysystem\WebDAV\WebDAVAdapter;
use Sabre\DAV\Client;
class NextcloudConnection extends OwncloudConnection
{
public function check(): bool
{
try {
$response = Http::withoutVerifying()
->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);
}
}

View File

@ -2,6 +2,7 @@
namespace Tests\Fileshare; namespace Tests\Fileshare;
use App\Fileshare\ConnectionTypes\NextcloudConnection;
use App\Fileshare\ConnectionTypes\OwncloudConnection; use App\Fileshare\ConnectionTypes\OwncloudConnection;
use App\Fileshare\Models\Fileshare; use App\Fileshare\Models\Fileshare;
use Tests\FileshareTestCase; use Tests\FileshareTestCase;
@ -10,11 +11,11 @@ class FileshareFilesActionTest extends FileshareTestCase
{ {
public function testItGetsFilesForAConnection(): void public function testItGetsFilesForAConnection(): void
{ {
$this->withoutExceptionHandling()->login()->loginNami()->withOwncloudUser('badenpowell', 'secret') $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'ieH2auj5AhKaengoD4Taeng9o')
->withDirs('badenpowell', ['/pictures', '/lala']); ->withDirs('badenpowell', ['/pictures', '/lala']);
$connection = Fileshare::factory() $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(); ->create();
$this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), [ $this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), [
@ -31,11 +32,11 @@ class FileshareFilesActionTest extends FileshareTestCase
public function testItGetsSubdirectories(): void 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']); ->withDirs('badenpowell', ['/pictures', '/lala', '/lala/dd', '/lala/ff']);
$connection = Fileshare::factory() $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(); ->create();
$this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), ['parent' => '/pictures'])->assertJsonCount(0, 'data'); $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 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']); ->withDirs('badenpowell', ['/lala', '/lala/dd', '/lala/dd/ee']);
$connection = Fileshare::factory() $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(); ->create();
$this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), ['parent' => '/lala/dd']) $this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), ['parent' => '/lala/dd'])
@ -67,14 +68,51 @@ class FileshareFilesActionTest extends FileshareTestCase
public function testItGetsFilesWithDot(): void public function testItGetsFilesWithDot(): void
{ {
$this->withoutExceptionHandling()->login()->loginNami()->withOwncloudUser('badenpowell', 'secret') $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'ieH2auj5AhKaengoD4Taeng9o')
->withDirs('badenpowell', ['/1. aa']); ->withDirs('badenpowell', ['/1. aa']);
$connection = Fileshare::factory() $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(); ->create();
$this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), ['parent' => '/']) $this->postJson(route('api.fileshare.files', ['fileshare' => $connection]), ['parent' => '/'])
->assertJsonPath('data.0.name', '1. aa'); ->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');
}
} }

View File

@ -2,6 +2,7 @@
namespace Tests\Fileshare; namespace Tests\Fileshare;
use App\Fileshare\ConnectionTypes\NextcloudConnection;
use App\Fileshare\ConnectionTypes\OwncloudConnection; use App\Fileshare\ConnectionTypes\OwncloudConnection;
use App\Fileshare\Models\Fileshare; use App\Fileshare\Models\Fileshare;
use Tests\FileshareTestCase; use Tests\FileshareTestCase;
@ -10,7 +11,7 @@ class FileshareStoreActionTest extends FileshareTestCase
{ {
public function testItStoresAConnection(): void public function testItStoresAConnection(): void
{ {
$this->withoutExceptionHandling()->login()->loginNami()->withOwncloudUser('badenpowell', 'secret'); $this->withoutExceptionHandling()->login()->loginNami()->withUser('badenpowell', 'secret');
$this->post(route('fileshare.store'), [ $this->post(route('fileshare.store'), [
'name' => 'Lala', 'name' => 'Lala',
@ -58,4 +59,25 @@ class FileshareStoreActionTest extends FileshareTestCase
] ]
])->assertJsonValidationErrors(['name' => 'Name ist erforderlich.']); ])->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);
}
} }

View File

@ -6,7 +6,8 @@ services:
ports: ports:
- 5566:8080 - 5566:8080
depends_on: depends_on:
- mariadb mariadb:
condition: service_healthy
environment: environment:
- OWNCLOUD_DOMAIN=http://localhost:5566 - OWNCLOUD_DOMAIN=http://localhost:5566
- OWNCLOUD_TRUSTED_DOMAINS= - OWNCLOUD_TRUSTED_DOMAINS=
@ -45,3 +46,36 @@ services:
retries: 5 retries: 5
volumes: volumes:
- ./oc_tmp/db:/var/lib/mysql - ./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=

View File

@ -2,16 +2,16 @@
namespace Tests; namespace Tests;
use App\Fileshare\ConnectionTypes\ConnectionType;
use App\Fileshare\ConnectionTypes\NextcloudConnection;
use App\Fileshare\ConnectionTypes\OwncloudConnection;
use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Http\Client\PendingRequest; use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\DirectoryAttributes;
use League\Flysystem\Filesystem; use League\Flysystem\Filesystem;
use League\Flysystem\WebDAV\WebDAVAdapter; use League\Flysystem\WebDAV\WebDAVAdapter;
use Sabre\DAV\Client; use Sabre\DAV\Client;
use Throwable;
abstract class FileshareTestCase extends TestCase abstract class FileshareTestCase extends TestCase
{ {
@ -29,25 +29,42 @@ abstract class FileshareTestCase extends TestCase
{ {
parent::setUp(); 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) { if ($user === $this->adminUser) {
continue; 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->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; return $this;
} }
private function http(): PendingRequest /**
* @param class-string<ConnectionType> $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 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) { foreach ($adapter->directories('/') as $directory) {
$adapter->deleteDirectory($directory); $adapter->deleteDirectory($directory);
} }
foreach ($adapter->files('/') as $file) { foreach ($adapter->files('/') as $file) {
$adapter->delete($file); $adapter->delete($file);
} }
foreach ($dirs as $dir) { foreach ($dirs as $dir) {
$adapter->makeDirectory($dir); $adapter->makeDirectory($dir);
}
} }
return $this; return $this;
} }
private function adapter(string $username): FilesystemAdapter /**
* @param class-string<ConnectionType> $connection
*/
private function adapter(string $username, string $connection): FilesystemAdapter
{ {
$adapter = new WebDAVAdapter(new Client([ if ($connection === OwncloudConnection::class) {
'baseUri' => env('TEST_OWNCLOUD_DOMAIN') . '/remote.php/dav/files/' . $username, $adapter = new WebDAVAdapter(new Client([
'userName' => $username, 'baseUri' => env('TEST_OWNCLOUD_DOMAIN') . '/remote.php/dav/files/' . $username,
'password' => $this->passwords[$username], 'userName' => $username,
]), '/remote.php/dav/files/' . $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); return new FilesystemAdapter(new Filesystem($adapter), $adapter);
} }