Skip to content

Commit

Permalink
refactor(nextcloud)!: Migrate to DAV v2 endpoint for WebDAV
Browse files Browse the repository at this point in the history
Signed-off-by: provokateurin <kate@provokateurin.de>
  • Loading branch information
provokateurin committed Oct 19, 2024
1 parent 4ad2560 commit af1f3d3
Show file tree
Hide file tree
Showing 47 changed files with 364 additions and 335 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,19 @@ class _FilesBrowserBloc extends InteractiveBloc implements FilesBrowserBloc {
await RequestManager.instance.wrap(
account: account,
subject: files,
getRequest: () => account.client.webdav.propfind_Request(
uri,
prop: const webdav.WebDavPropWithoutValues.fromBools(
davGetcontenttype: true,
davGetetag: true,
davGetlastmodified: true,
ncHasPreview: true,
ncMetadataBlurhash: true,
ocSize: true,
ocFavorite: true,
),
depth: webdav.WebDavDepth.one,
),
getRequest: () => account.client.webdav(account.username).propfind_Request(
uri,
prop: const webdav.WebDavPropWithoutValues.fromBools(
davGetcontenttype: true,
davGetetag: true,
davGetlastmodified: true,
ncHasPreview: true,
ncMetadataBlurhash: true,
ocSize: true,
ocFavorite: true,
),
depth: webdav.WebDavDepth.one,
),
converter: const webdav.WebDavResponseConverter(),
unwrap: (response) => BuiltList<webdav.WebDavFile>.build((b) {
for (final file in response.toWebDavFiles()) {
Expand Down
40 changes: 20 additions & 20 deletions packages/neon_framework/packages/files_app/lib/src/blocs/files.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class _FilesBloc extends InteractiveBloc implements FilesBloc {
file: File(localPath),
);
tasks.add(tasks.value.rebuild((b) => b.add(task)));
await uploadQueue.add(() => task.execute(account.client));
await uploadQueue.add(() => task.execute(account.client.webdav(account.username)));
tasks.add(tasks.value.rebuild((b) => b.remove(task)));
},
disableTimeout: true,
Expand All @@ -123,7 +123,7 @@ class _FilesBloc extends InteractiveBloc implements FilesBloc {
bytes: bytes,
);
tasks.add(tasks.value.rebuild((b) => b.add(task)));
await uploadQueue.add(() => task.execute(account.client));
await uploadQueue.add(() => task.execute(account.client.webdav(account.username)));
tasks.add(tasks.value.rebuild((b) => b.remove(task)));
},
disableTimeout: true,
Expand Down Expand Up @@ -166,52 +166,52 @@ class _FilesBloc extends InteractiveBloc implements FilesBloc {

@override
Future<void> delete(webdav.PathUri uri) async {
await wrapAction(() async => account.client.webdav.delete(uri));
await wrapAction(() async => account.client.webdav(account.username).delete(uri));
}

@override
Future<void> rename(webdav.PathUri uri, String name) async {
await wrapAction(
() async => account.client.webdav.move(
uri,
uri.rename(name),
),
() async => account.client.webdav(account.username).move(
uri,
uri.rename(name),
),
);
}

@override
Future<void> move(webdav.PathUri uri, webdav.PathUri destination) async {
await wrapAction(() async => account.client.webdav.move(uri, destination));
await wrapAction(() async => account.client.webdav(account.username).move(uri, destination));
}

@override
Future<void> copy(webdav.PathUri uri, webdav.PathUri destination) async {
await wrapAction(() async => account.client.webdav.copy(uri, destination));
await wrapAction(() async => account.client.webdav(account.username).copy(uri, destination));
}

@override
Future<void> addFavorite(webdav.PathUri uri) async {
await wrapAction(
() async => account.client.webdav.proppatch(
uri,
set: const webdav.WebDavProp(ocFavorite: true),
),
() async => account.client.webdav(account.username).proppatch(
uri,
set: const webdav.WebDavProp(ocFavorite: true),
),
);
}

@override
Future<void> removeFavorite(webdav.PathUri uri) async {
await wrapAction(
() async => account.client.webdav.proppatch(
uri,
set: const webdav.WebDavProp(ocFavorite: false),
),
() async => account.client.webdav(account.username).proppatch(
uri,
set: const webdav.WebDavProp(ocFavorite: false),
),
);
}

@override
Future<void> createFolder(webdav.PathUri uri) async {
await wrapAction(() async => account.client.webdav.mkcol(uri));
await wrapAction(() async => account.client.webdav(account.username).mkcol(uri));
}

Future<File> cacheFile(webdav.PathUri uri, String etag) async {
Expand All @@ -236,7 +236,7 @@ class _FilesBloc extends InteractiveBloc implements FilesBloc {
);

tasks.add(tasks.value.rebuild((b) => b.add(task)));
await downloadQueue.add(() => task.execute(account.client));
await downloadQueue.add(() => task.execute(account.client.webdav(account.username)));
tasks.add(tasks.value.rebuild((b) => b.remove(task)));
}

Expand All @@ -248,7 +248,7 @@ class _FilesBloc extends InteractiveBloc implements FilesBloc {
final future = task.stream.forEach(buffer.add);

tasks.add(tasks.value.rebuild((b) => b.add(task)));
await downloadQueue.add(() => task.execute(account.client));
await downloadQueue.add(() => task.execute(account.client.webdav(account.username)));
tasks.add(tasks.value.rebuild((b) => b.remove(task)));

await future;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:typed_data';

import 'package:meta/meta.dart';
import 'package:nextcloud/nextcloud.dart';
import 'package:nextcloud/webdav.dart' as webdav;
import 'package:timezone/timezone.dart' as tz;
import 'package:universal_io/io.dart';
Expand Down Expand Up @@ -66,8 +65,8 @@ class FilesDownloadTaskIO extends FilesTaskIO implements FilesDownloadTask {
required super.file,
});

Future<void> execute(NextcloudClient client) async {
await client.webdav.getFile(
Future<void> execute(webdav.WebDavClient client) async {
await client.getFile(
uri,
file,
onProgress: progressController.add,
Expand All @@ -90,8 +89,8 @@ class FilesUploadTaskIO extends FilesTaskIO implements FilesUploadTask {
@override
late tz.TZDateTime lastModified = tz.TZDateTime.from(_stat.modified, tz.UTC);

Future<void> execute(NextcloudClient client) async {
await client.webdav.putFile(
Future<void> execute(webdav.WebDavClient client) async {
await client.putFile(
file,
_stat,
uri,
Expand All @@ -107,8 +106,8 @@ class FilesDownloadTaskMemory extends FilesTaskMemory implements FilesDownloadTa
required super.uri,
});

Future<void> execute(NextcloudClient client) async {
final stream = await client.webdav.getStream(
Future<void> execute(webdav.WebDavClient client) async {
final stream = await client.getStream(
uri,
onProgress: progressController.add,
);
Expand All @@ -133,8 +132,8 @@ class FilesUploadTaskMemory extends FilesTaskMemory implements FilesUploadTask {
@override
final tz.TZDateTime? lastModified;

Future<void> execute(NextcloudClient client) async {
await client.webdav.putStream(
Future<void> execute(webdav.WebDavClient client) async {
await client.putStream(
_stream.stream,
uri,
lastModified: lastModified,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class WebDavFile {
isAbsolute: false,
isDirectory: href.isDirectory,
// The server might be hosted at a subpath, so we don't have a fixed number of path segments to remove
pathSegments: href.pathSegments.sublist(href.pathSegments.indexOf('remote.php') + 2),
pathSegments: href.pathSegments.sublist(href.pathSegments.indexOf('remote.php') + 4),
);
}();

Expand Down
7 changes: 2 additions & 5 deletions packages/nextcloud/lib/src/api/webdav/utils/webdav_uri.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import 'package:meta/meta.dart';
import 'package:nextcloud/src/api/webdav/webdav.dart';

/// Base path used on the server
final webdavBase = PathUri.parse('/remote.php/webdav');

/// Constructs the uri for a webdav request for a given server [baseURL] and file [path].
@internal
Uri constructUri(Uri baseURL, [PathUri? path]) {
final segments = baseURL.pathSegments.toList()..addAll(webdavBase.pathSegments);
Uri constructUri(String username, Uri baseURL, [PathUri? path]) {
final segments = baseURL.pathSegments.toList()..addAll(['remote.php', 'dav', 'files', username]);
if (path != null) {
segments.addAll(path.pathSegments);
}
Expand Down
15 changes: 12 additions & 3 deletions packages/nextcloud/lib/src/api/webdav/webdav_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class WebDavClient extends DynamiteClient {
/// triggered, when cookies are also sent.
WebDavClient(
super.baseURL, {
required this.username,
http.Client? httpClient,
super.authentications,
bool useCSRFClient = true,
Expand All @@ -44,14 +45,22 @@ class WebDavClient extends DynamiteClient {
);

/// Creates a new [WebDavClient] from another [client].
WebDavClient.fromClient(DynamiteClient client)
: this(
WebDavClient.fromClient(
DynamiteClient client, {
required String username,
}) : this(
client.baseURL,
username: username,
httpClient: client.httpClient,
authentications: client.authentications,
);

Uri _constructUri([PathUri? path]) => constructUri(baseURL, path);
/// The username of the user used for all requests.
final String username;

Uri _constructUri([PathUri? path]) {
return constructUri(username, baseURL, path);
}

/// Returns a request to query the WebDAV capabilities of the server.
///
Expand Down
17 changes: 16 additions & 1 deletion packages/nextcloud/lib/webdav.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,23 @@ export 'package:nextcloud/src/api/webdav/webdav.dart'

/// Client for WebDAV.
extension WebDAVExtension on NextcloudClient {
static final _username = Expando<String>();
static final _webdav = Expando<WebDavClient>();

/// Client for WebDAV.
WebDavClient get webdav => _webdav[this] ??= WebDavClient.fromClient(this);
///
/// To acquire the [username] of the user you can use the provisioning_api.
WebDavClient webdav(String username) {
if (_username[this] != null && username != _username[this]) {
throw ArgumentError(
'You can not provide a different username than on the first invocation. Got "$username" but expected "${_username[this]}".',
);
}

_username[this] ??= username;
return _webdav[this] ??= WebDavClient.fromClient(
this,
username: username,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ final class NextcloudTester {
NextcloudTester({
required String appName,
required Version version,
String username = defaultTestUsername,
}) : _preset = (name: appName, version: version),
_username = username;
this.username = defaultTestUsername,
}) : _preset = (name: appName, version: version);

final Preset _preset;

final String _username;
/// The username of the configured user.
final String username;

/// The app version tested.
Version get version => _preset.version;
Expand Down Expand Up @@ -63,7 +63,7 @@ final class NextcloudTester {
/// Initializes the tester creating the target and default client.
Future<void> init() async {
_target = await TestTargetFactory.instance.spawn(_preset);
_client = await _target!.createClient(username: _username);
_client = await _target!.createClient(username: username);
}

/// Closes the tester.
Expand Down
4 changes: 2 additions & 2 deletions packages/nextcloud/test/api/core/core_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ void main() {
group('Preview', () {
setUp(() async {
final file = File('test/files/test.png');
await tester.client.webdav.putFile(file, file.statSync(), webdav.PathUri.parse('preview.png'));
await tester.client.webdav(tester.username).putFile(file, file.statSync(), webdav.PathUri.parse('preview.png'));
resetFixture();
});

tearDown(() async {
closeFixture();
await tester.client.webdav.delete(webdav.PathUri.parse('preview.png'));
await tester.client.webdav(tester.username).delete(webdav.PathUri.parse('preview.png'));
});

test('Get', () async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ void main() {
group('shareapi', () {
setUp(() async {
final file = File('test/files/test.png');
await tester.client.webdav.putFile(file, file.statSync(), webdav.PathUri.parse('create-share.png'));
await tester.client
.webdav(tester.username)
.putFile(file, file.statSync(), webdav.PathUri.parse('create-share.png'));
resetFixture();
});

tearDown(() async {
closeFixture();
await tester.client.webdav.delete(webdav.PathUri.parse('create-share.png'));
await tester.client.webdav(tester.username).delete(webdav.PathUri.parse('create-share.png'));
});

test('createShare', () async {
Expand Down
Loading

0 comments on commit af1f3d3

Please sign in to comment.