mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 16:56:19 +01:00
Add api to retrieve face data from the Recognize app
This commit is contained in:
parent
4bde517813
commit
c54b178e5a
9 changed files with 676 additions and 0 deletions
|
@ -12,6 +12,7 @@ part 'face_recognition_api.dart';
|
|||
part 'files_api.dart';
|
||||
part 'files_sharing_api.dart';
|
||||
part 'photos_api.dart';
|
||||
part 'recognize_api.dart';
|
||||
part 'status_api.dart';
|
||||
part 'systemtag_api.dart';
|
||||
|
||||
|
|
|
@ -77,6 +77,20 @@ extension _$ApiPhotosAlbumNpLog on ApiPhotosAlbum {
|
|||
static final log = Logger("src.api.ApiPhotosAlbum");
|
||||
}
|
||||
|
||||
extension _$ApiRecognizeFacesNpLog on ApiRecognizeFaces {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger("src.api.ApiRecognizeFaces");
|
||||
}
|
||||
|
||||
extension _$ApiRecognizeFaceNpLog on ApiRecognizeFace {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger("src.api.ApiRecognizeFace");
|
||||
}
|
||||
|
||||
extension _$ApiStatusNpLog on ApiStatus {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
|
|
@ -212,6 +212,71 @@ class Person with EquatableMixin {
|
|||
final int count;
|
||||
}
|
||||
|
||||
@toString
|
||||
class RecognizeFace with EquatableMixin {
|
||||
const RecognizeFace({
|
||||
required this.href,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
href,
|
||||
];
|
||||
|
||||
final String href;
|
||||
}
|
||||
|
||||
@ToString(ignoreNull: true)
|
||||
class RecognizeFaceItem with EquatableMixin {
|
||||
const RecognizeFaceItem({
|
||||
required this.href,
|
||||
this.contentLength,
|
||||
this.contentType,
|
||||
this.etag,
|
||||
this.lastModified,
|
||||
this.faceDetections,
|
||||
this.fileMetadataSize,
|
||||
this.hasPreview,
|
||||
this.realPath,
|
||||
this.favorite,
|
||||
this.fileId,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
href,
|
||||
contentLength,
|
||||
contentType,
|
||||
etag,
|
||||
lastModified,
|
||||
faceDetections,
|
||||
fileMetadataSize,
|
||||
hasPreview,
|
||||
realPath,
|
||||
favorite,
|
||||
fileId,
|
||||
];
|
||||
|
||||
final String href;
|
||||
final int? contentLength;
|
||||
final String? contentType;
|
||||
final String? etag;
|
||||
final DateTime? lastModified;
|
||||
final List<JsonObj>? faceDetections;
|
||||
// format currently unknown
|
||||
final dynamic fileMetadataSize;
|
||||
final bool? hasPreview;
|
||||
final String? realPath;
|
||||
final bool? favorite;
|
||||
final int? fileId;
|
||||
}
|
||||
|
||||
@toString
|
||||
class Share with EquatableMixin {
|
||||
const Share({
|
||||
|
|
|
@ -55,6 +55,20 @@ extension _$PersonToString on Person {
|
|||
}
|
||||
}
|
||||
|
||||
extension _$RecognizeFaceToString on RecognizeFace {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
return "RecognizeFace {href: $href}";
|
||||
}
|
||||
}
|
||||
|
||||
extension _$RecognizeFaceItemToString on RecognizeFaceItem {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
return "RecognizeFaceItem {href: $href, ${contentLength == null ? "" : "contentLength: $contentLength, "}${contentType == null ? "" : "contentType: $contentType, "}${etag == null ? "" : "etag: $etag, "}${lastModified == null ? "" : "lastModified: $lastModified, "}${faceDetections == null ? "" : "faceDetections: $faceDetections, "}fileMetadataSize: $fileMetadataSize, ${hasPreview == null ? "" : "hasPreview: $hasPreview, "}${realPath == null ? "" : "realPath: $realPath, "}${favorite == null ? "" : "favorite: $favorite, "}${fileId == null ? "" : "fileId: $fileId"}}";
|
||||
}
|
||||
}
|
||||
|
||||
extension _$ShareToString on Share {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
|
|
154
np_api/lib/src/entity/recognize_face_item_parser.dart
Normal file
154
np_api/lib/src/entity/recognize_face_item_parser.dart
Normal file
|
@ -0,0 +1,154 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:np_api/src/entity/entity.dart';
|
||||
import 'package:np_api/src/entity/parser.dart';
|
||||
import 'package:np_common/log.dart';
|
||||
import 'package:np_common/type.dart';
|
||||
import 'package:xml/xml.dart';
|
||||
|
||||
class RecognizeFaceItemParser extends XmlResponseParser {
|
||||
Future<List<RecognizeFaceItem>> parse(String response) =>
|
||||
compute(_parseRecognizeFaceItemsIsolate, response);
|
||||
|
||||
List<RecognizeFaceItem> _parse(XmlDocument xml) =>
|
||||
parseT<RecognizeFaceItem>(xml, _toRecognizeFaceItem);
|
||||
|
||||
/// Map <DAV:response> contents to RecognizeFaceItem
|
||||
RecognizeFaceItem _toRecognizeFaceItem(XmlElement element) {
|
||||
String? href;
|
||||
int? contentLength;
|
||||
String? contentType;
|
||||
String? etag;
|
||||
DateTime? lastModified;
|
||||
List<JsonObj>? faceDetections;
|
||||
// format currently unknown
|
||||
dynamic fileMetadataSize;
|
||||
bool? hasPreview;
|
||||
String? realPath;
|
||||
bool? favorite;
|
||||
int? fileId;
|
||||
|
||||
for (final child in element.children.whereType<XmlElement>()) {
|
||||
if (child.matchQualifiedName("href",
|
||||
prefix: "DAV:", namespaces: namespaces)) {
|
||||
href = Uri.decodeComponent(child.innerText);
|
||||
} else if (child.matchQualifiedName("propstat",
|
||||
prefix: "DAV:", namespaces: namespaces)) {
|
||||
final status = child.children
|
||||
.whereType<XmlElement>()
|
||||
.firstWhere((element) => element.matchQualifiedName("status",
|
||||
prefix: "DAV:", namespaces: namespaces))
|
||||
.innerText;
|
||||
if (!status.contains(" 200 ")) {
|
||||
continue;
|
||||
}
|
||||
final prop = child.children.whereType<XmlElement>().firstWhere(
|
||||
(element) => element.matchQualifiedName("prop",
|
||||
prefix: "DAV:", namespaces: namespaces));
|
||||
final propParser = _PropParser(namespaces: namespaces);
|
||||
propParser.parse(prop);
|
||||
contentLength = propParser.contentLength;
|
||||
contentType = propParser.contentType;
|
||||
etag = propParser.etag;
|
||||
lastModified = propParser.lastModified;
|
||||
faceDetections = propParser.faceDetections;
|
||||
fileMetadataSize = propParser.fileMetadataSize;
|
||||
hasPreview = propParser.hasPreview;
|
||||
realPath = propParser.realPath;
|
||||
favorite = propParser.favorite;
|
||||
fileId = propParser.fileId;
|
||||
}
|
||||
}
|
||||
|
||||
return RecognizeFaceItem(
|
||||
href: href!,
|
||||
contentLength: contentLength,
|
||||
contentType: contentType,
|
||||
etag: etag,
|
||||
lastModified: lastModified,
|
||||
faceDetections: faceDetections,
|
||||
fileMetadataSize: fileMetadataSize,
|
||||
hasPreview: hasPreview,
|
||||
realPath: realPath,
|
||||
favorite: favorite,
|
||||
fileId: fileId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PropParser {
|
||||
_PropParser({
|
||||
this.namespaces = const {},
|
||||
});
|
||||
|
||||
/// Parse <DAV:prop> element contents
|
||||
void parse(XmlElement element) {
|
||||
for (final child in element.children.whereType<XmlElement>()) {
|
||||
if (child.matchQualifiedName("getcontentlength",
|
||||
prefix: "DAV:", namespaces: namespaces)) {
|
||||
_contentLength = int.parse(child.innerText);
|
||||
} else if (child.matchQualifiedName("getcontenttype",
|
||||
prefix: "DAV:", namespaces: namespaces)) {
|
||||
_contentType = child.innerText;
|
||||
} else if (child.matchQualifiedName("getetag",
|
||||
prefix: "DAV:", namespaces: namespaces)) {
|
||||
_etag = child.innerText.replaceAll("\"", "");
|
||||
} else if (child.matchQualifiedName("getlastmodified",
|
||||
prefix: "DAV:", namespaces: namespaces)) {
|
||||
_lastModified = HttpDate.parse(child.innerText);
|
||||
} else if (child.matchQualifiedName("face-detections",
|
||||
prefix: "http://nextcloud.org/ns", namespaces: namespaces)) {
|
||||
_faceDetections = child.innerText.isEmpty
|
||||
? null
|
||||
: (jsonDecode(child.innerText) as List).cast<JsonObj>();
|
||||
} else if (child.matchQualifiedName("file-metadata-size",
|
||||
prefix: "http://nextcloud.org/ns", namespaces: namespaces)) {
|
||||
_fileMetadataSize = child.innerText;
|
||||
} else if (child.matchQualifiedName("has-preview",
|
||||
prefix: "http://nextcloud.org/ns", namespaces: namespaces)) {
|
||||
_hasPreview = child.innerText == "true";
|
||||
} else if (child.matchQualifiedName("realpath",
|
||||
prefix: "http://nextcloud.org/ns", namespaces: namespaces)) {
|
||||
_realPath = child.innerText;
|
||||
} else if (child.matchQualifiedName("favorite",
|
||||
prefix: "http://owncloud.org/ns", namespaces: namespaces)) {
|
||||
_favorite = child.innerText != "0";
|
||||
} else if (child.matchQualifiedName("fileid",
|
||||
prefix: "http://owncloud.org/ns", namespaces: namespaces)) {
|
||||
_fileId = int.parse(child.innerText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int? get contentLength => _contentLength;
|
||||
String? get contentType => _contentType;
|
||||
String? get etag => _etag;
|
||||
DateTime? get lastModified => _lastModified;
|
||||
List<JsonObj>? get faceDetections => _faceDetections;
|
||||
dynamic get fileMetadataSize => _fileMetadataSize;
|
||||
bool? get hasPreview => _hasPreview;
|
||||
String? get realPath => _realPath;
|
||||
bool? get favorite => _favorite;
|
||||
int? get fileId => _fileId;
|
||||
|
||||
final Map<String, String> namespaces;
|
||||
|
||||
int? _contentLength;
|
||||
String? _contentType;
|
||||
String? _etag;
|
||||
DateTime? _lastModified;
|
||||
List<JsonObj>? _faceDetections;
|
||||
dynamic _fileMetadataSize;
|
||||
bool? _hasPreview;
|
||||
String? _realPath;
|
||||
bool? _favorite;
|
||||
int? _fileId;
|
||||
}
|
||||
|
||||
List<RecognizeFaceItem> _parseRecognizeFaceItemsIsolate(String response) {
|
||||
initLog();
|
||||
final xml = XmlDocument.parse(response);
|
||||
return RecognizeFaceItemParser()._parse(xml);
|
||||
}
|
35
np_api/lib/src/entity/recognize_face_parser.dart
Normal file
35
np_api/lib/src/entity/recognize_face_parser.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:np_api/src/entity/entity.dart';
|
||||
import 'package:np_api/src/entity/parser.dart';
|
||||
import 'package:np_common/log.dart';
|
||||
import 'package:xml/xml.dart';
|
||||
|
||||
class RecognizeFaceParser extends XmlResponseParser {
|
||||
Future<List<RecognizeFace>> parse(String response) =>
|
||||
compute(_parseRecognizeFacesIsolate, response);
|
||||
|
||||
List<RecognizeFace> _parse(XmlDocument xml) =>
|
||||
parseT<RecognizeFace>(xml, _toRecognizeFace);
|
||||
|
||||
/// Map <DAV:response> contents to RecognizeFace
|
||||
RecognizeFace _toRecognizeFace(XmlElement element) {
|
||||
String? href;
|
||||
|
||||
for (final child in element.children.whereType<XmlElement>()) {
|
||||
if (child.matchQualifiedName("href",
|
||||
prefix: "DAV:", namespaces: namespaces)) {
|
||||
href = Uri.decodeComponent(child.innerText);
|
||||
}
|
||||
}
|
||||
|
||||
return RecognizeFace(
|
||||
href: href!,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
List<RecognizeFace> _parseRecognizeFacesIsolate(String response) {
|
||||
initLog();
|
||||
final xml = XmlDocument.parse(response);
|
||||
return RecognizeFaceParser()._parse(xml);
|
||||
}
|
124
np_api/lib/src/recognize_api.dart
Normal file
124
np_api/lib/src/recognize_api.dart
Normal file
|
@ -0,0 +1,124 @@
|
|||
part of 'api.dart';
|
||||
|
||||
class ApiRecognize {
|
||||
const ApiRecognize(this.api, this.userId);
|
||||
|
||||
ApiRecognizeFaces faces() => ApiRecognizeFaces(this);
|
||||
ApiRecognizeFace face(String name) => ApiRecognizeFace(this, name);
|
||||
|
||||
String get _path => "remote.php/dav/recognize/$userId";
|
||||
|
||||
final Api api;
|
||||
final String userId;
|
||||
}
|
||||
|
||||
@npLog
|
||||
class ApiRecognizeFaces {
|
||||
const ApiRecognizeFaces(this.recognize);
|
||||
|
||||
Future<Response> propfind() async {
|
||||
final endpoint = "${recognize._path}/faces";
|
||||
try {
|
||||
return await api.request("PROPFIND", endpoint);
|
||||
} catch (e) {
|
||||
_log.severe("[propfind] Failed while propfind", e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Api get api => recognize.api;
|
||||
final ApiRecognize recognize;
|
||||
}
|
||||
|
||||
@npLog
|
||||
class ApiRecognizeFace {
|
||||
const ApiRecognizeFace(this.recognize, this.name);
|
||||
|
||||
Future<Response> propfind({
|
||||
getcontentlength,
|
||||
getcontenttype,
|
||||
getetag,
|
||||
getlastmodified,
|
||||
faceDetections,
|
||||
fileMetadataSize,
|
||||
hasPreview,
|
||||
realpath,
|
||||
favorite,
|
||||
fileid,
|
||||
}) async {
|
||||
final endpoint = _path;
|
||||
try {
|
||||
final bool hasDavNs = (getcontentlength != null ||
|
||||
getcontenttype != null ||
|
||||
getetag != null ||
|
||||
getlastmodified != null);
|
||||
final bool hasNcNs = (faceDetections != null ||
|
||||
fileMetadataSize != null ||
|
||||
hasPreview != null ||
|
||||
realpath != null);
|
||||
final bool hasOcNs = (favorite != null || fileid != null);
|
||||
if (!hasDavNs && !hasOcNs && !hasNcNs) {
|
||||
// no body
|
||||
return await api.request("PROPFIND", endpoint);
|
||||
}
|
||||
|
||||
final namespaces = {
|
||||
"DAV:": "d",
|
||||
if (hasOcNs) "http://owncloud.org/ns": "oc",
|
||||
if (hasNcNs) "http://nextcloud.org/ns": "nc",
|
||||
};
|
||||
final builder = XmlBuilder();
|
||||
builder
|
||||
..processing("xml", "version=\"1.0\"")
|
||||
..element("d:propfind", namespaces: namespaces, nest: () {
|
||||
builder.element("d:prop", nest: () {
|
||||
if (getcontentlength != null) {
|
||||
builder.element("d:getcontentlength");
|
||||
}
|
||||
if (getcontenttype != null) {
|
||||
builder.element("d:getcontenttype");
|
||||
}
|
||||
if (getetag != null) {
|
||||
builder.element("d:getetag");
|
||||
}
|
||||
if (getlastmodified != null) {
|
||||
builder.element("d:getlastmodified");
|
||||
}
|
||||
if (faceDetections != null) {
|
||||
builder.element("nc:face-detections");
|
||||
}
|
||||
if (fileMetadataSize != null) {
|
||||
builder.element("nc:file-metadata-size");
|
||||
}
|
||||
if (hasPreview != null) {
|
||||
builder.element("nc:has-preview");
|
||||
}
|
||||
if (realpath != null) {
|
||||
builder.element("nc:realpath");
|
||||
}
|
||||
if (favorite != null) {
|
||||
builder.element("oc:favorite");
|
||||
}
|
||||
if (fileid != null) {
|
||||
builder.element("oc:fileid");
|
||||
}
|
||||
});
|
||||
});
|
||||
return await api.request(
|
||||
"PROPFIND",
|
||||
endpoint,
|
||||
header: {"Content-Type": "application/xml"},
|
||||
body: builder.buildDocument().toXmlString(),
|
||||
);
|
||||
} catch (e) {
|
||||
_log.severe("[propfind] Failed while propfind", e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
String get _path => "${recognize._path}/faces/$name";
|
||||
|
||||
Api get api => recognize.api;
|
||||
final ApiRecognize recognize;
|
||||
final String name;
|
||||
}
|
154
np_api/test/entity/recognize_face_item_parser_test.dart
Normal file
154
np_api/test/entity/recognize_face_item_parser_test.dart
Normal file
|
@ -0,0 +1,154 @@
|
|||
import 'package:np_api/np_api.dart';
|
||||
import 'package:np_api/src/entity/recognize_face_item_parser.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group("RecognizeFaceItemParser", () {
|
||||
group("parse", () {
|
||||
test("empty", _empty);
|
||||
test("image", _image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _empty() async {
|
||||
const xml = """
|
||||
<?xml version="1.0"?>
|
||||
<d:multistatus xmlns:d="DAV:"
|
||||
xmlns:s="http://sabredav.org/ns"
|
||||
xmlns:oc="http://owncloud.org/ns"
|
||||
xmlns:nc="http://nextcloud.org/ns">
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/recognize/admin/faces/test/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype>
|
||||
<d:collection/>
|
||||
</d:resourcetype>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:getcontentlength/>
|
||||
<d:getcontenttype/>
|
||||
<d:getetag/>
|
||||
<d:getlastmodified/>
|
||||
<nc:face-detections/>
|
||||
<nc:file-metadata-size/>
|
||||
<nc:has-preview/>
|
||||
<nc:realpath/>
|
||||
<oc:favorite/>
|
||||
<oc:fileid/>
|
||||
<oc:permissions/>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 404 Not Found</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
</d:multistatus>
|
||||
""";
|
||||
final results = await RecognizeFaceItemParser().parse(xml);
|
||||
expect(
|
||||
results,
|
||||
const [
|
||||
RecognizeFaceItem(href: "/remote.php/dav/recognize/admin/faces/test/"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _image() async {
|
||||
const xml = """
|
||||
<?xml version="1.0"?>
|
||||
<d:multistatus xmlns:d="DAV:"
|
||||
xmlns:s="http://sabredav.org/ns"
|
||||
xmlns:oc="http://owncloud.org/ns"
|
||||
xmlns:nc="http://nextcloud.org/ns">
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/recognize/admin/faces/test/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype>
|
||||
<d:collection/>
|
||||
</d:resourcetype>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:getcontentlength/>
|
||||
<d:getcontenttype/>
|
||||
<d:getetag/>
|
||||
<d:getlastmodified/>
|
||||
<nc:face-detections/>
|
||||
<nc:file-metadata-size/>
|
||||
<nc:has-preview/>
|
||||
<nc:realpath/>
|
||||
<oc:favorite/>
|
||||
<oc:fileid/>
|
||||
<oc:permissions/>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 404 Not Found</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/recognize/admin/faces/test/test1.jpg</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:getcontentlength>12345</d:getcontentlength>
|
||||
<d:getcontenttype>image/jpeg</d:getcontenttype>
|
||||
<d:getetag>00000000000000000000000000000000</d:getetag>
|
||||
<d:getlastmodified>Sun, 1 Jan 2023 01:02:03 GMT</d:getlastmodified>
|
||||
<d:resourcetype/>
|
||||
<nc:face-detections>[{"id":1,"userId":"test","fileId":2,"x":0.5,"y":0.5,"height":0.1,"width":0.1,"vector":[-0.1,0.1,0.1,-0.01],"clusterId":10,"title":"test"}]</nc:face-detections>
|
||||
<nc:file-metadata-size>[]</nc:file-metadata-size>
|
||||
<nc:has-preview>true</nc:has-preview>
|
||||
<nc:realpath>/admin/files/test1.jpg</nc:realpath>
|
||||
<oc:favorite>0</oc:favorite>
|
||||
<oc:fileid>2</oc:fileid>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<oc:permissions/>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 404 Not Found</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
</d:multistatus>
|
||||
""";
|
||||
final results = await RecognizeFaceItemParser().parse(xml);
|
||||
expect(
|
||||
results,
|
||||
[
|
||||
const RecognizeFaceItem(
|
||||
href: "/remote.php/dav/recognize/admin/faces/test/"),
|
||||
RecognizeFaceItem(
|
||||
href: "/remote.php/dav/recognize/admin/faces/test/test1.jpg",
|
||||
contentLength: 12345,
|
||||
contentType: "image/jpeg",
|
||||
etag: "00000000000000000000000000000000",
|
||||
lastModified: DateTime.utc(2023, 1, 1, 1, 2, 3),
|
||||
faceDetections: [
|
||||
{
|
||||
"id": 1,
|
||||
"userId": "test",
|
||||
"fileId": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"height": 0.1,
|
||||
"width": 0.1,
|
||||
"vector": [-0.1, 0.1, 0.1, -0.01],
|
||||
"clusterId": 10,
|
||||
"title": "test",
|
||||
},
|
||||
],
|
||||
fileMetadataSize: "[]",
|
||||
hasPreview: true,
|
||||
realPath: "/admin/files/test1.jpg",
|
||||
favorite: false,
|
||||
fileId: 2,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
115
np_api/test/entity/recognize_face_parser_test.dart
Normal file
115
np_api/test/entity/recognize_face_parser_test.dart
Normal file
|
@ -0,0 +1,115 @@
|
|||
import 'package:np_api/np_api.dart';
|
||||
import 'package:np_api/src/entity/recognize_face_parser.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group("RecognizeFaceParser", () {
|
||||
group("parse", () {
|
||||
test("empty", _empty);
|
||||
test("unnamed", _unnamed);
|
||||
test("named", _named);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _empty() async {
|
||||
const xml = """
|
||||
<?xml version="1.0"?>
|
||||
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/recognize/admin/faces/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype>
|
||||
<d:collection/>
|
||||
</d:resourcetype>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
</d:multistatus>
|
||||
""";
|
||||
final results = await RecognizeFaceParser().parse(xml);
|
||||
expect(
|
||||
results,
|
||||
const [
|
||||
RecognizeFace(href: "/remote.php/dav/recognize/admin/faces/"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _unnamed() async {
|
||||
const xml = """
|
||||
<?xml version="1.0"?>
|
||||
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/recognize/admin/faces/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype>
|
||||
<d:collection/>
|
||||
</d:resourcetype>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/recognize/admin/faces/10/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype>
|
||||
<d:collection/>
|
||||
</d:resourcetype>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
</d:multistatus>
|
||||
""";
|
||||
final results = await RecognizeFaceParser().parse(xml);
|
||||
expect(
|
||||
results,
|
||||
const [
|
||||
RecognizeFace(href: "/remote.php/dav/recognize/admin/faces/"),
|
||||
RecognizeFace(href: "/remote.php/dav/recognize/admin/faces/10/"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _named() async {
|
||||
const xml = """
|
||||
<?xml version="1.0"?>
|
||||
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/recognize/admin/faces/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype>
|
||||
<d:collection/>
|
||||
</d:resourcetype>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/recognize/admin/faces/lovely%20face/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype>
|
||||
<d:collection/>
|
||||
</d:resourcetype>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
</d:multistatus>
|
||||
""";
|
||||
final results = await RecognizeFaceParser().parse(xml);
|
||||
expect(
|
||||
results,
|
||||
const [
|
||||
RecognizeFace(href: "/remote.php/dav/recognize/admin/faces/"),
|
||||
RecognizeFace(href: "/remote.php/dav/recognize/admin/faces/lovely face/"),
|
||||
],
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue