api and storage restructure
This commit is contained in:
@@ -3,31 +3,25 @@ import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../model/account_data.dart';
|
||||
import '../../../model/endpoint_data.dart';
|
||||
import '../nextcloud_ocs.dart';
|
||||
import 'autocompleteResponse.dart';
|
||||
|
||||
class AutocompleteApi {
|
||||
Future<AutocompleteResponse> find(String query) async {
|
||||
var getParameters = <String, dynamic>{
|
||||
'search': query,
|
||||
'itemType': ' ',
|
||||
'itemId': ' ',
|
||||
'shareTypes[]': ['0'],
|
||||
'limit': '10',
|
||||
};
|
||||
|
||||
var headers = <String, String>{};
|
||||
headers.putIfAbsent('Accept', () => 'application/json');
|
||||
headers.putIfAbsent('OCS-APIRequest', () => 'true');
|
||||
headers.putIfAbsent('Authorization', AccountData().getBasicAuthHeader);
|
||||
|
||||
var endpoint = Uri.https(EndpointData().nextcloud().domain, '${EndpointData().nextcloud().path}/ocs/v2.php/core/autocomplete/get', getParameters);
|
||||
|
||||
var response = await http.get(endpoint, headers: headers);
|
||||
if(response.statusCode != HttpStatus.ok) throw Exception('Api call failed with ${response.statusCode}: ${response.body}');
|
||||
var result = response.body;
|
||||
return AutocompleteResponse.fromJson(jsonDecode(result)['ocs']);
|
||||
final endpoint = NextcloudOcs.uri(
|
||||
'core/autocomplete/get',
|
||||
queryParameters: {
|
||||
'search': query,
|
||||
'itemType': ' ',
|
||||
'itemId': ' ',
|
||||
'shareTypes[]': ['0'],
|
||||
'limit': '10',
|
||||
},
|
||||
);
|
||||
final response = await http.get(endpoint, headers: NextcloudOcs.headers());
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
throw Exception('Api call failed with ${response.statusCode}: ${response.body}');
|
||||
}
|
||||
return AutocompleteResponse.fromJson(jsonDecode(response.body)['ocs']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,21 +2,17 @@ import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../model/account_data.dart';
|
||||
import '../../../model/endpoint_data.dart';
|
||||
import '../nextcloud_ocs.dart';
|
||||
import 'fileSharingApiParams.dart';
|
||||
|
||||
class FileSharingApi {
|
||||
Future<void> share(FileSharingApiParams query) async {
|
||||
var headers = <String, String>{};
|
||||
headers.putIfAbsent('Accept', () => 'application/json');
|
||||
headers.putIfAbsent('OCS-APIRequest', () => 'true');
|
||||
headers.putIfAbsent('Authorization', AccountData().getBasicAuthHeader);
|
||||
|
||||
var endpoint = Uri.https(EndpointData().nextcloud().domain, '${EndpointData().nextcloud().path}/ocs/v2.php/apps/files_sharing/api/v1/shares', query.toJson().map((key, value) => MapEntry(key, value.toString())));
|
||||
var response = await http.post(endpoint, headers: headers);
|
||||
|
||||
if(response.statusCode != HttpStatus.ok) {
|
||||
final endpoint = NextcloudOcs.uri(
|
||||
'apps/files_sharing/api/v1/shares',
|
||||
queryParameters: query.toJson(),
|
||||
);
|
||||
final response = await http.post(endpoint, headers: NextcloudOcs.headers());
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
throw Exception('Api call failed with ${response.statusCode}: ${response.body}');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import '../../model/account_data.dart';
|
||||
import '../../model/endpoint_data.dart';
|
||||
|
||||
/// Shared helpers for Nextcloud OCS v2 endpoints.
|
||||
///
|
||||
/// Three call sites previously duplicated the same header dictionary and the
|
||||
/// same URI scaffolding (TalkApi, AutocompleteApi, FileSharingApi). Anything
|
||||
/// that talks to `https://<domain>/<base>/ocs/v2.php/...` should go through
|
||||
/// these two helpers so additions like a new header or a different auth
|
||||
/// scheme only need to change here.
|
||||
class NextcloudOcs {
|
||||
NextcloudOcs._();
|
||||
|
||||
/// The standard OCS request header set: JSON accept, OCS API marker,
|
||||
/// HTTP Basic auth from the active [AccountData].
|
||||
static Map<String, String> headers() => {
|
||||
'Accept': 'application/json',
|
||||
'OCS-APIRequest': 'true',
|
||||
'Authorization': AccountData().getBasicAuthHeader(),
|
||||
};
|
||||
|
||||
/// Builds an OCS URI by appending [pathSuffix] under `/ocs/v2.php/` of
|
||||
/// the configured Nextcloud endpoint. Query parameters are converted to
|
||||
/// strings (Uri rejects non-string values).
|
||||
static Uri uri(String pathSuffix, {Map<String, dynamic>? queryParameters}) {
|
||||
final endpoint = EndpointData().nextcloud();
|
||||
return Uri.https(
|
||||
endpoint.domain,
|
||||
'${endpoint.path}/ocs/v2.php/$pathSuffix',
|
||||
queryParameters?.map((key, value) => MapEntry(key, value.toString())),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../apiParams.dart';
|
||||
import '../../../apiResponse.dart';
|
||||
import '../talkApi.dart';
|
||||
|
||||
/// Small POST/DELETE-only Talk endpoints that have no response payload.
|
||||
/// Each class extends [TalkApi] with `assemble` returning `null`. They share
|
||||
/// no state — they're collected here purely to avoid eight near-empty files.
|
||||
|
||||
class SetFavorite extends TalkApi {
|
||||
final String chatToken;
|
||||
final bool favoriteState;
|
||||
|
||||
SetFavorite(this.chatToken, this.favoriteState) : super('v4/room/$chatToken/favorite', null);
|
||||
|
||||
@override
|
||||
ApiResponse? assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri, ApiParams? body, Map<String, String>? headers) =>
|
||||
favoriteState ? http.post(uri, headers: headers) : http.delete(uri, headers: headers);
|
||||
}
|
||||
|
||||
class LeaveRoom extends TalkApi {
|
||||
final String chatToken;
|
||||
|
||||
LeaveRoom(this.chatToken) : super('v4/room/$chatToken/participants/self', null);
|
||||
|
||||
@override
|
||||
ApiResponse? assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri, ApiParams? body, Map<String, String>? headers) =>
|
||||
http.delete(uri, headers: headers);
|
||||
}
|
||||
|
||||
class DeleteMessage extends TalkApi {
|
||||
final String chatToken;
|
||||
final int messageId;
|
||||
|
||||
DeleteMessage(this.chatToken, this.messageId) : super('v1/chat/$chatToken/$messageId', null);
|
||||
|
||||
@override
|
||||
ApiResponse? assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri, ApiParams? body, Map<String, String>? headers) =>
|
||||
http.delete(uri, headers: headers);
|
||||
}
|
||||
@@ -1,36 +1,26 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import '../../../requestCache.dart';
|
||||
import 'getChat.dart';
|
||||
import 'getChatParams.dart';
|
||||
import 'getChatResponse.dart';
|
||||
|
||||
class GetChatCache extends RequestCache<GetChatResponse> {
|
||||
String chatToken;
|
||||
|
||||
class GetChatCache extends SimpleCache<GetChatResponse> {
|
||||
GetChatCache({
|
||||
required void Function(GetChatResponse) onUpdate,
|
||||
void Function(Exception)? onError,
|
||||
required this.chatToken,
|
||||
super.onError,
|
||||
required String chatToken,
|
||||
}) : super(
|
||||
RequestCache.cacheNothing,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
cacheTime: RequestCache.cacheNothing,
|
||||
loader: () => GetChat(
|
||||
chatToken,
|
||||
GetChatParams(
|
||||
lookIntoFuture: GetChatParamsSwitch.off,
|
||||
setReadMarker: GetChatParamsSwitch.on,
|
||||
limit: 200,
|
||||
),
|
||||
).run(),
|
||||
fromJson: GetChatResponse.fromJson,
|
||||
onUpdate: onUpdate,
|
||||
) {
|
||||
start('nc-chat-$chatToken');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetChatResponse> onLoad() => GetChat(
|
||||
chatToken,
|
||||
GetChatParams(
|
||||
lookIntoFuture: GetChatParamsSwitch.off,
|
||||
setReadMarker: GetChatParamsSwitch.on,
|
||||
limit: 200,
|
||||
)
|
||||
).run();
|
||||
|
||||
@override
|
||||
GetChatResponse onLocalData(String json) => GetChatResponse.fromJson(jsonDecode(json));
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import '../../../apiParams.dart';
|
||||
import '../talkApi.dart';
|
||||
|
||||
class DeleteMessage extends TalkApi {
|
||||
String chatToken;
|
||||
int messageId;
|
||||
DeleteMessage(this.chatToken, this.messageId) : super('v1/chat/$chatToken/$messageId', null);
|
||||
|
||||
@override
|
||||
assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri, ApiParams? body, Map<String, String>? headers) => http.delete(uri, headers: headers);
|
||||
|
||||
}
|
||||
@@ -1,22 +1,17 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import '../../../requestCache.dart';
|
||||
import 'getParticipants.dart';
|
||||
import 'getParticipantsResponse.dart';
|
||||
|
||||
class GetParticipantsCache extends RequestCache<GetParticipantsResponse> {
|
||||
String chatToken;
|
||||
|
||||
GetParticipantsCache({required void Function(GetParticipantsResponse) onUpdate, required this.chatToken}) : super(RequestCache.cacheNothing, onUpdate) {
|
||||
class GetParticipantsCache extends SimpleCache<GetParticipantsResponse> {
|
||||
GetParticipantsCache({
|
||||
required void Function(GetParticipantsResponse) onUpdate,
|
||||
required String chatToken,
|
||||
}) : super(
|
||||
cacheTime: RequestCache.cacheNothing,
|
||||
loader: () => GetParticipants(chatToken).run(),
|
||||
fromJson: GetParticipantsResponse.fromJson,
|
||||
onUpdate: onUpdate,
|
||||
) {
|
||||
start('nc-chat-participants-$chatToken');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetParticipantsResponse> onLoad() => GetParticipants(
|
||||
chatToken,
|
||||
).run();
|
||||
|
||||
@override
|
||||
GetParticipantsResponse onLocalData(String json) => GetParticipantsResponse.fromJson(jsonDecode(json));
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import '../talkApi.dart';
|
||||
class LeaveRoom extends TalkApi {
|
||||
String chatToken;
|
||||
|
||||
LeaveRoom(this.chatToken) : super('v4/room/$chatToken/participants/self', null);
|
||||
|
||||
@override
|
||||
assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<Response> request(Uri uri, Object? body, Map<String, String>? headers) => http.delete(uri, headers: headers);
|
||||
}
|
||||
@@ -1,32 +1,15 @@
|
||||
import 'dart:convert';
|
||||
|
||||
|
||||
import '../../../requestCache.dart';
|
||||
import 'getRoom.dart';
|
||||
import 'getRoomParams.dart';
|
||||
import 'getRoomResponse.dart';
|
||||
|
||||
class GetRoomCache extends RequestCache<GetRoomResponse> {
|
||||
GetRoomCache({
|
||||
void Function(GetRoomResponse)? onUpdate,
|
||||
void Function(Exception)? onError,
|
||||
bool? renew,
|
||||
}) : super(
|
||||
RequestCache.cacheMinute,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
renew: renew,
|
||||
class GetRoomCache extends SimpleCache<GetRoomResponse> {
|
||||
GetRoomCache({super.onUpdate, super.onError, super.renew})
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheMinute,
|
||||
loader: () => GetRoom(GetRoomParams(includeStatus: true)).run(),
|
||||
fromJson: GetRoomResponse.fromJson,
|
||||
) {
|
||||
start('nc-rooms');
|
||||
}
|
||||
|
||||
@override
|
||||
GetRoomResponse onLocalData(String json) => GetRoomResponse.fromJson(jsonDecode(json));
|
||||
|
||||
@override
|
||||
Future<GetRoomResponse> onLoad() => GetRoom(
|
||||
GetRoomParams(
|
||||
includeStatus: true,
|
||||
)
|
||||
).run();
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import '../../../apiResponse.dart';
|
||||
|
||||
class SendMessageResponse extends ApiResponse {
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import '../talkApi.dart';
|
||||
|
||||
class SetFavorite extends TalkApi {
|
||||
String chatToken;
|
||||
bool favoriteState;
|
||||
|
||||
SetFavorite(this.chatToken, this.favoriteState) : super('v4/room/$chatToken/favorite', null);
|
||||
|
||||
@override
|
||||
assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<Response> request(Uri uri, Object? body, Map<String, String>? headers) {
|
||||
if(favoriteState) {
|
||||
return http.post(uri, headers: headers);
|
||||
} else {
|
||||
return http.delete(uri, headers: headers);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,12 +2,11 @@ import 'dart:developer';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../model/account_data.dart';
|
||||
import '../../../model/endpoint_data.dart';
|
||||
import '../../apiError.dart';
|
||||
import '../../apiParams.dart';
|
||||
import '../../apiRequest.dart';
|
||||
import '../../apiResponse.dart';
|
||||
import '../nextcloud_ocs.dart';
|
||||
|
||||
enum TalkApiMethod {
|
||||
get,
|
||||
@@ -19,7 +18,7 @@ enum TalkApiMethod {
|
||||
abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
|
||||
String path;
|
||||
ApiParams? body;
|
||||
Map<String, String>? headers = {};
|
||||
Map<String, String>? headers;
|
||||
Map<String, dynamic>? getParameters;
|
||||
|
||||
http.Response? response;
|
||||
@@ -30,36 +29,28 @@ abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
|
||||
T assemble(String raw);
|
||||
|
||||
Future<T> run() async {
|
||||
getParameters?.forEach((key, value) {
|
||||
getParameters?.update(key, (value) => value.toString());
|
||||
});
|
||||
|
||||
var endpoint = Uri.https(EndpointData().nextcloud().domain, '${EndpointData().nextcloud().path}/ocs/v2.php/apps/spreed/api/$path', getParameters);
|
||||
|
||||
headers ??= {};
|
||||
headers?.putIfAbsent('Accept', () => 'application/json');
|
||||
headers?.putIfAbsent('OCS-APIRequest', () => 'true');
|
||||
headers?.putIfAbsent('Authorization', AccountData().getBasicAuthHeader);
|
||||
final endpoint = NextcloudOcs.uri('apps/spreed/api/$path', queryParameters: getParameters);
|
||||
final mergedHeaders = {...NextcloudOcs.headers(), ...?headers};
|
||||
|
||||
http.Response? data;
|
||||
|
||||
try {
|
||||
data = await request(endpoint, body, headers);
|
||||
if(data == null) throw Exception('No response Data');
|
||||
if(data.statusCode >= 400 || data.statusCode < 200) throw Exception("Response status code '${data.statusCode}' might indicate an error");
|
||||
} catch(e) {
|
||||
data = await request(endpoint, body, mergedHeaders);
|
||||
if (data == null) throw Exception('No response Data');
|
||||
if (data.statusCode >= 400 || data.statusCode < 200) {
|
||||
throw Exception("Response status code '${data.statusCode}' might indicate an error");
|
||||
}
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
throw ApiError('Request $endpoint could not be dispatched: ${e.toString()}');
|
||||
}
|
||||
//dynamic jsonData = jsonDecode(data.body);
|
||||
|
||||
T assembled;
|
||||
try {
|
||||
assembled = assemble(data.body);
|
||||
final assembled = assemble(data.body);
|
||||
assembled?.headers = data.headers;
|
||||
return assembled;
|
||||
} catch (e) {
|
||||
var message = 'Error assembling Talk API ${T.toString()} message: ${e.toString()} response with request body: $body and request headers: ${headers.toString()}';
|
||||
final message = 'Error assembling Talk API ${T.toString()} message: ${e.toString()}'
|
||||
' response with request body: $body and request headers: $mergedHeaders';
|
||||
log(message);
|
||||
throw Exception(message);
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import '../getPoll/getPollStateResponse.dart';
|
||||
import '../talkApi.dart';
|
||||
import 'votePollParams.dart';
|
||||
|
||||
@Deprecated('VotePoll is broken')
|
||||
class VotePoll extends TalkApi {
|
||||
String token;
|
||||
int pollId;
|
||||
VotePoll({required this.token, required this.pollId, required VotePollParams params}) : super('v1/poll/$token/$pollId', params);
|
||||
|
||||
@override
|
||||
GetPollStateResponse assemble(String raw) => GetPollStateResponse.fromJson(jsonDecode(raw)['ocs']);
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri, Object? body, Map<String, String>? headers) {
|
||||
if(body is VotePollParams) {
|
||||
return http.post(uri, headers: headers, body: body.toJson().toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../../../apiParams.dart';
|
||||
|
||||
part 'votePollParams.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
@Deprecated('VotePoll is broken')
|
||||
class VotePollParams extends ApiParams {
|
||||
List<int> optionIds;
|
||||
|
||||
VotePollParams({required this.optionIds});
|
||||
factory VotePollParams.fromJson(Map<String, dynamic> json) => _$VotePollParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$VotePollParamsToJson(this);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'votePollParams.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
VotePollParams _$VotePollParamsFromJson(Map<String, dynamic> json) =>
|
||||
VotePollParams(
|
||||
optionIds: (json['optionIds'] as List<dynamic>)
|
||||
.map((e) => (e as num).toInt())
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$VotePollParamsToJson(VotePollParams instance) =>
|
||||
<String, dynamic>{'optionIds': instance.optionIds};
|
||||
@@ -6,34 +6,20 @@ import 'listFiles.dart';
|
||||
import 'listFilesParams.dart';
|
||||
import 'listFilesResponse.dart';
|
||||
|
||||
class ListFilesCache extends RequestCache<ListFilesResponse> {
|
||||
String path;
|
||||
|
||||
class ListFilesCache extends SimpleCache<ListFilesResponse> {
|
||||
ListFilesCache({
|
||||
required void Function(ListFilesResponse) onUpdate,
|
||||
void Function(ListFilesResponse)? onCacheData,
|
||||
void Function(ListFilesResponse)? onNetworkData,
|
||||
void Function(Exception)? onError,
|
||||
required this.path,
|
||||
super.onCacheData,
|
||||
super.onNetworkData,
|
||||
super.onError,
|
||||
required String path,
|
||||
}) : super(
|
||||
RequestCache.cacheNothing,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
onCacheData: onCacheData,
|
||||
onNetworkData: onNetworkData,
|
||||
cacheTime: RequestCache.cacheNothing,
|
||||
loader: () => ListFiles(ListFilesParams(path)).run(),
|
||||
fromJson: ListFilesResponse.fromJson,
|
||||
onUpdate: onUpdate,
|
||||
) {
|
||||
var bytes = utf8.encode('MarianumMobile-$path');
|
||||
var cacheName = md5.convert(bytes).toString();
|
||||
final cacheName = md5.convert(utf8.encode('MarianumMobile-$path')).toString();
|
||||
start('wd-folder-$cacheName');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ListFilesResponse> onLoad() async {
|
||||
var data = await ListFiles(ListFilesParams(path)).run();
|
||||
return data;
|
||||
}
|
||||
|
||||
@override
|
||||
ListFilesResponse onLocalData(String json) => ListFilesResponse.fromJson(jsonDecode(json));
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user