Refactor: make webdav parser more generic

This commit is contained in:
Ming Ming 2022-01-26 03:36:41 +08:00
parent 313d5f3dcb
commit 4c88070a7e
3 changed files with 177 additions and 164 deletions

View file

@ -62,7 +62,7 @@ class FileWebdavDataSource implements FileDataSource {
}
final xml = XmlDocument.parse(response.body);
var files = WebdavFileParser()(xml);
var files = WebdavResponseParser().parseFiles(xml);
// _log.fine("[list] Parsed files: [$files]");
files = files.where((element) => _validateFile(element)).map((e) {
if (e.metadata == null || e.metadata!.fileEtag == e.etag) {

View file

@ -7,8 +7,12 @@ import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/string_extension.dart';
import 'package:xml/xml.dart';
class WebdavFileParser {
List<File> call(XmlDocument xml) {
class WebdavResponseParser {
List<File> parseFiles(XmlDocument xml) => _parse<File>(xml, _toFile);
Map<String, String> get namespaces => _namespaces;
List<T> _parse<T>(XmlDocument xml, T Function(XmlElement) mapper) {
_namespaces = _parseNamespaces(xml);
final body = () {
try {
@ -16,28 +20,26 @@ class WebdavFileParser {
element.matchQualifiedName("multistatus",
prefix: "DAV:", namespaces: _namespaces));
} catch (_) {
_log.shout("[call] Missing element: multistatus");
_log.shout("[_parse] Missing element: multistatus");
rethrow;
}
}();
return body.children
.whereType<XmlElement>()
.where((element) => element.matchQualifiedName("response",
.where((e) => e.matchQualifiedName("response",
prefix: "DAV:", namespaces: _namespaces))
.map((element) {
.map((e) {
try {
return _toFile(element);
} catch (e, stacktrace) {
_log.shout("[call] Failed parsing XML", e, stacktrace);
return mapper(e);
} catch (e, stackTrace) {
_log.shout("[_parse] Failed parsing XML", e, stackTrace);
return null;
}
})
.whereType<File>()
.whereType<T>()
.toList();
}
Map<String, String> get namespaces => _namespaces;
Map<String, String> _parseNamespaces(XmlDocument xml) {
final namespaces = <String, String>{};
final xmlContent = xml.descendants.whereType<XmlElement>().firstWhere(
@ -91,7 +93,7 @@ class WebdavFileParser {
(element) => element.matchQualifiedName("prop",
prefix: "DAV:", namespaces: _namespaces));
final propParser =
_PropParser(namespaces: _namespaces, logFilePath: path);
_FilePropParser(namespaces: _namespaces, logFilePath: path);
propParser.parse(prop);
contentLength = propParser.contentLength;
contentType = propParser.contentType;
@ -149,8 +151,8 @@ class WebdavFileParser {
Logger("entity.webdav_response_parser.WebdavResponseParser");
}
class _PropParser {
_PropParser({
class _FilePropParser {
_FilePropParser({
this.namespaces = const {},
this.logFilePath,
});

View file

@ -5,7 +5,20 @@ import 'package:xml/xml.dart';
void main() {
group("WebdavFileParser", () {
test("file", () {
group("parseFiles", () {
test("file", _files);
test("file w/ 404 properties", _files404props);
test("file w/ metadata", _filesMetadata);
test("file w/ is-archived", _filesIsArchived);
test("file w/ override-date-time", _filesOverrideDateTime);
test("multiple files", _filesMultiple);
test("directory", _filesDir);
test("nextcloud hosted in subdir", _filesServerHostedInSubdir);
});
});
}
void _files() {
final xml = XmlDocument.parse("""
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:"
@ -29,7 +42,7 @@ void main() {
</d:response>
</d:multistatus>
""");
final results = WebdavFileParser()(xml);
final results = WebdavResponseParser().parseFiles(xml);
expect(results, [
File(
path: "remote.php/dav/files/admin/Nextcloud intro.mp4",
@ -42,9 +55,9 @@ void main() {
isCollection: false,
),
]);
});
}
test("file w/ 404 properties", () {
void _files404props() {
final xml = XmlDocument.parse("""
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:"
@ -75,7 +88,7 @@ void main() {
</d:response>
</d:multistatus>
""");
final results = WebdavFileParser()(xml);
final results = WebdavResponseParser().parseFiles(xml);
expect(results, [
File(
path: "remote.php/dav/files/admin/Nextcloud intro.mp4",
@ -88,9 +101,9 @@ void main() {
isCollection: false,
),
]);
});
}
test("file w/ metadata", () {
void _filesMetadata() {
final xml = XmlDocument.parse("""
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:"
@ -115,7 +128,7 @@ void main() {
</d:response>
</d:multistatus>
""");
final results = WebdavFileParser()(xml);
final results = WebdavResponseParser().parseFiles(xml);
expect(results, [
File(
path: "remote.php/dav/files/admin/Photos/Nextcloud community.jpg",
@ -134,9 +147,9 @@ void main() {
),
),
]);
});
}
test("file w/ is-archived", () {
void _filesIsArchived() {
final xml = XmlDocument.parse("""
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:"
@ -160,7 +173,7 @@ void main() {
</d:response>
</d:multistatus>
""");
final results = WebdavFileParser()(xml);
final results = WebdavResponseParser().parseFiles(xml);
expect(results, [
File(
path: "remote.php/dav/files/admin/Photos/Nextcloud community.jpg",
@ -173,9 +186,9 @@ void main() {
isArchived: true,
),
]);
});
}
test("file w/ override-date-time", () {
void _filesOverrideDateTime() {
final xml = XmlDocument.parse("""
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:"
@ -199,7 +212,7 @@ void main() {
</d:response>
</d:multistatus>
""");
final results = WebdavFileParser()(xml);
final results = WebdavResponseParser().parseFiles(xml);
expect(results, [
File(
path: "remote.php/dav/files/admin/Photos/Nextcloud community.jpg",
@ -212,9 +225,9 @@ void main() {
overrideDateTime: DateTime.utc(2021, 1, 2, 3, 4, 5),
),
]);
});
}
test("multiple files", () {
void _filesMultiple() {
final xml = XmlDocument.parse("""
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:"
@ -254,7 +267,7 @@ void main() {
</d:response>
</d:multistatus>
""");
final results = WebdavFileParser()(xml);
final results = WebdavResponseParser().parseFiles(xml);
expect(results, [
File(
path: "remote.php/dav/files/admin/Nextcloud intro.mp4",
@ -283,9 +296,9 @@ void main() {
),
),
]);
});
}
test("directory", () {
void _filesDir() {
final xml = XmlDocument.parse("""
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:"
@ -317,7 +330,7 @@ void main() {
</d:response>
</d:multistatus>
""");
final results = WebdavFileParser()(xml);
final results = WebdavResponseParser().parseFiles(xml);
expect(results, [
File(
path: "remote.php/dav/files/admin/Photos",
@ -328,9 +341,9 @@ void main() {
fileId: 123,
),
]);
});
}
test("nextcloud hosed in subdir", () {
void _filesServerHostedInSubdir() {
final xml = XmlDocument.parse("""
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:"
@ -354,7 +367,7 @@ void main() {
</d:response>
</d:multistatus>
""");
final results = WebdavFileParser()(xml);
final results = WebdavResponseParser().parseFiles(xml);
expect(results, [
File(
path: "remote.php/dav/files/admin/Nextcloud intro.mp4",
@ -367,6 +380,4 @@ void main() {
isCollection: false,
),
]);
});
});
}