mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-10 06:07:57 -06:00
fix: Add custom fields, translations, add app logs to login routes
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
enum CustomFieldDataType {
|
||||
text,
|
||||
boolean,
|
||||
date,
|
||||
url,
|
||||
integer,
|
||||
number,
|
||||
monetary;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -68,5 +68,8 @@ enum ErrorCode {
|
||||
loadTasksError,
|
||||
userNotFound,
|
||||
userAlreadyExists,
|
||||
updateSavedViewError;
|
||||
updateSavedViewError,
|
||||
customFieldCreateFailed,
|
||||
customFieldLoadFailed,
|
||||
customFieldDeleteFailed;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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')!),
|
||||
|
||||
Reference in New Issue
Block a user