mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-10 02:07:57 -06:00
Externalized API and models as own package
This commit is contained in:
@@ -1,17 +1,21 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:paperless_mobile/core/model/paperless_server_information.dart';
|
||||
import 'package:paperless_mobile/core/service/paperless_server_information_service.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/bloc/paperless_server_information_state.dart';
|
||||
|
||||
@singleton
|
||||
class PaperlessServerInformationCubit
|
||||
extends Cubit<PaperlessServerInformation> {
|
||||
final PaperlessServerInformationService service;
|
||||
extends Cubit<PaperlessServerInformationState> {
|
||||
final PaperlessServerStatsApi service;
|
||||
|
||||
PaperlessServerInformationCubit(this.service)
|
||||
: super(PaperlessServerInformation());
|
||||
: super(PaperlessServerInformationState());
|
||||
|
||||
Future<void> updateInformtion() async {
|
||||
emit(await service.getInformation());
|
||||
final information = await service.getServerInformation();
|
||||
emit(PaperlessServerInformationState(
|
||||
isLoaded: true,
|
||||
information: information,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
11
lib/core/bloc/paperless_server_information_state.dart
Normal file
11
lib/core/bloc/paperless_server_information_state.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
class PaperlessServerInformationState {
|
||||
final bool isLoaded;
|
||||
final PaperlessServerInformationModel? information;
|
||||
|
||||
PaperlessServerInformationState({
|
||||
this.isLoaded = false,
|
||||
this.information,
|
||||
});
|
||||
}
|
||||
@@ -1,35 +1,32 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:paperless_mobile/core/model/error_message.dart';
|
||||
import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/store/local_vault.dart';
|
||||
import 'package:http_interceptor/http_interceptor.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
@injectable
|
||||
class AuthenticationInterceptor implements InterceptorContract {
|
||||
AuthenticationCubit authenticationCubit;
|
||||
AuthenticationInterceptor(this.authenticationCubit);
|
||||
final LocalVault _localVault;
|
||||
AuthenticationInterceptor(this._localVault);
|
||||
|
||||
@override
|
||||
Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
|
||||
final authState = authenticationCubit.state;
|
||||
final auth = await _localVault.loadAuthenticationInformation();
|
||||
|
||||
if (kDebugMode) {
|
||||
log("Intercepted ${request.method} request to ${request.url.toString()}");
|
||||
}
|
||||
if (authState.authentication == null) {
|
||||
throw const ErrorMessage(ErrorCode.notAuthenticated);
|
||||
if (auth == null) {
|
||||
throw const PaperlessServerException(ErrorCode.notAuthenticated);
|
||||
}
|
||||
return request.copyWith(
|
||||
//Append server Url
|
||||
url: Uri.parse(
|
||||
authState.authentication!.serverUrl + request.url.toString()),
|
||||
headers: authState.authentication!.token.isEmpty
|
||||
url: Uri.parse(auth.serverUrl + request.url.toString()),
|
||||
headers: auth.token.isEmpty
|
||||
? request.headers
|
||||
: {
|
||||
...request.headers,
|
||||
'Authorization': 'Token ${authState.authentication!.token}'
|
||||
},
|
||||
: {...request.headers, 'Authorization': 'Token ${auth.token}'},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:paperless_mobile/core/model/error_message.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/generated/l10n.dart';
|
||||
|
||||
String translateError(BuildContext context, ErrorCode code) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'dart:typed_data';
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:paperless_mobile/core/model/error_message.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/service/connectivity_status.service.dart';
|
||||
import 'package:paperless_mobile/core/type/types.dart';
|
||||
import 'package:paperless_mobile/di_initializer.dart';
|
||||
@@ -24,8 +24,8 @@ class TimeoutClient implements BaseClient {
|
||||
Future<StreamedResponse> send(BaseRequest request) async {
|
||||
return getIt<BaseClient>().send(request).timeout(
|
||||
requestTimeout,
|
||||
onTimeout: () =>
|
||||
Future.error(const ErrorMessage(ErrorCode.requestTimedOut)),
|
||||
onTimeout: () => Future.error(
|
||||
const PaperlessServerException(ErrorCode.requestTimedOut)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ class TimeoutClient implements BaseClient {
|
||||
.delete(url, headers: headers, body: body, encoding: encoding)
|
||||
.timeout(
|
||||
requestTimeout,
|
||||
onTimeout: () =>
|
||||
Future.error(const ErrorMessage(ErrorCode.requestTimedOut)),
|
||||
onTimeout: () => Future.error(
|
||||
const PaperlessServerException(ErrorCode.requestTimedOut)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -62,8 +62,8 @@ class TimeoutClient implements BaseClient {
|
||||
return _handle400Error(
|
||||
await getIt<BaseClient>().get(url, headers: headers).timeout(
|
||||
requestTimeout,
|
||||
onTimeout: () =>
|
||||
Future.error(const ErrorMessage(ErrorCode.requestTimedOut)),
|
||||
onTimeout: () => Future.error(
|
||||
const PaperlessServerException(ErrorCode.requestTimedOut)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -77,8 +77,8 @@ class TimeoutClient implements BaseClient {
|
||||
return _handle400Error(
|
||||
await getIt<BaseClient>().head(url, headers: headers).timeout(
|
||||
requestTimeout,
|
||||
onTimeout: () =>
|
||||
Future.error(const ErrorMessage(ErrorCode.requestTimedOut)),
|
||||
onTimeout: () => Future.error(
|
||||
const PaperlessServerException(ErrorCode.requestTimedOut)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -96,8 +96,8 @@ class TimeoutClient implements BaseClient {
|
||||
.patch(url, headers: headers, body: body, encoding: encoding)
|
||||
.timeout(
|
||||
requestTimeout,
|
||||
onTimeout: () =>
|
||||
Future.error(const ErrorMessage(ErrorCode.requestTimedOut)),
|
||||
onTimeout: () => Future.error(
|
||||
const PaperlessServerException(ErrorCode.requestTimedOut)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -115,8 +115,8 @@ class TimeoutClient implements BaseClient {
|
||||
.post(url, headers: headers, body: body, encoding: encoding)
|
||||
.timeout(
|
||||
requestTimeout,
|
||||
onTimeout: () =>
|
||||
Future.error(const ErrorMessage(ErrorCode.requestTimedOut)),
|
||||
onTimeout: () => Future.error(
|
||||
const PaperlessServerException(ErrorCode.requestTimedOut)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -134,8 +134,8 @@ class TimeoutClient implements BaseClient {
|
||||
.put(url, headers: headers, body: body, encoding: encoding)
|
||||
.timeout(
|
||||
requestTimeout,
|
||||
onTimeout: () =>
|
||||
Future.error(const ErrorMessage(ErrorCode.requestTimedOut)),
|
||||
onTimeout: () => Future.error(
|
||||
const PaperlessServerException(ErrorCode.requestTimedOut)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -148,8 +148,8 @@ class TimeoutClient implements BaseClient {
|
||||
await _handleOfflineState();
|
||||
return getIt<BaseClient>().read(url, headers: headers).timeout(
|
||||
requestTimeout,
|
||||
onTimeout: () =>
|
||||
Future.error(const ErrorMessage(ErrorCode.requestTimedOut)),
|
||||
onTimeout: () => Future.error(
|
||||
const PaperlessServerException(ErrorCode.requestTimedOut)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -161,8 +161,8 @@ class TimeoutClient implements BaseClient {
|
||||
await _handleOfflineState();
|
||||
return getIt<BaseClient>().readBytes(url, headers: headers).timeout(
|
||||
requestTimeout,
|
||||
onTimeout: () =>
|
||||
Future.error(const ErrorMessage(ErrorCode.requestTimedOut)),
|
||||
onTimeout: () => Future.error(
|
||||
const PaperlessServerException(ErrorCode.requestTimedOut)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ class TimeoutClient implements BaseClient {
|
||||
|
||||
Future<void> _handleOfflineState() async {
|
||||
if (!(await connectivityStatusService.isConnectedToInternet())) {
|
||||
throw const ErrorMessage(ErrorCode.deviceOffline);
|
||||
throw const PaperlessServerException(ErrorCode.deviceOffline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
class ErrorMessage implements Exception {
|
||||
final ErrorCode code;
|
||||
final String? details;
|
||||
final StackTrace? stackTrace;
|
||||
final int? httpStatusCode;
|
||||
|
||||
const ErrorMessage(
|
||||
this.code, {
|
||||
this.details,
|
||||
this.stackTrace,
|
||||
this.httpStatusCode,
|
||||
});
|
||||
|
||||
const ErrorMessage.unknown() : this(ErrorCode.unknown);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "ErrorMessage(code: $code${stackTrace != null ? ', stackTrace: ${stackTrace.toString()}' : ''}${httpStatusCode != null ? ', httpStatusCode: $httpStatusCode' : ''})";
|
||||
}
|
||||
}
|
||||
|
||||
enum ErrorCode {
|
||||
unknown,
|
||||
authenticationFailed,
|
||||
notAuthenticated,
|
||||
documentUploadFailed,
|
||||
documentUpdateFailed,
|
||||
documentLoadFailed,
|
||||
documentDeleteFailed,
|
||||
documentBulkActionFailed,
|
||||
documentPreviewFailed,
|
||||
documentAsnQueryFailed,
|
||||
tagCreateFailed,
|
||||
tagLoadFailed,
|
||||
documentTypeCreateFailed,
|
||||
documentTypeLoadFailed,
|
||||
correspondentCreateFailed,
|
||||
correspondentLoadFailed,
|
||||
scanRemoveFailed,
|
||||
invalidClientCertificateConfiguration,
|
||||
biometricsNotSupported,
|
||||
biometricAuthenticationFailed,
|
||||
deviceOffline,
|
||||
serverUnreachable,
|
||||
similarQueryError,
|
||||
autocompleteQueryError,
|
||||
storagePathLoadFailed,
|
||||
storagePathCreateFailed,
|
||||
loadSavedViewsError,
|
||||
createSavedViewError,
|
||||
deleteSavedViewError,
|
||||
requestTimedOut,
|
||||
unsupportedFileFormat,
|
||||
missingClientCertificate;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
class PaperlessServerInformation {
|
||||
static const String versionHeader = 'x-version';
|
||||
static const String apiVersionHeader = 'x-api-version';
|
||||
static const String hostHeader = 'x-served-by';
|
||||
final String? version;
|
||||
final int? apiVersion;
|
||||
final String? username;
|
||||
final String? host;
|
||||
PaperlessServerInformation({
|
||||
this.host,
|
||||
this.username,
|
||||
this.version = 'unknown',
|
||||
this.apiVersion = 1,
|
||||
});
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:paperless_mobile/core/type/types.dart';
|
||||
|
||||
class PaperlessStatistics {
|
||||
final int documentsTotal;
|
||||
final int documentsInInbox;
|
||||
|
||||
PaperlessStatistics({
|
||||
required this.documentsTotal,
|
||||
required this.documentsInInbox,
|
||||
});
|
||||
|
||||
PaperlessStatistics.fromJson(JSON json)
|
||||
: documentsTotal = json['documents_total'],
|
||||
documentsInInbox = json['documents_inbox'];
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:paperless_mobile/core/model/paperless_statistics.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
class PaperlessStatisticsState {
|
||||
final bool isLoaded;
|
||||
final PaperlessStatistics? statistics;
|
||||
final PaperlessServerStatisticsModel? statistics;
|
||||
|
||||
PaperlessStatisticsState({
|
||||
required this.isLoaded,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:paperless_mobile/core/model/error_message.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
@@ -12,7 +12,7 @@ class FileService {
|
||||
) async {
|
||||
final dir = await documentsDirectory;
|
||||
if (dir == null) {
|
||||
throw const ErrorMessage.unknown(); //TODO: better handling
|
||||
throw const PaperlessServerException.unknown(); //TODO: better handling
|
||||
}
|
||||
File file = File("${dir.path}/$filename");
|
||||
return file..writeAsBytes(bytes);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:paperless_mobile/core/model/paperless_server_information.dart';
|
||||
import 'package:paperless_mobile/core/store/local_vault.dart';
|
||||
|
||||
@injectable
|
||||
class PaperlessServerInformationService {
|
||||
final BaseClient client;
|
||||
final LocalVault localStore;
|
||||
|
||||
PaperlessServerInformationService(
|
||||
@Named("timeoutClient") this.client,
|
||||
this.localStore,
|
||||
);
|
||||
|
||||
Future<PaperlessServerInformation> getInformation() async {
|
||||
final response = await client.get(Uri.parse("/api/ui_settings/"));
|
||||
final version =
|
||||
response.headers[PaperlessServerInformation.versionHeader] ?? 'unknown';
|
||||
final apiVersion = int.tryParse(
|
||||
response.headers[PaperlessServerInformation.apiVersionHeader] ?? '1');
|
||||
final String username =
|
||||
jsonDecode(utf8.decode(response.bodyBytes))['username'];
|
||||
final String? host =
|
||||
response.headers[PaperlessServerInformation.hostHeader] ??
|
||||
response.request?.headers[PaperlessServerInformation.hostHeader] ??
|
||||
('${response.request?.url.host}:${response.request?.url.port}');
|
||||
return PaperlessServerInformation(
|
||||
username: username,
|
||||
version: version,
|
||||
apiVersion: apiVersion,
|
||||
host: host,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:paperless_mobile/core/model/error_message.dart';
|
||||
import 'package:paperless_mobile/core/model/paperless_statistics.dart';
|
||||
import 'package:paperless_mobile/core/type/types.dart';
|
||||
|
||||
abstract class PaperlessStatisticsService {
|
||||
Future<PaperlessStatistics> getStatistics();
|
||||
}
|
||||
|
||||
@Injectable(as: PaperlessStatisticsService)
|
||||
class PaperlessStatisticsServiceImpl extends PaperlessStatisticsService {
|
||||
final BaseClient client;
|
||||
|
||||
PaperlessStatisticsServiceImpl(@Named('timeoutClient') this.client);
|
||||
|
||||
@override
|
||||
Future<PaperlessStatistics> getStatistics() async {
|
||||
final response = await client.get(Uri.parse('/api/statistics/'));
|
||||
if (response.statusCode == 200) {
|
||||
return PaperlessStatistics.fromJson(
|
||||
jsonDecode(utf8.decode(response.bodyBytes)) as JSON,
|
||||
);
|
||||
}
|
||||
throw const ErrorMessage.unknown();
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,13 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/bloc/document_status_cubit.dart';
|
||||
import 'package:paperless_mobile/core/model/document_processing_status.dart';
|
||||
import 'package:paperless_mobile/di_initializer.dart';
|
||||
import 'package:paperless_mobile/features/documents/model/document.model.dart';
|
||||
import 'package:paperless_mobile/features/documents/model/paged_search_result.dart';
|
||||
import 'package:paperless_mobile/features/login/model/authentication_information.dart';
|
||||
import 'package:paperless_mobile/util.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:web_socket_channel/io.dart';
|
||||
|
||||
abstract class StatusService {
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:paperless_mobile/core/model/error_message.dart';
|
||||
import 'package:paperless_mobile/core/type/types.dart';
|
||||
import 'package:paperless_mobile/di_initializer.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
const requestTimeout = Duration(seconds: 5);
|
||||
|
||||
Future<T> getSingleResult<T>(
|
||||
String url,
|
||||
T Function(JSON) fromJson,
|
||||
ErrorCode errorCode, {
|
||||
int minRequiredApiVersion = 1,
|
||||
}) async {
|
||||
final httpClient = getIt<BaseClient>(instanceName: "timeoutClient");
|
||||
final response = await httpClient.get(
|
||||
Uri.parse(url),
|
||||
headers: {'accept': 'application/json; version=$minRequiredApiVersion'},
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
return compute(
|
||||
fromJson,
|
||||
jsonDecode(utf8.decode(response.bodyBytes)) as JSON,
|
||||
);
|
||||
}
|
||||
throw ErrorMessage(errorCode);
|
||||
}
|
||||
|
||||
Future<List<T>> getCollection<T>(
|
||||
String url,
|
||||
T Function(JSON) fromJson,
|
||||
ErrorCode errorCode, {
|
||||
int minRequiredApiVersion = 1,
|
||||
}) async {
|
||||
final httpClient = getIt<BaseClient>(instanceName: "timeoutClient");
|
||||
final response = await httpClient.get(
|
||||
Uri.parse(url),
|
||||
headers: {'accept': 'application/json; version=$minRequiredApiVersion'},
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
final JSON body = jsonDecode(utf8.decode(response.bodyBytes));
|
||||
if (body.containsKey('count')) {
|
||||
if (body['count'] == 0) {
|
||||
return <T>[];
|
||||
} else {
|
||||
return compute(
|
||||
_collectionFromJson,
|
||||
_CollectionFromJsonSerializationParams(
|
||||
fromJson, (body['results'] as List).cast<JSON>()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw ErrorMessage(errorCode);
|
||||
}
|
||||
|
||||
List<T> _collectionFromJson<T>(
|
||||
_CollectionFromJsonSerializationParams<T> params) {
|
||||
return params.list.map<T>((result) => params.fromJson(result)).toList();
|
||||
}
|
||||
|
||||
class _CollectionFromJsonSerializationParams<T> {
|
||||
final T Function(JSON) fromJson;
|
||||
final List<JSON> list;
|
||||
|
||||
_CollectionFromJsonSerializationParams(this.fromJson, this.list);
|
||||
}
|
||||
Reference in New Issue
Block a user