From ba56d9a1b6be2ef8b64273e9706ab9c9cb87da7a Mon Sep 17 00:00:00 2001 From: jld3103 Date: Sun, 23 Apr 2023 17:31:55 +0200 Subject: [PATCH] nextcloud: Implement dav resourcetype --- packages/nextcloud/lib/src/webdav/file.dart | 5 +- packages/nextcloud/lib/src/webdav/props.csv | 1 + packages/nextcloud/lib/src/webdav/props.dart | 9 +++ .../nextcloud/lib/src/webdav/props.g.dart | 71 +++++++++++++++++++ packages/nextcloud/lib/src/webdav/webdav.dart | 14 +++- .../nextcloud/lib/src/webdav/webdav.g.dart | 70 ++++++++++++++++++ packages/nextcloud/test/webdav.dart | 4 ++ 7 files changed, 172 insertions(+), 2 deletions(-) diff --git a/packages/nextcloud/lib/src/webdav/file.dart b/packages/nextcloud/lib/src/webdav/file.dart index 0242d65e..066fd482 100644 --- a/packages/nextcloud/lib/src/webdav/file.dart +++ b/packages/nextcloud/lib/src/webdav/file.dart @@ -41,6 +41,9 @@ class WebDavFile { /// The unique id for the file within the instance late final String? fileId = props.ocfileid; + /// Whether this is a collection resource type + late final bool? isCollection = props.davresourcetype != null ? props.davresourcetype!.collection != null : null; + /// Mime-type of the file late final String? mimeType = props.davgetcontenttype; @@ -93,5 +96,5 @@ class WebDavFile { }(); /// Returns if the file is a directory - late final bool isDirectory = path.endsWith('/'); + late final bool isDirectory = (isCollection ?? false) || path.endsWith('/'); } diff --git a/packages/nextcloud/lib/src/webdav/props.csv b/packages/nextcloud/lib/src/webdav/props.csv index 115c416f..ebff2143 100644 --- a/packages/nextcloud/lib/src/webdav/props.csv +++ b/packages/nextcloud/lib/src/webdav/props.csv @@ -2,6 +2,7 @@ dav,getlastmodified,String dav,getetag,String dav,getcontenttype,String dav,getcontentlength,int +dav,resourcetype,WebDavResourcetype oc,id,String oc,fileid,String oc,favorite,int diff --git a/packages/nextcloud/lib/src/webdav/props.dart b/packages/nextcloud/lib/src/webdav/props.dart index 3ebcf793..092f22b0 100644 --- a/packages/nextcloud/lib/src/webdav/props.dart +++ b/packages/nextcloud/lib/src/webdav/props.dart @@ -12,6 +12,7 @@ class WebDavPropfindProp with _$WebDavPropfindPropXmlSerializableMixin { this.davgetetag, this.davgetcontenttype, this.davgetcontentlength, + this.davresourcetype, this.ocid, this.ocfileid, this.ocfavorite, @@ -44,6 +45,8 @@ class WebDavPropfindProp with _$WebDavPropfindPropXmlSerializableMixin { bool? davgetcontenttype; @annotation.XmlElement(name: 'getcontentlength', namespace: namespaceDav, includeIfNull: false) bool? davgetcontentlength; + @annotation.XmlElement(name: 'resourcetype', namespace: namespaceDav, includeIfNull: false) + bool? davresourcetype; @annotation.XmlElement(name: 'id', namespace: namespaceOwncloud, includeIfNull: false) bool? ocid; @annotation.XmlElement(name: 'fileid', namespace: namespaceOwncloud, includeIfNull: false) @@ -98,6 +101,7 @@ class WebDavProp with _$WebDavPropXmlSerializableMixin { this.davgetetag, this.davgetcontenttype, this.davgetcontentlength, + this.davresourcetype, this.ocid, this.ocfileid, this.ocfavorite, @@ -130,6 +134,8 @@ class WebDavProp with _$WebDavPropXmlSerializableMixin { String? davgetcontenttype; @annotation.XmlElement(name: 'getcontentlength', namespace: namespaceDav, includeIfNull: false) int? davgetcontentlength; + @annotation.XmlElement(name: 'resourcetype', namespace: namespaceDav, includeIfNull: false) + WebDavResourcetype? davresourcetype; @annotation.XmlElement(name: 'id', namespace: namespaceOwncloud, includeIfNull: false) String? ocid; @annotation.XmlElement(name: 'fileid', namespace: namespaceOwncloud, includeIfNull: false) @@ -184,6 +190,7 @@ class WebDavOcFilterRules with _$WebDavOcFilterRulesXmlSerializableMixin { this.davgetetag, this.davgetcontenttype, this.davgetcontentlength, + this.davresourcetype, this.ocid, this.ocfileid, this.ocfavorite, @@ -216,6 +223,8 @@ class WebDavOcFilterRules with _$WebDavOcFilterRulesXmlSerializableMixin { String? davgetcontenttype; @annotation.XmlElement(name: 'getcontentlength', namespace: namespaceDav, includeIfNull: false) int? davgetcontentlength; + @annotation.XmlElement(name: 'resourcetype', namespace: namespaceDav, includeIfNull: false) + WebDavResourcetype? davresourcetype; @annotation.XmlElement(name: 'id', namespace: namespaceOwncloud, includeIfNull: false) String? ocid; @annotation.XmlElement(name: 'fileid', namespace: namespaceOwncloud, includeIfNull: false) diff --git a/packages/nextcloud/lib/src/webdav/props.g.dart b/packages/nextcloud/lib/src/webdav/props.g.dart index 2196bf7b..6c8c6f31 100644 --- a/packages/nextcloud/lib/src/webdav/props.g.dart +++ b/packages/nextcloud/lib/src/webdav/props.g.dart @@ -52,6 +52,17 @@ void _$WebDavPropfindPropBuildXmlChildren(WebDavPropfindProp instance, XmlBuilde builder.text(davgetcontentlengthSerialized); }); } + final davresourcetype = instance.davresourcetype; + final davresourcetypeSerialized = davresourcetype != null + ? davresourcetype == true + ? 'true' + : 'false' + : null; + if (davresourcetypeSerialized != null) { + builder.element('resourcetype', namespace: 'DAV:', nest: () { + builder.text(davresourcetypeSerialized); + }); + } final ocid = instance.ocid; final ocidSerialized = ocid != null ? ocid == true @@ -308,6 +319,7 @@ WebDavPropfindProp _$WebDavPropfindPropFromXmlElement(XmlElement element) { final davgetetag = element.getElement('getetag', namespace: 'DAV:')?.getText(); final davgetcontenttype = element.getElement('getcontenttype', namespace: 'DAV:')?.getText(); final davgetcontentlength = element.getElement('getcontentlength', namespace: 'DAV:')?.getText(); + final davresourcetype = element.getElement('resourcetype', namespace: 'DAV:')?.getText(); final ocid = element.getElement('id', namespace: 'http://owncloud.org/ns')?.getText(); final ocfileid = element.getElement('fileid', namespace: 'http://owncloud.org/ns')?.getText(); final ocfavorite = element.getElement('favorite', namespace: 'http://owncloud.org/ns')?.getText(); @@ -361,6 +373,13 @@ WebDavPropfindProp _$WebDavPropfindPropFromXmlElement(XmlElement element) { ? false : throw FormatException('Invalid bool format', davgetcontentlength) : null, + davresourcetype: davresourcetype != null + ? davresourcetype == 'true' || davresourcetype == '1' + ? true + : davresourcetype == 'false' || davresourcetype == '0' + ? false + : throw FormatException('Invalid bool format', davresourcetype) + : null, ocid: ocid != null ? ocid == 'true' || ocid == '1' ? true @@ -574,6 +593,18 @@ List _$WebDavPropfindPropToXmlChildren(WebDavPropfindProp instance, if (davgetcontentlengthConstructed != null) { children.add(davgetcontentlengthConstructed); } + final davresourcetype = instance.davresourcetype; + final davresourcetypeSerialized = davresourcetype != null + ? davresourcetype == true + ? 'true' + : 'false' + : null; + final davresourcetypeConstructed = davresourcetypeSerialized != null + ? XmlElement(XmlName('resourcetype', namespaces['DAV:']), [], [XmlText(davresourcetypeSerialized)]) + : null; + if (davresourcetypeConstructed != null) { + children.add(davresourcetypeConstructed); + } final ocid = instance.ocid; final ocidSerialized = ocid != null ? ocid == true @@ -906,6 +937,13 @@ void _$WebDavPropBuildXmlChildren(WebDavProp instance, XmlBuilder builder, builder.text(davgetcontentlengthSerialized); }); } + final davresourcetype = instance.davresourcetype; + final davresourcetypeSerialized = davresourcetype; + if (davresourcetypeSerialized != null) { + builder.element('resourcetype', namespace: 'DAV:', nest: () { + davresourcetypeSerialized.buildXmlChildren(builder, namespaces: namespaces); + }); + } final ocid = instance.ocid; final ocidSerialized = ocid; if (ocidSerialized != null) { @@ -1077,6 +1115,7 @@ WebDavProp _$WebDavPropFromXmlElement(XmlElement element) { final davgetetag = element.getElement('getetag', namespace: 'DAV:')?.getText(); final davgetcontenttype = element.getElement('getcontenttype', namespace: 'DAV:')?.getText(); final davgetcontentlength = element.getElement('getcontentlength', namespace: 'DAV:')?.getText(); + final davresourcetype = element.getElement('resourcetype', namespace: 'DAV:'); final ocid = element.getElement('id', namespace: 'http://owncloud.org/ns')?.getText(); final ocfileid = element.getElement('fileid', namespace: 'http://owncloud.org/ns')?.getText(); final ocfavorite = element.getElement('favorite', namespace: 'http://owncloud.org/ns')?.getText(); @@ -1106,6 +1145,7 @@ WebDavProp _$WebDavPropFromXmlElement(XmlElement element) { davgetetag: davgetetag, davgetcontenttype: davgetcontenttype, davgetcontentlength: davgetcontentlength != null ? int.parse(davgetcontentlength) : null, + davresourcetype: davresourcetype != null ? WebDavResourcetype.fromXmlElement(davresourcetype) : null, ocid: ocid, ocfileid: ocfileid, ocfavorite: ocfavorite != null ? int.parse(ocfavorite) : null, @@ -1175,6 +1215,17 @@ List _$WebDavPropToXmlChildren(WebDavProp instance, {Map _$WebDavOcFilterRulesToXmlChildren(WebDavOcFilterRules instance, if (davgetcontentlengthConstructed != null) { children.add(davgetcontentlengthConstructed); } + final davresourcetype = instance.davresourcetype; + final davresourcetypeSerialized = davresourcetype; + final davresourcetypeConstructed = davresourcetypeSerialized != null + ? XmlElement( + XmlName('resourcetype', namespaces['DAV:']), + davresourcetypeSerialized.toXmlAttributes(namespaces: namespaces), + davresourcetypeSerialized.toXmlChildren(namespaces: namespaces)) + : null; + if (davresourcetypeConstructed != null) { + children.add(davresourcetypeConstructed); + } final ocid = instance.ocid; final ocidSerialized = ocid; final ocidConstructed = ocidSerialized != null diff --git a/packages/nextcloud/lib/src/webdav/webdav.dart b/packages/nextcloud/lib/src/webdav/webdav.dart index 924eed0d..c226cbdf 100644 --- a/packages/nextcloud/lib/src/webdav/webdav.dart +++ b/packages/nextcloud/lib/src/webdav/webdav.dart @@ -128,7 +128,19 @@ class WebDavOcFilterFiles with _$WebDavOcFilterFilesXmlSerializableMixin { final WebDavPropfindProp prop; } -// TODO: d:resourcetype +@annotation.XmlSerializable(createMixin: true) +@annotation.XmlRootElement(name: 'resourcetype', namespace: namespaceDav) +class WebDavResourcetype with _$WebDavResourcetypeXmlSerializableMixin { + WebDavResourcetype({ + required this.collection, + }); + + factory WebDavResourcetype.fromXmlElement(final XmlElement element) => _$WebDavResourcetypeFromXmlElement(element); + + @annotation.XmlElement(name: 'collection', namespace: namespaceDav, isSelfClosing: true, includeIfNull: true) + final List? collection; +} + // TODO: oc:checksum // TODO: oc:tags // TODO: oc:systemtag diff --git a/packages/nextcloud/lib/src/webdav/webdav.g.dart b/packages/nextcloud/lib/src/webdav/webdav.g.dart index 46b12110..6d5b2e0e 100644 --- a/packages/nextcloud/lib/src/webdav/webdav.g.dart +++ b/packages/nextcloud/lib/src/webdav/webdav.g.dart @@ -475,3 +475,73 @@ mixin _$WebDavOcFilterFilesXmlSerializableMixin { XmlElement toXmlElement({Map namespaces = const {}}) => _$WebDavOcFilterFilesToXmlElement(this as WebDavOcFilterFiles, namespaces: namespaces); } + +void _$WebDavResourcetypeBuildXmlChildren(WebDavResourcetype instance, XmlBuilder builder, + {Map namespaces = const {}}) { + final collection = instance.collection; + final collectionSerialized = collection; + if (collectionSerialized != null) { + for (final value in collectionSerialized) { + builder.element('collection', namespace: 'DAV:', isSelfClosing: true, nest: () { + if (value != null) { + builder.text(value); + } + }); + } + } +} + +void _$WebDavResourcetypeBuildXmlElement(WebDavResourcetype instance, XmlBuilder builder, + {Map namespaces = const {}}) { + builder.element('resourcetype', namespace: 'DAV:', namespaces: namespaces, nest: () { + instance.buildXmlChildren(builder, namespaces: namespaces); + }); +} + +WebDavResourcetype _$WebDavResourcetypeFromXmlElement(XmlElement element) { + final collection = element.getElements('collection', namespace: 'DAV:')?.map((e) => e.getText()).whereType(); + return WebDavResourcetype(collection: collection?.toList()); +} + +List _$WebDavResourcetypeToXmlAttributes(WebDavResourcetype instance, + {Map namespaces = const {}}) { + final attributes = []; + return attributes; +} + +List _$WebDavResourcetypeToXmlChildren(WebDavResourcetype instance, + {Map namespaces = const {}}) { + final children = []; + final collection = instance.collection; + final collectionSerialized = collection; + final collectionConstructed = collectionSerialized + ?.map((e) => XmlElement(XmlName('collection', namespaces['DAV:']), [], e != null ? [XmlText(e)] : [], true)); + if (collectionConstructed != null) { + children.addAll(collectionConstructed); + } + return children; +} + +XmlElement _$WebDavResourcetypeToXmlElement(WebDavResourcetype instance, {Map namespaces = const {}}) { + return XmlElement( + XmlName('resourcetype', namespaces['DAV:']), + [...namespaces.toXmlAttributes(), ...instance.toXmlAttributes(namespaces: namespaces)], + instance.toXmlChildren(namespaces: namespaces)); +} + +mixin _$WebDavResourcetypeXmlSerializableMixin { + void buildXmlChildren(XmlBuilder builder, {Map namespaces = const {}}) => + _$WebDavResourcetypeBuildXmlChildren(this as WebDavResourcetype, builder, namespaces: namespaces); + + void buildXmlElement(XmlBuilder builder, {Map namespaces = const {}}) => + _$WebDavResourcetypeBuildXmlElement(this as WebDavResourcetype, builder, namespaces: namespaces); + + List toXmlAttributes({Map namespaces = const {}}) => + _$WebDavResourcetypeToXmlAttributes(this as WebDavResourcetype, namespaces: namespaces); + + List toXmlChildren({Map namespaces = const {}}) => + _$WebDavResourcetypeToXmlChildren(this as WebDavResourcetype, namespaces: namespaces); + + XmlElement toXmlElement({Map namespaces = const {}}) => + _$WebDavResourcetypeToXmlElement(this as WebDavResourcetype, namespaces: namespaces); +} diff --git a/packages/nextcloud/test/webdav.dart b/packages/nextcloud/test/webdav.dart index 51f6817f..08475131 100644 --- a/packages/nextcloud/test/webdav.dart +++ b/packages/nextcloud/test/webdav.dart @@ -215,6 +215,7 @@ Future run(final DockerImage image) async { davgetetag: true, davgetcontenttype: true, davgetcontentlength: true, + davresourcetype: true, ocid: true, ocfileid: true, ocfavorite: true, @@ -248,6 +249,7 @@ Future run(final DockerImage image) async { 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); @@ -282,6 +284,7 @@ Future run(final DockerImage image) async { prop: WebDavPropfindProp( davgetcontenttype: true, davgetlastmodified: true, + davresourcetype: true, ocsize: true, ), depth: '0', @@ -293,6 +296,7 @@ Future run(final DockerImage image) async { .prop; expect(props.davgetcontenttype, isNull); expectDateInReasonableTimeRange(webdavDateFormat.parseUtc(props.davgetlastmodified!), DateTime.now()); + expect(props.davresourcetype!.collection, isNotNull); expect(props.ocsize, data.lengthInBytes); });