diff --git a/packages/nextcloud/lib/src/webdav/client.dart b/packages/nextcloud/lib/src/webdav/client.dart index 1bce6929..d1aa4952 100644 --- a/packages/nextcloud/lib/src/webdav/client.dart +++ b/packages/nextcloud/lib/src/webdav/client.dart @@ -164,16 +164,12 @@ class WebDavClient { final DateTime? lastModified, final DateTime? created, }) => - _send( - 'PUT', - _constructPath(remotePath), - [200, 201, 204], - data: Stream.value(localData), - headers: _generateUploadHeaders( - lastModified: lastModified, - created: created, - contentLength: localData.lengthInBytes, - ), + uploadStream( + Stream.value(localData), + remotePath, + lastModified: lastModified, + created: created, + contentLength: localData.lengthInBytes, ); /// upload a new file with [localData] as content to [remotePath] @@ -197,15 +193,8 @@ class WebDavClient { ); /// download [remotePath] and store the response file contents to String - Future download(final String remotePath) async => Uint8List.fromList( - (await (await _send( - 'GET', - _constructPath(remotePath), - [200], - )) - .join()) - .codeUnits, - ); + Future download(final String remotePath) async => + Uint8List.fromList((await (await downloadStream(remotePath)).join()).codeUnits); /// download [remotePath] and store the response file contents to ByteStream Future downloadStream(final String remotePath) async => _send( diff --git a/packages/nextcloud/lib/src/webdav/file.dart b/packages/nextcloud/lib/src/webdav/file.dart index 5f3d8e1f..f864e2f9 100644 --- a/packages/nextcloud/lib/src/webdav/file.dart +++ b/packages/nextcloud/lib/src/webdav/file.dart @@ -71,11 +71,12 @@ class WebDavFile { /// Upload date of the file late final DateTime? uploadedDate = - props.ncuploadtime != null ? DateTime.fromMillisecondsSinceEpoch(props.ncuploadtime! * 1000) : null; + props.ncuploadtime != null ? DateTime.fromMillisecondsSinceEpoch(props.ncuploadtime! * 1000, isUtc: true) : null; /// Creation date of the file as provided by uploader - late final DateTime? createdDate = - props.nccreationtime != null ? DateTime.fromMillisecondsSinceEpoch(props.nccreationtime! * 1000) : null; + late final DateTime? createdDate = props.nccreationtime != null + ? DateTime.fromMillisecondsSinceEpoch(props.nccreationtime! * 1000, isUtc: true) + : null; /// Whether this file is marked as favorite late final bool? favorite = props.ocfavorite == null ? null : props.ocfavorite == 1; diff --git a/packages/nextcloud/lib/src/webdav/webdav.dart b/packages/nextcloud/lib/src/webdav/webdav.dart index 6a7932a5..981c520b 100644 --- a/packages/nextcloud/lib/src/webdav/webdav.dart +++ b/packages/nextcloud/lib/src/webdav/webdav.dart @@ -84,7 +84,7 @@ class WebDavPropertyupdate with _$WebDavPropertyupdateXmlSerializableMixin { } @annotation.XmlSerializable(createMixin: true) -@annotation.XmlRootElement(name: 'propertyupdate', namespace: namespaceDav) +@annotation.XmlRootElement(name: 'set', namespace: namespaceDav) class WebDavSet with _$WebDavSetXmlSerializableMixin { WebDavSet({ required this.prop, diff --git a/packages/nextcloud/lib/src/webdav/webdav.g.dart b/packages/nextcloud/lib/src/webdav/webdav.g.dart index 6d5b2e0e..1007981f 100644 --- a/packages/nextcloud/lib/src/webdav/webdav.g.dart +++ b/packages/nextcloud/lib/src/webdav/webdav.g.dart @@ -289,7 +289,7 @@ void _$WebDavSetBuildXmlChildren(WebDavSet instance, XmlBuilder builder, {Map namespaces = const {}}) { - builder.element('propertyupdate', namespace: 'DAV:', namespaces: namespaces, nest: () { + builder.element('set', namespace: 'DAV:', namespaces: namespaces, nest: () { instance.buildXmlChildren(builder, namespaces: namespaces); }); } @@ -316,7 +316,7 @@ List _$WebDavSetToXmlChildren(WebDavSet instance, {Map XmlElement _$WebDavSetToXmlElement(WebDavSet instance, {Map namespaces = const {}}) { return XmlElement( - XmlName('propertyupdate', namespaces['DAV:']), + XmlName('set', namespaces['DAV:']), [...namespaces.toXmlAttributes(), ...instance.toXmlAttributes(namespaces: namespaces)], instance.toXmlChildren(namespaces: namespaces)); } diff --git a/packages/nextcloud/test/core.dart b/packages/nextcloud/test/core.dart index 2520e413..596b25e1 100644 --- a/packages/nextcloud/test/core.dart +++ b/packages/nextcloud/test/core.dart @@ -1,3 +1,4 @@ +import 'package:crypto/crypto.dart'; import 'package:nextcloud/nextcloud.dart'; import 'package:test/test.dart'; @@ -98,5 +99,33 @@ Future run(final DockerImage image) async { expect(response.ocs.data[2].subline, ''); expect(response.ocs.data[2].shareWithDisplayNameUnique, ''); }); + + test('Get preview', () async { + final response = await client.core.getPreview(file: 'Nextcloud.png'); + expect(sha1.convert(response).toString(), '168c31b76ae4e8bdc5f8edd4c896f40e9d4afe1e'); + }); + + test('Get avatar', () async { + final response = await client.core.getAvatar(userId: 'admin', size: 32); + expect(sha1.convert(response).toString(), '618830d6512203281de64cc738e8a7b0cc3d1f47'); + }); + + test('Get dark avatar', () async { + final response = await client.core.getDarkAvatar(userId: 'admin', size: 32); + expect(sha1.convert(response).toString(), 'e7294d71b817d05940574061008c80a7d7a04b87'); + }); + + test('Delete app password', () async { + client = await getTestClient( + container, + useAppPassword: true, + ); + + await client.core.deleteAppPassword(); + expect( + () => client.core.getCapabilities(), + throwsA(predicate((final e) => (e! as NextcloudApiException).statusCode == 401)), + ); + }); }); } diff --git a/packages/nextcloud/test/webdav.dart b/packages/nextcloud/test/webdav.dart index 2b6db36b..f07d6bb4 100644 --- a/packages/nextcloud/test/webdav.dart +++ b/packages/nextcloud/test/webdav.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; +import 'package:crypto/crypto.dart'; import 'package:nextcloud/nextcloud.dart'; import 'package:test/test.dart'; @@ -141,6 +142,18 @@ Future run(final DockerImage image) async { ); }); + test('Download file', () async { + final response = await client.webdav.download('Nextcloud.png'); + expect(sha1.convert(response).toString(), '5ab8040bc0e9a3c47f45abd8a6d44f6e381ba6ed'); + }); + + test('Delete file', () async { + final response = await client.webdav.delete('Nextcloud.png'); + expect(response.statusCode, 204); + final responses = (await client.webdav.ls('/')).responses; + expect(responses.where((final response) => response.href!.endsWith('/Nextcloud.png')), hasLength(0)); + }); + test('Copy file', () async { final response = await client.webdav.copy( 'Nextcloud.png', @@ -208,7 +221,7 @@ Future run(final DockerImage image) async { }); test('Get file props', () async { - final props = (await client.webdav.ls( + final response = (await client.webdav.ls( 'Nextcloud.png', prop: WebDavPropfindProp.fromBools( davgetlastmodified: true, @@ -240,38 +253,54 @@ Future run(final DockerImage image) async { ocmsharepermissions: true, ), )) - .responses - .single - .propstats - .first - .prop; - expect(webdavDateFormat.parseUtc(props.davgetlastmodified!).isBefore(DateTime.now()), isTrue); - expect(props.davgetetag, isNotEmpty); - expect(props.davgetcontenttype, 'image/png'); - expect(props.davgetcontentlength, 50598); - expect(props.davresourcetype!.collection, isNull); - expect(props.ocid, isNotEmpty); - expect(props.ocfileid, isNotEmpty); - expect(props.ocfavorite, 0); - expect(props.occommentshref, isNotEmpty); - expect(props.occommentscount, 0); - expect(props.occommentsunread, 0); - expect(props.ocdownloadurl, isNull); - expect(props.ocownerid, 'user1'); - expect(props.ocownerdisplayname, 'User One'); - expect(props.ocsize, 50598); - expect(props.ocpermissions, 'RGDNVW'); - expect(props.ncnote, isNull); - expect(props.ncdatafingerprint, isNull); - expect(props.nchaspreview, isTrue); - expect(props.ncmounttype, isNull); - expect(props.ncisencrypted, isNull); - expect(props.ncmetadataetag, isNull); - expect(props.ncuploadtime, 0); - expect(props.nccreationtime, 0); - expect(props.ncrichworkspace, isNull); - expect(props.ocssharepermissions, 19); - expect(json.decode(props.ocmsharepermissions!), ['share', 'read', 'write']); + .toWebDavFiles(client.webdav) + .single; + + expect(response.path, '/Nextcloud.png'); + expect(response.id, isNotEmpty); + expect(response.fileId, isNotEmpty); + expect(response.isCollection, isFalse); + expect(response.mimeType, 'image/png'); + expect(response.etag, isNotEmpty); + expect(response.size, 50598); + expect(response.ownerId, 'user1'); + expect(response.ownerDisplay, 'User One'); + expect(response.lastModified!.isBefore(DateTime.now()), isTrue); + expect(response.isDirectory, isFalse); + expect(response.uploadedDate, DateTime.utc(1970)); + expect(response.createdDate, DateTime.utc(1970)); + expect(response.favorite, isFalse); + expect(response.hasPreview, isTrue); + expect(response.name, 'Nextcloud.png'); + expect(response.isDirectory, isFalse); + + expect(webdavDateFormat.parseUtc(response.props.davgetlastmodified!).isBefore(DateTime.now()), isTrue); + expect(response.props.davgetetag, isNotEmpty); + expect(response.props.davgetcontenttype, 'image/png'); + expect(response.props.davgetcontentlength, 50598); + expect(response.props.davresourcetype!.collection, isNull); + expect(response.props.ocid, isNotEmpty); + expect(response.props.ocfileid, isNotEmpty); + expect(response.props.ocfavorite, 0); + expect(response.props.occommentshref, isNotEmpty); + expect(response.props.occommentscount, 0); + expect(response.props.occommentsunread, 0); + expect(response.props.ocdownloadurl, isNull); + expect(response.props.ocownerid, 'user1'); + expect(response.props.ocownerdisplayname, 'User One'); + expect(response.props.ocsize, 50598); + expect(response.props.ocpermissions, 'RGDNVW'); + expect(response.props.ncnote, isNull); + expect(response.props.ncdatafingerprint, isNull); + expect(response.props.nchaspreview, isTrue); + expect(response.props.ncmounttype, isNull); + expect(response.props.ncisencrypted, isNull); + expect(response.props.ncmetadataetag, isNull); + expect(response.props.ncuploadtime, 0); + expect(response.props.nccreationtime, 0); + expect(response.props.ncrichworkspace, isNull); + expect(response.props.ocssharepermissions, 19); + expect(json.decode(response.props.ocmsharepermissions!), ['share', 'read', 'write']); }); test('Get directory props', () async { @@ -279,7 +308,7 @@ Future run(final DockerImage image) async { await client.webdav.mkdir('test'); await client.webdav.upload(data, 'test/test.txt'); - final props = (await client.webdav.ls( + final response = (await client.webdav.ls( 'test', prop: WebDavPropfindProp.fromBools( davgetcontenttype: true, @@ -289,15 +318,21 @@ Future run(final DockerImage image) async { ), depth: '0', )) - .responses - .single - .propstats - .first - .prop; - expect(props.davgetcontenttype, isNull); - expectDateInReasonableTimeRange(webdavDateFormat.parseUtc(props.davgetlastmodified!), DateTime.now()); - expect(props.davresourcetype!.collection, isNotNull); - expect(props.ocsize, data.lengthInBytes); + .toWebDavFiles(client.webdav) + .single; + + expect(response.path, '/test/'); + expect(response.isCollection, isTrue); + expect(response.mimeType, isNull); + expect(response.size, data.lengthInBytes); + expectDateInReasonableTimeRange(response.lastModified!, DateTime.now()); + expect(response.name, 'test'); + expect(response.isDirectory, isTrue); + + expect(response.props.davgetcontenttype, isNull); + expectDateInReasonableTimeRange(webdavDateFormat.parseUtc(response.props.davgetlastmodified!), DateTime.now()); + expect(response.props.davresourcetype!.collection, isNotNull); + expect(response.props.ocsize, data.lengthInBytes); }); test('Filter files', () async {