nc-photos/app/lib/api/api.dart

891 lines
24 KiB
Dart
Raw Normal View History

2021-04-10 06:28:12 +02:00
import 'dart:convert';
2022-12-08 16:39:13 +01:00
import 'package:flutter/foundation.dart';
2021-04-10 06:28:12 +02:00
import 'package:http/http.dart' as http;
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
2022-12-13 16:50:00 +01:00
import 'package:nc_photos/string_extension.dart';
2022-12-16 16:01:04 +01:00
import 'package:np_codegen/np_codegen.dart';
2022-12-08 16:39:13 +01:00
import 'package:to_string/to_string.dart';
2021-04-10 06:28:12 +02:00
import 'package:xml/xml.dart';
2022-12-08 16:39:13 +01:00
part 'api.g.dart';
@toString
2021-04-10 06:28:12 +02:00
class Response {
Response(this.statusCode, this.headers, this.body);
bool get isGood => _isHttpStatusGood(statusCode);
@override
2022-12-08 16:39:13 +01:00
String toString() => _$toString();
2021-04-10 06:28:12 +02:00
final int statusCode;
2022-12-08 16:39:13 +01:00
@Format(r"...")
2021-04-10 06:28:12 +02:00
final Map<String, String> headers;
/// Content of the response body, String if isResponseString == true during
/// request, Uint8List otherwise
2022-12-08 16:39:13 +01:00
@Format(
2022-12-13 16:50:00 +01:00
r"${kDebugMode ? body.toString().replaceAll(RegExp(r'\n\t'), '').slice(0, 200) : '...'}")
2021-04-10 06:28:12 +02:00
final dynamic body;
}
class BasicAuth {
BasicAuth(this.username, this.password);
BasicAuth.fromAccount(Account account)
: this(
account.username2,
account.password,
);
@override
toString() {
final authString = base64.encode(utf8.encode("$username:$password"));
return "Basic $authString";
}
final String username;
final String password;
}
2022-12-16 16:01:04 +01:00
@npLog
2021-04-10 06:28:12 +02:00
class Api {
Api(Account account)
: _baseUrl = Uri.parse(account.url),
_auth = BasicAuth.fromAccount(account);
Api.fromBaseUrl(Uri baseUrl) : _baseUrl = baseUrl;
2021-04-10 06:28:12 +02:00
2022-07-08 16:52:18 +02:00
ApiFiles files() => ApiFiles(this);
2022-07-08 16:52:18 +02:00
ApiOcs ocs() => ApiOcs(this);
2022-07-08 16:52:18 +02:00
ApiSystemtags systemtags() => ApiSystemtags(this);
2022-07-08 16:52:18 +02:00
ApiSystemtagsRelations systemtagsRelations() => ApiSystemtagsRelations(this);
2021-04-10 06:28:12 +02:00
static String getAuthorizationHeaderValue(Account account) {
return BasicAuth.fromAccount(account).toString();
2021-04-10 06:28:12 +02:00
}
Future<Response> request(
String method,
String endpoint, {
2021-07-23 22:05:57 +02:00
Map<String, String>? header,
2021-08-05 06:50:36 +02:00
Map<String, String>? queryParameters,
2021-07-23 22:05:57 +02:00
String? body,
Uint8List? bodyBytes,
2021-04-10 06:28:12 +02:00
bool isResponseString = true,
}) async {
2021-08-05 06:50:36 +02:00
final url = _makeUri(endpoint, queryParameters: queryParameters);
final req = http.Request(method, url);
if (_auth != null) {
req.headers.addAll({
"authorization": _auth.toString(),
2021-04-10 06:28:12 +02:00
});
}
2021-04-10 06:28:12 +02:00
if (header != null) {
// turn all to lower case, since HTTP headers are case-insensitive, this
// smooths our processing (if any)
req.headers.addEntries(
header.entries.map((e) => MapEntry(e.key.toLowerCase(), e.value)));
}
if (body != null) {
req.body = body;
} else if (bodyBytes != null) {
req.bodyBytes = bodyBytes;
}
final response =
await http.Response.fromStream(await http.Client().send(req));
if (!_isHttpStatusGood(response.statusCode)) {
2021-05-23 19:26:28 +02:00
if (response.statusCode == 404) {
_log.severe(
"[request] HTTP $method (${response.statusCode}): $endpoint",
);
} else {
_log.severe(
"[request] HTTP $method (${response.statusCode}): $endpoint",
response.body,
);
}
2021-04-10 06:28:12 +02:00
}
return Response(response.statusCode, response.headers,
isResponseString ? response.body : response.bodyBytes);
}
2021-08-05 06:50:36 +02:00
Uri _makeUri(
String endpoint, {
Map<String, String>? queryParameters,
}) {
final path = _baseUrl.path + "/$endpoint";
if (_baseUrl.scheme == "http") {
return Uri.http(_baseUrl.authority, path, queryParameters);
2021-05-06 07:26:26 +02:00
} else {
return Uri.https(_baseUrl.authority, path, queryParameters);
2021-05-06 07:26:26 +02:00
}
}
final Uri _baseUrl;
BasicAuth? _auth;
2021-04-10 06:28:12 +02:00
}
bool _isHttpStatusGood(int status) => status ~/ 100 == 2;
2022-12-16 16:01:04 +01:00
@npLog
2022-07-08 16:52:18 +02:00
class ApiFiles {
ApiFiles(this._api);
2021-04-10 06:28:12 +02:00
2021-09-15 08:58:06 +02:00
final Api _api;
2021-04-10 06:28:12 +02:00
Future<Response> delete({
2021-07-23 22:05:57 +02:00
required String path,
2021-04-10 06:28:12 +02:00
}) async {
try {
return await _api.request("DELETE", path);
} catch (e) {
_log.severe("[delete] Failed while delete", e);
rethrow;
}
}
Future<Response> get({
2021-07-23 22:05:57 +02:00
required String path,
2021-04-10 06:28:12 +02:00
}) async {
try {
return await _api.request("GET", path, isResponseString: false);
} catch (e) {
_log.severe("[get] Failed while get", e);
rethrow;
}
}
Future<Response> put({
2021-07-23 22:05:57 +02:00
required String path,
2021-04-10 06:28:12 +02:00
String mime = "application/octet-stream",
2021-07-23 22:05:57 +02:00
required Uint8List content,
2021-04-10 06:28:12 +02:00
}) async {
try {
return await _api.request(
"PUT",
path,
header: {
"Content-Type": mime,
2021-04-10 06:28:12 +02:00
},
bodyBytes: content,
);
} catch (e) {
_log.severe("[put] Failed while put", e);
rethrow;
}
}
Future<Response> propfind({
2021-07-23 22:05:57 +02:00
required String path,
int? depth,
2021-04-10 06:28:12 +02:00
getlastmodified,
getetag,
getcontenttype,
resourcetype,
getcontentlength,
id,
fileid,
favorite,
commentsHref,
commentsCount,
commentsUnread,
ownerId,
ownerDisplayName,
shareTypes,
checksums,
hasPreview,
size,
richWorkspace,
2021-08-01 22:06:28 +02:00
trashbinFilename,
trashbinOriginalLocation,
trashbinDeletionTime,
2021-07-23 22:05:57 +02:00
Map<String, String>? customNamespaces,
List<String>? customProperties,
2021-04-10 06:28:12 +02:00
}) async {
try {
final bool hasDavNs = (getlastmodified != null ||
getetag != null ||
getcontenttype != null ||
resourcetype != null ||
getcontentlength != null);
final bool hasOcNs = (id != null ||
fileid != null ||
favorite != null ||
commentsHref != null ||
commentsCount != null ||
commentsUnread != null ||
ownerId != null ||
ownerDisplayName != null ||
shareTypes != null ||
checksums != null ||
size != null);
2021-08-01 22:06:28 +02:00
final bool hasNcNs = (hasPreview != null ||
richWorkspace != null ||
trashbinFilename != null ||
trashbinOriginalLocation != null ||
trashbinDeletionTime != null);
2021-04-10 06:28:12 +02:00
if (!hasDavNs && !hasOcNs && !hasNcNs) {
// no body
return await _api.request("PROPFIND", path);
}
final namespaces = <String, String>{
"DAV:": "d",
if (hasOcNs) "http://owncloud.org/ns": "oc",
if (hasNcNs) "http://nextcloud.org/ns": "nc",
}..addAll(customNamespaces ?? {});
final builder = XmlBuilder();
builder
..processing("xml", "version=\"1.0\"")
..element("d:propfind", namespaces: namespaces, nest: () {
builder.element("d:prop", nest: () {
if (getlastmodified != null) {
builder.element("d:getlastmodified");
}
if (getetag != null) {
builder.element("d:getetag");
}
if (getcontenttype != null) {
builder.element("d:getcontenttype");
}
if (resourcetype != null) {
builder.element("d:resourcetype");
}
if (getcontentlength != null) {
builder.element("d:getcontentlength");
}
if (id != null) {
builder.element("oc:id");
}
if (fileid != null) {
builder.element("oc:fileid");
}
if (favorite != null) {
builder.element("oc:favorite");
}
if (commentsHref != null) {
builder.element("oc:comments-href");
}
if (commentsCount != null) {
builder.element("oc:comments-count");
}
if (commentsUnread != null) {
builder.element("oc:comments-unread");
}
if (ownerId != null) {
builder.element("oc:owner-id");
}
if (ownerDisplayName != null) {
builder.element("oc:owner-display-name");
}
if (shareTypes != null) {
builder.element("oc:share-types");
}
if (checksums != null) {
builder.element("oc:checksums");
}
if (size != null) {
builder.element("oc:size");
}
if (hasPreview != null) {
builder.element("nc:has-preview");
}
if (richWorkspace != null) {
builder.element("nc:rich-workspace");
}
2021-08-01 22:06:28 +02:00
if (trashbinFilename != null) {
builder.element("nc:trashbin-filename");
}
if (trashbinOriginalLocation != null) {
builder.element("nc:trashbin-original-location");
}
if (trashbinDeletionTime != null) {
builder.element("nc:trashbin-deletion-time");
}
for (final p in customProperties ?? []) {
2021-04-10 06:28:12 +02:00
builder.element(p);
}
});
});
return await _api.request("PROPFIND", path,
2021-04-24 13:50:57 +02:00
header: {
"Content-Type": "application/xml",
2021-04-24 13:50:57 +02:00
if (depth != null) "Depth": depth.toString(),
},
2021-04-10 06:28:12 +02:00
body: builder.buildDocument().toXmlString());
} catch (e) {
_log.severe("[propfind] Failed while propfind", e);
rethrow;
}
}
/// Set or remove custom properties
///
/// [namespaces] should be specified in the format {"URI": "prefix"}, eg,
/// {"DAV:": "d"}
Future<Response> proppatch({
2021-07-23 22:05:57 +02:00
required String path,
Map<String, String>? namespaces,
Map<String, dynamic>? set,
List<String>? remove,
2021-04-10 06:28:12 +02:00
}) async {
try {
final ns = <String, String>{
"DAV:": "d",
}..addAll(namespaces ?? {});
final builder = XmlBuilder();
builder
..processing("xml", "version=\"1.0\"")
..element("d:propertyupdate", namespaces: ns, nest: () {
2021-07-23 22:05:57 +02:00
if (set != null && set.isNotEmpty) {
2021-04-10 06:28:12 +02:00
builder.element("d:set", nest: () {
builder.element("d:prop", nest: () {
for (final e in set.entries) {
2021-09-15 08:58:06 +02:00
builder.element(e.key, nest: () {
2021-04-10 06:28:12 +02:00
builder.text("${e.value}");
});
}
});
});
}
2021-07-23 22:05:57 +02:00
if (remove != null && remove.isNotEmpty) {
2021-04-10 06:28:12 +02:00
builder.element("d:remove", nest: () {
builder.element("d:prop", nest: () {
for (final e in remove) {
2021-09-15 08:58:06 +02:00
builder.element(e);
2021-04-10 06:28:12 +02:00
}
});
});
}
});
return await _api.request(
"PROPPATCH",
path,
header: {
"Content-Type": "application/xml",
},
body: builder.buildDocument().toXmlString(),
);
2021-04-10 06:28:12 +02:00
} catch (e) {
_log.severe("[proppatch] Failed while proppatch", e);
rethrow;
}
}
/// A folder can be created by sending a MKCOL request to the folder
Future<Response> mkcol({
2021-07-23 22:05:57 +02:00
required String path,
2021-04-10 06:28:12 +02:00
}) async {
try {
return await _api.request("MKCOL", path);
} catch (e) {
_log.severe("[mkcol] Failed while get", e);
rethrow;
}
}
2021-05-20 17:43:53 +02:00
/// A file or folder can be copied by sending a COPY request to the file or
/// folder and specifying the [destinationUrl] as full url
Future<Response> copy({
2021-07-23 22:05:57 +02:00
required String path,
required String destinationUrl,
bool? overwrite,
2021-05-20 17:43:53 +02:00
}) async {
try {
return await _api.request("COPY", path, header: {
"Destination": Uri.parse(destinationUrl).toString(),
2021-05-20 17:43:53 +02:00
if (overwrite != null) "Overwrite": overwrite ? "T" : "F",
});
} catch (e) {
_log.severe("[copy] Failed while delete", e);
rethrow;
}
}
2021-05-20 17:45:06 +02:00
/// A file or folder can be moved by sending a MOVE request to the file or
/// folder and specifying the [destinationUrl] as full url
Future<Response> move({
2021-07-23 22:05:57 +02:00
required String path,
required String destinationUrl,
bool? overwrite,
2021-05-20 17:45:06 +02:00
}) async {
try {
return await _api.request("MOVE", path, header: {
"Destination": Uri.parse(destinationUrl).toString(),
2021-05-20 17:45:06 +02:00
if (overwrite != null) "Overwrite": overwrite ? "T" : "F",
});
} catch (e) {
_log.severe("[move] Failed while delete", e);
rethrow;
}
}
2022-01-25 11:08:13 +01:00
Future<Response> report({
required String path,
bool? favorite,
2022-01-29 12:31:32 +01:00
List<int>? systemtag,
2022-01-25 11:08:13 +01:00
}) async {
try {
final namespaces = <String, String>{
"DAV:": "d",
"http://owncloud.org/ns": "oc",
};
final builder = XmlBuilder();
builder
..processing("xml", "version=\"1.0\"")
..element("oc:filter-files", namespaces: namespaces, nest: () {
builder.element("oc:filter-rules", nest: () {
if (favorite != null) {
builder.element("oc:favorite", nest: () {
builder.text(favorite ? "1" : "0");
});
}
2022-01-29 12:31:32 +01:00
for (final t in systemtag ?? []) {
builder.element("oc:systemtag", nest: () {
builder.text(t);
});
}
2022-01-25 11:08:13 +01:00
});
builder.element("d:prop", nest: () {
builder.element("oc:fileid");
});
});
return await _api.request(
"REPORT",
path,
header: {
"Content-Type": "application/xml",
},
body: builder.buildDocument().toXmlString(),
);
} catch (e) {
_log.severe("[report] Failed while report", e);
rethrow;
}
}
2021-04-10 06:28:12 +02:00
}
2021-08-05 07:48:32 +02:00
2022-07-08 16:52:18 +02:00
class ApiOcs {
ApiOcs(this._api);
2021-08-05 07:48:32 +02:00
2022-07-08 16:52:18 +02:00
ApiOcsDav dav() => ApiOcsDav(this);
2022-07-08 16:52:18 +02:00
ApiOcsFacerecognition facerecognition() => ApiOcsFacerecognition(this);
2022-07-08 16:52:18 +02:00
ApiOcsFilesSharing filesSharing() => ApiOcsFilesSharing(this);
2021-08-05 07:48:32 +02:00
2021-09-15 08:58:06 +02:00
final Api _api;
2021-08-05 07:48:32 +02:00
}
2022-07-08 16:52:18 +02:00
class ApiOcsDav {
ApiOcsDav(this._ocs);
2021-08-05 07:48:32 +02:00
2022-07-08 16:52:18 +02:00
ApiOcsDavDirect direct() => ApiOcsDavDirect(this);
2021-08-05 07:48:32 +02:00
2022-07-08 16:52:18 +02:00
final ApiOcs _ocs;
2021-08-05 07:48:32 +02:00
}
2022-12-16 16:01:04 +01:00
@npLog
2022-07-08 16:52:18 +02:00
class ApiOcsDavDirect {
ApiOcsDavDirect(this._dav);
2021-08-05 07:48:32 +02:00
Future<Response> post({
required int fileId,
}) async {
try {
return await _dav._ocs._api.request(
"POST",
"ocs/v2.php/apps/dav/api/v1/direct",
header: {
"OCS-APIRequest": "true",
"Content-Type": "application/x-www-form-urlencoded",
},
queryParameters: {
"format": "json",
},
body: "fileId=$fileId",
);
} catch (e) {
_log.severe("[post] Failed while post", e);
rethrow;
}
}
2022-07-08 16:52:18 +02:00
final ApiOcsDav _dav;
2021-08-05 07:48:32 +02:00
}
2021-08-07 22:34:44 +02:00
2022-07-08 16:52:18 +02:00
class ApiOcsFacerecognition {
ApiOcsFacerecognition(this._ocs);
2022-07-08 16:52:18 +02:00
ApiOcsFacerecognitionPersons persons() => ApiOcsFacerecognitionPersons(this);
2022-07-08 16:52:18 +02:00
ApiOcsFacerecognitionPerson person(String name) =>
ApiOcsFacerecognitionPerson(this, name);
2022-07-08 16:52:18 +02:00
final ApiOcs _ocs;
}
2022-12-16 16:01:04 +01:00
@npLog
2022-07-08 16:52:18 +02:00
class ApiOcsFacerecognitionPersons {
ApiOcsFacerecognitionPersons(this._facerecognition);
Future<Response> get() async {
try {
return await _facerecognition._ocs._api.request(
"GET",
"ocs/v2.php/apps/facerecognition/api/v1/persons",
header: {
"OCS-APIRequest": "true",
},
queryParameters: {
"format": "json",
},
);
} catch (e) {
_log.severe("[get] Failed while get", e);
rethrow;
}
}
2022-07-08 16:52:18 +02:00
final ApiOcsFacerecognition _facerecognition;
}
2022-07-08 16:52:18 +02:00
class ApiOcsFacerecognitionPerson {
ApiOcsFacerecognitionPerson(this._facerecognition, this._name);
2021-09-10 19:10:26 +02:00
2022-07-08 16:52:18 +02:00
ApiOcsFacerecognitionPersonFaces faces() =>
ApiOcsFacerecognitionPersonFaces(this);
2021-09-10 19:10:26 +02:00
2022-07-08 16:52:18 +02:00
final ApiOcsFacerecognition _facerecognition;
2021-09-10 19:10:26 +02:00
final String _name;
}
2022-12-16 16:01:04 +01:00
@npLog
2022-07-08 16:52:18 +02:00
class ApiOcsFacerecognitionPersonFaces {
ApiOcsFacerecognitionPersonFaces(this._person);
2021-09-10 19:10:26 +02:00
Future<Response> get() async {
try {
return await _person._facerecognition._ocs._api.request(
"GET",
"ocs/v2.php/apps/facerecognition/api/v1/person/${_person._name}/faces",
header: {
"OCS-APIRequest": "true",
},
queryParameters: {
"format": "json",
},
);
} catch (e) {
_log.severe("[get] Failed while get", e);
rethrow;
}
}
2022-07-08 16:52:18 +02:00
final ApiOcsFacerecognitionPerson _person;
2021-09-10 19:10:26 +02:00
}
2022-07-08 16:52:18 +02:00
class ApiOcsFilesSharing {
ApiOcsFilesSharing(this._ocs);
2021-08-07 22:34:44 +02:00
2022-07-08 16:52:18 +02:00
ApiOcsFilesSharingShares shares() => ApiOcsFilesSharingShares(this);
2022-07-08 16:52:18 +02:00
ApiOcsFilesSharingShare share(String shareId) =>
ApiOcsFilesSharingShare(this, shareId);
2022-07-08 16:52:18 +02:00
ApiOcsFilesSharingSharees sharees() => ApiOcsFilesSharingSharees(this);
2021-08-07 22:34:44 +02:00
2022-07-08 16:52:18 +02:00
final ApiOcs _ocs;
2021-08-07 22:34:44 +02:00
}
2022-12-16 16:01:04 +01:00
@npLog
2022-07-08 16:52:18 +02:00
class ApiOcsFilesSharingShares {
ApiOcsFilesSharingShares(this._filesSharing);
2021-08-07 22:34:44 +02:00
/// Get Shares from a specific file or folder
///
2021-10-18 21:45:22 +02:00
/// If [sharedWithMe] is not null, [subfiles] and [path] are ignored. This is
/// a limitation of the server API.
///
2021-08-07 22:34:44 +02:00
/// See: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#get-shares-from-a-specific-file-or-folder
2021-10-11 19:03:37 +02:00
/// See: https://doc.owncloud.com/server/latest/developer_manual/core/apis/ocs-share-api.html#get-all-shares
2021-08-07 22:34:44 +02:00
Future<Response> get({
String? path,
bool? reshares,
bool? subfiles,
2021-10-11 19:03:37 +02:00
bool? sharedWithMe,
2021-08-07 22:34:44 +02:00
}) async {
try {
return await _filesSharing._ocs._api.request(
"GET",
"ocs/v2.php/apps/files_sharing/api/v1/shares",
header: {
"OCS-APIRequest": "true",
},
queryParameters: {
"format": "json",
if (path != null) "path": path,
if (reshares != null) "reshares": reshares.toString(),
if (subfiles != null) "subfiles": subfiles.toString(),
2021-10-11 19:03:37 +02:00
if (sharedWithMe != null) "shared_with_me": sharedWithMe.toString(),
2021-08-07 22:34:44 +02:00
},
);
} catch (e) {
_log.severe("[get] Failed while get", e);
rethrow;
}
}
/// Create a new Share
///
/// See: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#create-a-new-share
Future<Response> post({
required String path,
required int shareType,
String? shareWith,
String? publicUpload,
String? password,
int? permissions,
String? expireDate,
}) async {
try {
return await _filesSharing._ocs._api.request(
"POST",
"ocs/v2.php/apps/files_sharing/api/v1/shares",
header: {
"OCS-APIRequest": "true",
"Content-Type": "application/x-www-form-urlencoded",
},
queryParameters: {
"format": "json",
"path": path,
"shareType": shareType.toString(),
if (shareWith != null) "shareWith": shareWith,
if (publicUpload != null) "publicUpload": publicUpload,
if (password != null) "password": password,
if (password != null) "password": password,
if (expireDate != null) "expireDate": expireDate.toString(),
},
);
} catch (e) {
_log.severe("[post] Failed while post", e);
rethrow;
}
}
2022-07-08 16:52:18 +02:00
final ApiOcsFilesSharing _filesSharing;
2021-08-07 22:34:44 +02:00
}
2022-12-16 16:01:04 +01:00
@npLog
2022-07-08 16:52:18 +02:00
class ApiOcsFilesSharingShare {
ApiOcsFilesSharingShare(this._filesSharing, this._shareId);
2021-08-07 22:34:44 +02:00
/// Remove the given share
///
/// See: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#delete-share
/// * The type of share ID is listed as int in the document, however, the
2022-07-08 16:52:18 +02:00
/// share ID returned in [ApiOcsFilesSharingShares.get] is actually a string. To
2021-08-07 22:34:44 +02:00
/// keep it consistent, we'll use string instead
Future<Response> delete() async {
try {
return await _filesSharing._ocs._api.request(
"DELETE",
"ocs/v2.php/apps/files_sharing/api/v1/shares/$_shareId",
header: {
"OCS-APIRequest": "true",
},
);
} catch (e) {
_log.severe("[delete] Failed while delete", e);
rethrow;
}
}
2022-07-08 16:52:18 +02:00
final ApiOcsFilesSharing _filesSharing;
2021-08-07 22:34:44 +02:00
final String _shareId;
}
2022-12-16 16:01:04 +01:00
@npLog
2022-07-08 16:52:18 +02:00
class ApiOcsFilesSharingSharees {
ApiOcsFilesSharingSharees(this._filesSharing);
2021-08-07 22:34:44 +02:00
/// Get all sharees matching a search term
///
/// See: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-sharee-api.html#search-sharees
Future<Response> get({
String? search,
bool? lookup,
int? perPage,
String? itemType,
}) async {
try {
return await _filesSharing._ocs._api.request(
"GET",
"ocs/v1.php/apps/files_sharing/api/v1/sharees",
header: {
"OCS-APIRequest": "true",
},
queryParameters: {
"format": "json",
if (search != null) "search": search,
if (lookup != null) "lookup": lookup.toString(),
if (perPage != null) "perPage": perPage.toString(),
if (itemType != null) "itemType": itemType,
},
);
} catch (e) {
_log.severe("[get] Failed while get", e);
rethrow;
}
}
2022-07-08 16:52:18 +02:00
final ApiOcsFilesSharing _filesSharing;
2021-08-07 22:34:44 +02:00
}
2022-01-28 20:34:38 +01:00
2022-12-16 16:01:04 +01:00
@npLog
2022-07-08 16:52:18 +02:00
class ApiSystemtags {
const ApiSystemtags(this.api);
2022-01-29 12:31:32 +01:00
2022-08-05 10:19:03 +02:00
/// Retrieve a list of all tags
///
/// See: https://doc.owncloud.com/server/10.10/developer_manual/webdav_api/tags.html#list-tags
2022-01-29 12:31:32 +01:00
Future<Response> propfind({
id,
displayName,
userVisible,
userAssignable,
}) async {
const endpoint = "remote.php/dav/systemtags";
try {
if (id == null &&
displayName == null &&
userVisible == null &&
2022-08-05 10:19:03 +02:00
userAssignable == null) {
2022-01-29 12:31:32 +01:00
// no body
return await api.request("PROPFIND", endpoint);
}
final namespaces = <String, String>{
"DAV:": "d",
"http://owncloud.org/ns": "oc",
};
final builder = XmlBuilder();
builder
..processing("xml", "version=\"1.0\"")
..element("d:propfind", namespaces: namespaces, nest: () {
builder.element("d:prop", nest: () {
if (id != null) {
builder.element("oc:id");
}
if (displayName != null) {
builder.element("oc:display-name");
}
if (userVisible != null) {
builder.element("oc:user-visible");
}
if (userAssignable != null) {
builder.element("oc:user-assignable");
}
});
});
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;
}
}
final Api api;
}
2022-07-08 16:52:18 +02:00
class ApiSystemtagsRelations {
const ApiSystemtagsRelations(this.api);
2022-01-28 20:34:38 +01:00
2022-07-08 16:52:18 +02:00
ApiSystemtagsRelationsFiles files(int fileId) =>
ApiSystemtagsRelationsFiles(this, fileId);
2022-01-28 20:34:38 +01:00
final Api api;
}
2022-12-16 16:01:04 +01:00
@npLog
2022-07-08 16:52:18 +02:00
class ApiSystemtagsRelationsFiles {
const ApiSystemtagsRelationsFiles(this.systemtagsRelations, this.fileId);
2022-01-28 20:34:38 +01:00
2022-08-05 10:19:03 +02:00
/// Retrieve the tag ids and metadata of a given file
2022-01-28 20:34:38 +01:00
///
2022-08-05 10:19:03 +02:00
/// See: https://doc.owncloud.com/server/10.10/developer_manual/webdav_api/tags.html#retrieve-the-tag-ids-and-metadata-of-a-given-file
2022-01-28 20:34:38 +01:00
Future<Response> propfind({
id,
displayName,
userVisible,
userAssignable,
canAssign,
}) async {
final endpoint = "remote.php/dav/systemtags-relations/files/$fileId";
try {
if (id == null &&
displayName == null &&
userVisible == null &&
userAssignable == null &&
canAssign == null) {
// no body
return await systemtagsRelations.api.request("PROPFIND", endpoint);
}
final namespaces = <String, String>{
"DAV:": "d",
"http://owncloud.org/ns": "oc",
};
final builder = XmlBuilder();
builder
..processing("xml", "version=\"1.0\"")
..element("d:propfind", namespaces: namespaces, nest: () {
builder.element("d:prop", nest: () {
if (id != null) {
builder.element("oc:id");
}
if (displayName != null) {
builder.element("oc:display-name");
}
if (userVisible != null) {
builder.element("oc:user-visible");
}
if (userAssignable != null) {
builder.element("oc:user-assignable");
}
if (canAssign != null) {
builder.element("oc:can-assign");
}
});
});
return await systemtagsRelations.api.request(
"PROPFIND",
endpoint,
header: {
"Content-Type": "application/xml",
},
body: builder.buildDocument().toXmlString(),
);
} catch (e) {
_log.severe("[propfind] Failed while propfind", e);
rethrow;
}
}
2022-07-08 16:52:18 +02:00
final ApiSystemtagsRelations systemtagsRelations;
2022-01-28 20:34:38 +01:00
final int fileId;
}