fix: Add custom fields, translations, add app logs to login routes

This commit is contained in:
Anton Stubenbord
2023-12-10 12:48:32 +01:00
parent 5e5e5d2df3
commit 9f6b95f506
102 changed files with 2399 additions and 1088 deletions

View File

@@ -0,0 +1,9 @@
enum CustomFieldDataType {
text,
boolean,
date,
url,
integer,
number,
monetary;
}

View File

@@ -0,0 +1,26 @@
import 'package:equatable/equatable.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:paperless_api/src/models/custom_field_data_type.dart';
part 'custom_field_model.g.dart';
@JsonSerializable()
class CustomFieldModel with EquatableMixin {
final int? id;
final String name;
final CustomFieldDataType dataType;
CustomFieldModel({
this.id,
required this.name,
required this.dataType,
});
@override
List<Object?> get props => [id, name, dataType];
factory CustomFieldModel.fromJson(Map<String, dynamic> json) =>
_$CustomFieldModelFromJson(json);
Map<String, dynamic> toJson() => _$CustomFieldModelToJson(this);
}

View File

@@ -4,6 +4,7 @@ import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
import 'package:paperless_api/src/models/custom_field_model.dart';
import 'package:paperless_api/src/models/search_hit.dart';
part 'document_model.g.dart';
@@ -50,6 +51,7 @@ class DocumentModel extends Equatable {
// Only present if full_perms=true
final Permissions? permissions;
final Iterable<CustomFieldModel>? customFields;
const DocumentModel({
required this.id,
@@ -69,6 +71,7 @@ class DocumentModel extends Equatable {
this.owner,
this.userCanChange,
this.permissions,
this.customFields,
});
factory DocumentModel.fromJson(Map<String, dynamic> json) =>
@@ -89,6 +92,8 @@ class DocumentModel extends Equatable {
int? Function()? archiveSerialNumber,
String? originalFileName,
String? archivedFileName,
int? Function()? owner,
bool? userCanChange,
}) {
return DocumentModel(
id: id,
@@ -107,6 +112,8 @@ class DocumentModel extends Equatable {
? archiveSerialNumber()
: this.archiveSerialNumber,
archivedFileName: archivedFileName ?? this.archivedFileName,
owner: owner != null ? owner() : this.owner,
userCanChange: userCanChange ?? this.userCanChange,
);
}
@@ -114,17 +121,18 @@ class DocumentModel extends Equatable {
List<Object?> get props => [
id,
title,
content.hashCode,
tags,
documentType,
storagePath,
content,
correspondent,
documentType,
tags,
storagePath,
created,
modified,
added,
archiveSerialNumber,
originalFileName,
archivedFileName,
storagePath,
owner,
userCanChange,
];
}

View File

@@ -19,9 +19,12 @@ class PaperlessFormValidationException implements Exception {
return validationMessages[formKey];
}
static bool canParse(Map<String, dynamic> json) {
return json.values
.every((element) => element is String || element is List);
static bool canParse(dynamic json) {
if (json is Map<String, dynamic>) {
return json.values
.every((element) => element is String || element is List);
}
return false;
}
factory PaperlessFormValidationException.fromJson(Map<String, dynamic> json) {

View File

@@ -11,9 +11,8 @@ class PaperlessServerMessageException implements Exception {
static bool canParse(dynamic json) {
if (json is Map<String, dynamic>) {
return json.containsKey('detail') && json.length == 1;
} else {
return false;
}
return false;
}
factory PaperlessServerMessageException.fromJson(Map<String, dynamic> json) =>

View File

@@ -68,5 +68,8 @@ enum ErrorCode {
loadTasksError,
userNotFound,
userAlreadyExists,
updateSavedViewError;
updateSavedViewError,
customFieldCreateFailed,
customFieldLoadFailed,
customFieldDeleteFailed;
}

View File

@@ -14,9 +14,15 @@ class PaperlessServerStatisticsModel {
: documentsTotal = json['documents_total'] ?? 0,
documentsInInbox = json['documents_inbox'] ?? 0,
totalChars = json["character_count"],
fileTypeCounts = (json['document_file_type_counts'] as List? ?? [])
.map((e) => DocumentFileTypeCount.fromJson(e))
.toList();
fileTypeCounts =
_parseFileTypeCounts(json['document_file_type_counts']);
static List<DocumentFileTypeCount> _parseFileTypeCounts(dynamic value) {
if (value is List) {
return value.map((e) => DocumentFileTypeCount.fromJson(e)).toList();
}
return [];
}
}
class DocumentFileTypeCount {

View File

@@ -0,0 +1,8 @@
import 'package:paperless_api/src/models/custom_field_model.dart';
abstract interface class CustomFieldsApi {
Future<CustomFieldModel> createCustomField(CustomFieldModel customField);
Future<CustomFieldModel?> getCustomField(int id);
Future<List<CustomFieldModel>> getCustomFields();
Future<int> deleteCustomField(CustomFieldModel customField);
}

View File

@@ -0,0 +1,72 @@
import 'package:dio/dio.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_api/src/extensions/dio_exception_extension.dart';
import 'package:paperless_api/src/models/custom_field_model.dart';
import 'package:paperless_api/src/modules/custom_fields/custom_fields_api.dart';
import 'package:paperless_api/src/request_utils.dart';
class CustomFieldsApiImpl implements CustomFieldsApi {
final Dio _dio;
const CustomFieldsApiImpl(this._dio);
@override
Future<CustomFieldModel> createCustomField(
CustomFieldModel customField) async {
try {
final response = await _dio.post(
"/api/custom_fields/",
data: customField.toJson(),
options: Options(
validateStatus: (status) => status == 201,
),
);
return CustomFieldModel.fromJson(response.data);
} on DioException catch (exception) {
throw exception.unravel(
orElse: const PaperlessApiException(
ErrorCode.customFieldCreateFailed,
),
);
}
}
@override
Future<int> deleteCustomField(CustomFieldModel customField) async {
try {
await _dio.delete(
"/api/custom_fields/${customField.id}/",
options: Options(
validateStatus: (status) => status == 204,
),
);
return customField.id!;
} on DioException catch (exception) {
throw exception.unravel(
orElse: const PaperlessApiException(
ErrorCode.customFieldDeleteFailed,
),
);
}
}
@override
Future<CustomFieldModel?> getCustomField(int id) {
return getSingleResult(
'/api/custom_fields/$id/',
CustomFieldModel.fromJson,
ErrorCode.customFieldLoadFailed,
client: _dio,
);
}
@override
Future<List<CustomFieldModel>> getCustomFields() {
return getCollection(
'/api/custom_fields/?page=1&page_size=100000',
CustomFieldModel.fromJson,
ErrorCode.customFieldLoadFailed,
client: _dio,
);
}
}

View File

@@ -109,7 +109,10 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi {
);
} on DioException catch (exception) {
throw exception.unravel(
orElse: const PaperlessApiException(ErrorCode.documentLoadFailed),
orElse: PaperlessApiException(
ErrorCode.documentLoadFailed,
details: exception.message,
),
);
}
}

View File

@@ -4,7 +4,6 @@ import 'dart:io';
import 'package:dio/dio.dart';
import 'package:paperless_api/src/extensions/dio_exception_extension.dart';
import 'package:paperless_api/src/models/models.dart';
import 'package:paperless_api/src/models/paperless_api_exception.dart';
import 'package:paperless_api/src/modules/labels_api/paperless_labels_api.dart';
import 'package:paperless_api/src/request_utils.dart';

View File

@@ -14,7 +14,7 @@ import 'paperless_server_stats_api.dart';
///
class PaperlessServerStatsApiImpl implements PaperlessServerStatsApi {
final Dio client;
static const _fallbackVersion = '0.0.0';
PaperlessServerStatsApiImpl(this.client);
@override
@@ -24,7 +24,10 @@ class PaperlessServerStatsApiImpl implements PaperlessServerStatsApi {
"/api/remote_version/",
options: Options(validateStatus: (status) => status == 200),
);
final version = response.data["version"] as String;
var version = response.data["version"] as String;
if (version == _fallbackVersion) {
version = response.headers.value('x-version') ?? _fallbackVersion;
}
final updateAvailable = response.data["update_available"] as bool;
return PaperlessServerInformationModel(
apiVersion: int.parse(response.headers.value('x-api-version')!),