mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-09 18:07:50 -06:00
Removed suggestions from inbox, added translations, added paging to inbox, visual updates, changed default matching algorithm to auto
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
class LocalDateTimeJsonConverter extends JsonConverter<DateTime, String> {
|
||||
const LocalDateTimeJsonConverter();
|
||||
|
||||
@override
|
||||
DateTime fromJson(String json) {
|
||||
return DateTime.parse(json).toLocal();
|
||||
}
|
||||
|
||||
@override
|
||||
String toJson(DateTime object) {
|
||||
return object.toIso8601String();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||
|
||||
part 'document_model.g.dart';
|
||||
|
||||
@LocalDateTimeJsonConverter()
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class DocumentModel extends Equatable {
|
||||
static const idKey = 'id';
|
||||
static const titleKey = 'title';
|
||||
@@ -47,50 +53,18 @@ class DocumentModel extends Equatable {
|
||||
this.storagePath,
|
||||
});
|
||||
|
||||
DocumentModel.fromJson(Map<String, dynamic> json)
|
||||
: id = json[idKey],
|
||||
title = json[titleKey],
|
||||
content = json[contentKey],
|
||||
created = DateTime.parse(json[createdKey]),
|
||||
modified = DateTime.parse(json[modifiedKey]),
|
||||
added = DateTime.parse(json[addedKey]),
|
||||
archiveSerialNumber = json[asnKey],
|
||||
originalFileName = json[originalFileNameKey],
|
||||
archivedFileName = json[archivedFileNameKey],
|
||||
tags = (json[tagsKey] as List<dynamic>).cast<int>(),
|
||||
correspondent = json[correspondentKey],
|
||||
documentType = json[documentTypeKey],
|
||||
storagePath = json[storagePathKey];
|
||||
factory DocumentModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$DocumentModelFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
idKey: id,
|
||||
titleKey: title,
|
||||
asnKey: archiveSerialNumber,
|
||||
archivedFileNameKey: archivedFileName,
|
||||
contentKey: content,
|
||||
correspondentKey: correspondent,
|
||||
documentTypeKey: documentType,
|
||||
createdKey: created.toIso8601String(),
|
||||
modifiedKey: modified.toIso8601String(),
|
||||
addedKey: added.toIso8601String(),
|
||||
originalFileNameKey: originalFileName,
|
||||
tagsKey: tags.toList(),
|
||||
storagePathKey: storagePath,
|
||||
};
|
||||
}
|
||||
Map<String, dynamic> toJson() => _$DocumentModelToJson(this);
|
||||
|
||||
DocumentModel copyWith({
|
||||
String? title,
|
||||
String? content,
|
||||
bool overwriteTags = false,
|
||||
Iterable<int>? tags,
|
||||
bool overwriteDocumentType = false,
|
||||
int? documentType,
|
||||
bool overwriteCorrespondent = false,
|
||||
int? correspondent,
|
||||
bool overwriteStoragePath = false,
|
||||
int? storagePath,
|
||||
int? Function()? documentType,
|
||||
int? Function()? correspondent,
|
||||
int? Function()? storagePath,
|
||||
DateTime? created,
|
||||
DateTime? modified,
|
||||
DateTime? added,
|
||||
@@ -102,11 +76,10 @@ class DocumentModel extends Equatable {
|
||||
id: id,
|
||||
title: title ?? this.title,
|
||||
content: content ?? this.content,
|
||||
documentType: overwriteDocumentType ? documentType : this.documentType,
|
||||
correspondent:
|
||||
overwriteCorrespondent ? correspondent : this.correspondent,
|
||||
storagePath: overwriteDocumentType ? storagePath : this.storagePath,
|
||||
tags: overwriteTags ? tags ?? [] : this.tags,
|
||||
documentType: documentType?.call() ?? this.documentType,
|
||||
correspondent: correspondent?.call() ?? this.correspondent,
|
||||
storagePath: storagePath?.call() ?? this.storagePath,
|
||||
tags: tags ?? this.tags,
|
||||
created: created ?? this.created,
|
||||
modified: modified ?? this.modified,
|
||||
added: added ?? this.added,
|
||||
|
||||
45
packages/paperless_api/lib/src/models/document_model.g.dart
Normal file
45
packages/paperless_api/lib/src/models/document_model.g.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'document_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
DocumentModel _$DocumentModelFromJson(Map<String, dynamic> json) =>
|
||||
DocumentModel(
|
||||
id: json['id'] as int,
|
||||
title: json['title'] as String,
|
||||
content: json['content'] as String?,
|
||||
tags: (json['tags'] as List<dynamic>?)?.map((e) => e as int) ??
|
||||
const <int>[],
|
||||
documentType: json['document_type'] as int?,
|
||||
correspondent: json['correspondent'] as int?,
|
||||
created: const LocalDateTimeJsonConverter()
|
||||
.fromJson(json['created'] as String),
|
||||
modified: const LocalDateTimeJsonConverter()
|
||||
.fromJson(json['modified'] as String),
|
||||
added:
|
||||
const LocalDateTimeJsonConverter().fromJson(json['added'] as String),
|
||||
archiveSerialNumber: json['archive_serial_number'] as int?,
|
||||
originalFileName: json['original_file_name'] as String,
|
||||
archivedFileName: json['archived_file_name'] as String?,
|
||||
storagePath: json['storage_path'] as int?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$DocumentModelToJson(DocumentModel instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'title': instance.title,
|
||||
'content': instance.content,
|
||||
'tags': instance.tags.toList(),
|
||||
'document_type': instance.documentType,
|
||||
'correspondent': instance.correspondent,
|
||||
'storage_path': instance.storagePath,
|
||||
'created': const LocalDateTimeJsonConverter().toJson(instance.created),
|
||||
'modified': const LocalDateTimeJsonConverter().toJson(instance.modified),
|
||||
'added': const LocalDateTimeJsonConverter().toJson(instance.added),
|
||||
'archive_serial_number': instance.archiveSerialNumber,
|
||||
'original_file_name': instance.originalFileName,
|
||||
'archived_file_name': instance.archivedFileName,
|
||||
};
|
||||
@@ -1,14 +1,16 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||
import 'package:paperless_api/src/models/document_model.dart';
|
||||
|
||||
part 'field_suggestions.g.dart';
|
||||
|
||||
@LocalDateTimeJsonConverter()
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class FieldSuggestions {
|
||||
final int? documentId;
|
||||
final Iterable<int> correspondents;
|
||||
final Iterable<int> tags;
|
||||
final Iterable<int> documentTypes;
|
||||
final Iterable<int> storagePaths;
|
||||
final Iterable<DateTime> dates;
|
||||
|
||||
const FieldSuggestions({
|
||||
@@ -16,28 +18,24 @@ class FieldSuggestions {
|
||||
this.correspondents = const [],
|
||||
this.tags = const [],
|
||||
this.documentTypes = const [],
|
||||
this.storagePaths = const [],
|
||||
this.dates = const [],
|
||||
});
|
||||
|
||||
bool get hasSuggestedCorrespondents => correspondents.isNotEmpty;
|
||||
bool get hasSuggestedTags => tags.isNotEmpty;
|
||||
bool get hasSuggestedDocumentTypes => documentTypes.isNotEmpty;
|
||||
bool get hasSuggestedStoragePaths => storagePaths.isNotEmpty;
|
||||
bool get hasSuggestedDates => dates.isNotEmpty;
|
||||
|
||||
bool get hasSuggestions =>
|
||||
hasSuggestedCorrespondents ||
|
||||
hasSuggestedDates ||
|
||||
hasSuggestedTags ||
|
||||
hasSuggestedStoragePaths ||
|
||||
hasSuggestedDocumentTypes;
|
||||
|
||||
int get suggestionsCount =>
|
||||
(correspondents.isNotEmpty ? 1 : 0) +
|
||||
(tags.isNotEmpty ? 1 : 0) +
|
||||
(documentTypes.isNotEmpty ? 1 : 0) +
|
||||
(storagePaths.isNotEmpty ? 1 : 0) +
|
||||
(dates.isNotEmpty ? 1 : 0);
|
||||
|
||||
FieldSuggestions forDocumentId(int id) => FieldSuggestions(
|
||||
@@ -46,9 +44,53 @@ class FieldSuggestions {
|
||||
dates: dates,
|
||||
documentTypes: documentTypes,
|
||||
tags: tags,
|
||||
storagePaths: storagePaths,
|
||||
);
|
||||
|
||||
///
|
||||
/// Removes the suggestions given in the parameters.
|
||||
///
|
||||
FieldSuggestions difference({
|
||||
Iterable<int> tags = const {},
|
||||
Iterable<int> correspondents = const {},
|
||||
Iterable<int> documentTypes = const {},
|
||||
Iterable<DateTime> dates = const {},
|
||||
}) {
|
||||
return copyWith(
|
||||
tags: this.tags.toSet().difference(tags.toSet()),
|
||||
correspondents:
|
||||
this.correspondents.toSet().difference(correspondents.toSet()),
|
||||
documentTypes:
|
||||
this.documentTypes.toSet().difference(documentTypes.toSet()),
|
||||
dates: this.dates.toSet().difference(dates.toSet()),
|
||||
);
|
||||
}
|
||||
|
||||
FieldSuggestions documentDifference(DocumentModel document) {
|
||||
return difference(
|
||||
tags: document.tags,
|
||||
correspondents:
|
||||
[document.correspondent].where((e) => e != null).map((e) => e!),
|
||||
documentTypes:
|
||||
[document.documentType].where((e) => e != null).map((e) => e!),
|
||||
dates: [document.created],
|
||||
);
|
||||
}
|
||||
|
||||
FieldSuggestions copyWith({
|
||||
Iterable<int>? tags,
|
||||
Iterable<int>? correspondents,
|
||||
Iterable<int>? documentTypes,
|
||||
Iterable<DateTime>? dates,
|
||||
int? documentId,
|
||||
}) {
|
||||
return FieldSuggestions(
|
||||
tags: tags ?? this.tags,
|
||||
correspondents: correspondents ?? this.correspondents,
|
||||
dates: dates ?? this.dates,
|
||||
documentId: documentId ?? this.documentId,
|
||||
);
|
||||
}
|
||||
|
||||
factory FieldSuggestions.fromJson(Map<String, dynamic> json) =>
|
||||
_$FieldSuggestionsFromJson(json);
|
||||
|
||||
|
||||
@@ -16,11 +16,8 @@ FieldSuggestions _$FieldSuggestionsFromJson(Map<String, dynamic> json) =>
|
||||
documentTypes:
|
||||
(json['document_types'] as List<dynamic>?)?.map((e) => e as int) ??
|
||||
const [],
|
||||
storagePaths:
|
||||
(json['storage_paths'] as List<dynamic>?)?.map((e) => e as int) ??
|
||||
const [],
|
||||
dates: (json['dates'] as List<dynamic>?)
|
||||
?.map((e) => DateTime.parse(e as String)) ??
|
||||
dates: (json['dates'] as List<dynamic>?)?.map((e) =>
|
||||
const LocalDateTimeJsonConverter().fromJson(e as String)) ??
|
||||
const [],
|
||||
);
|
||||
|
||||
@@ -30,6 +27,7 @@ Map<String, dynamic> _$FieldSuggestionsToJson(FieldSuggestions instance) =>
|
||||
'correspondents': instance.correspondents.toList(),
|
||||
'tags': instance.tags.toList(),
|
||||
'document_types': instance.documentTypes.toList(),
|
||||
'storage_paths': instance.storagePaths.toList(),
|
||||
'dates': instance.dates.map((e) => e.toIso8601String()).toList(),
|
||||
'dates': instance.dates
|
||||
.map(const LocalDateTimeJsonConverter().toJson)
|
||||
.toList(),
|
||||
};
|
||||
|
||||
@@ -2,6 +2,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/constants.dart';
|
||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||
|
||||
import 'query_parameters/tags_query/any_assigned_tags_query.dart';
|
||||
import 'query_parameters/tags_query/exclude_tag_id_query.dart';
|
||||
@@ -13,6 +14,7 @@ part 'filter_rule_model.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class FilterRule with EquatableMixin {
|
||||
static const _dateTimeConverter = LocalDateTimeJsonConverter();
|
||||
static const int titleRule = 0;
|
||||
static const int asnRule = 2;
|
||||
static const int correspondentRule = 3;
|
||||
@@ -95,66 +97,72 @@ class FilterRule with EquatableMixin {
|
||||
if (filter.created is AbsoluteDateRangeQuery) {
|
||||
return filter.copyWith(
|
||||
created: (filter.created as AbsoluteDateRangeQuery)
|
||||
.copyWith(before: DateTime.parse(value!)),
|
||||
.copyWith(before: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
} else {
|
||||
return filter.copyWith(
|
||||
created: AbsoluteDateRangeQuery(before: DateTime.parse(value!)),
|
||||
created: AbsoluteDateRangeQuery(
|
||||
before: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
}
|
||||
case createdAfterRule:
|
||||
if (filter.created is AbsoluteDateRangeQuery) {
|
||||
return filter.copyWith(
|
||||
created: (filter.created as AbsoluteDateRangeQuery)
|
||||
.copyWith(after: DateTime.parse(value!)),
|
||||
.copyWith(after: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
} else {
|
||||
return filter.copyWith(
|
||||
created: AbsoluteDateRangeQuery(after: DateTime.parse(value!)),
|
||||
created: AbsoluteDateRangeQuery(
|
||||
after: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
}
|
||||
case addedBeforeRule:
|
||||
if (filter.added is AbsoluteDateRangeQuery) {
|
||||
return filter.copyWith(
|
||||
added: (filter.added as AbsoluteDateRangeQuery)
|
||||
.copyWith(before: DateTime.parse(value!)),
|
||||
.copyWith(before: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
} else {
|
||||
return filter.copyWith(
|
||||
added: AbsoluteDateRangeQuery(before: DateTime.parse(value!)),
|
||||
added: AbsoluteDateRangeQuery(
|
||||
before: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
}
|
||||
case addedAfterRule:
|
||||
if (filter.added is AbsoluteDateRangeQuery) {
|
||||
return filter.copyWith(
|
||||
added: (filter.added as AbsoluteDateRangeQuery)
|
||||
.copyWith(after: DateTime.parse(value!)),
|
||||
.copyWith(after: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
} else {
|
||||
return filter.copyWith(
|
||||
added: AbsoluteDateRangeQuery(after: DateTime.parse(value!)),
|
||||
added: AbsoluteDateRangeQuery(
|
||||
after: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
}
|
||||
case modifiedBeforeRule:
|
||||
if (filter.modified is AbsoluteDateRangeQuery) {
|
||||
return filter.copyWith(
|
||||
modified: (filter.modified as AbsoluteDateRangeQuery)
|
||||
.copyWith(before: DateTime.parse(value!)),
|
||||
.copyWith(before: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
} else {
|
||||
return filter.copyWith(
|
||||
modified: AbsoluteDateRangeQuery(before: DateTime.parse(value!)),
|
||||
modified: AbsoluteDateRangeQuery(
|
||||
before: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
}
|
||||
case modifiedAfterRule:
|
||||
if (filter.modified is AbsoluteDateRangeQuery) {
|
||||
return filter.copyWith(
|
||||
modified: (filter.modified as AbsoluteDateRangeQuery)
|
||||
.copyWith(after: DateTime.parse(value!)),
|
||||
.copyWith(after: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
} else {
|
||||
return filter.copyWith(
|
||||
added: AbsoluteDateRangeQuery(after: DateTime.parse(value!)),
|
||||
added: AbsoluteDateRangeQuery(
|
||||
after: _dateTimeConverter.fromJson(value!)),
|
||||
);
|
||||
}
|
||||
case titleAndContentRule:
|
||||
@@ -347,15 +355,16 @@ class FilterRule with EquatableMixin {
|
||||
}
|
||||
|
||||
//Join values of all extended filter rules if exist
|
||||
if (filterRules.isNotEmpty) {
|
||||
final FilterRule extendedFilterRule = filterRules
|
||||
.where((r) => r.ruleType == extendedRule)
|
||||
.reduce((previousValue, element) => previousValue.copyWith(
|
||||
value: previousValue.value! + element.value!,
|
||||
));
|
||||
if (filterRules.isNotEmpty &&
|
||||
filterRules.where((e) => e.ruleType == FilterRule.extendedRule).length >
|
||||
1) {
|
||||
final mergedExtendedRule = filterRules
|
||||
.where((r) => r.ruleType == FilterRule.extendedRule)
|
||||
.map((e) => e.value)
|
||||
.join(",");
|
||||
filterRules
|
||||
..removeWhere((element) => element.ruleType == extendedRule)
|
||||
..add(extendedFilterRule);
|
||||
..add(FilterRule(FilterRule.extendedRule, mergedExtendedRule));
|
||||
}
|
||||
return filterRules;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||
import 'package:paperless_api/src/models/labels/label_model.dart';
|
||||
import 'package:paperless_api/src/models/labels/matching_algorithm.dart';
|
||||
|
||||
part 'correspondent_model.g.dart';
|
||||
|
||||
@LocalDateTimeJsonConverter()
|
||||
@JsonSerializable(includeIfNull: false, fieldRename: FieldRename.snake)
|
||||
class Correspondent extends Label {
|
||||
final DateTime? lastCorrespondence;
|
||||
@@ -13,7 +15,7 @@ class Correspondent extends Label {
|
||||
required super.name,
|
||||
super.slug,
|
||||
super.match,
|
||||
super.matchingAlgorithm,
|
||||
required super.matchingAlgorithm,
|
||||
super.isInsensitive,
|
||||
super.documentCount,
|
||||
this.lastCorrespondence,
|
||||
|
||||
@@ -12,13 +12,13 @@ Correspondent _$CorrespondentFromJson(Map<String, dynamic> json) =>
|
||||
name: json['name'] as String,
|
||||
slug: json['slug'] as String?,
|
||||
match: json['match'] as String?,
|
||||
matchingAlgorithm: $enumDecodeNullable(
|
||||
_$MatchingAlgorithmEnumMap, json['matching_algorithm']),
|
||||
matchingAlgorithm:
|
||||
$enumDecode(_$MatchingAlgorithmEnumMap, json['matching_algorithm']),
|
||||
isInsensitive: json['is_insensitive'] as bool?,
|
||||
documentCount: json['document_count'] as int?,
|
||||
lastCorrespondence: json['last_correspondence'] == null
|
||||
? null
|
||||
: DateTime.parse(json['last_correspondence'] as String),
|
||||
lastCorrespondence: _$JsonConverterFromJson<String, DateTime>(
|
||||
json['last_correspondence'],
|
||||
const LocalDateTimeJsonConverter().fromJson),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$CorrespondentToJson(Correspondent instance) {
|
||||
@@ -34,12 +34,14 @@ Map<String, dynamic> _$CorrespondentToJson(Correspondent instance) {
|
||||
val['name'] = instance.name;
|
||||
writeNotNull('slug', instance.slug);
|
||||
writeNotNull('match', instance.match);
|
||||
writeNotNull('matching_algorithm',
|
||||
_$MatchingAlgorithmEnumMap[instance.matchingAlgorithm]);
|
||||
val['matching_algorithm'] =
|
||||
_$MatchingAlgorithmEnumMap[instance.matchingAlgorithm]!;
|
||||
writeNotNull('is_insensitive', instance.isInsensitive);
|
||||
writeNotNull('document_count', instance.documentCount);
|
||||
writeNotNull(
|
||||
'last_correspondence', instance.lastCorrespondence?.toIso8601String());
|
||||
'last_correspondence',
|
||||
_$JsonConverterToJson<String, DateTime>(instance.lastCorrespondence,
|
||||
const LocalDateTimeJsonConverter().toJson));
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -48,6 +50,18 @@ const _$MatchingAlgorithmEnumMap = {
|
||||
MatchingAlgorithm.allWords: 2,
|
||||
MatchingAlgorithm.exactMatch: 3,
|
||||
MatchingAlgorithm.regex: 4,
|
||||
MatchingAlgorithm.similarWord: 5,
|
||||
MatchingAlgorithm.fuzzy: 5,
|
||||
MatchingAlgorithm.auto: 6,
|
||||
};
|
||||
|
||||
Value? _$JsonConverterFromJson<Json, Value>(
|
||||
Object? json,
|
||||
Value? Function(Json json) fromJson,
|
||||
) =>
|
||||
json == null ? null : fromJson(json as Json);
|
||||
|
||||
Json? _$JsonConverterToJson<Json, Value>(
|
||||
Value? value,
|
||||
Json? Function(Value value) toJson,
|
||||
) =>
|
||||
value == null ? null : toJson(value);
|
||||
|
||||
@@ -10,7 +10,7 @@ class DocumentType extends Label {
|
||||
required super.name,
|
||||
super.slug,
|
||||
super.match,
|
||||
super.matchingAlgorithm,
|
||||
required super.matchingAlgorithm,
|
||||
super.isInsensitive,
|
||||
super.documentCount,
|
||||
});
|
||||
|
||||
@@ -11,8 +11,8 @@ DocumentType _$DocumentTypeFromJson(Map<String, dynamic> json) => DocumentType(
|
||||
name: json['name'] as String,
|
||||
slug: json['slug'] as String?,
|
||||
match: json['match'] as String?,
|
||||
matchingAlgorithm: $enumDecodeNullable(
|
||||
_$MatchingAlgorithmEnumMap, json['matching_algorithm']),
|
||||
matchingAlgorithm:
|
||||
$enumDecode(_$MatchingAlgorithmEnumMap, json['matching_algorithm']),
|
||||
isInsensitive: json['is_insensitive'] as bool?,
|
||||
documentCount: json['document_count'] as int?,
|
||||
);
|
||||
@@ -30,8 +30,8 @@ Map<String, dynamic> _$DocumentTypeToJson(DocumentType instance) {
|
||||
val['name'] = instance.name;
|
||||
writeNotNull('slug', instance.slug);
|
||||
writeNotNull('match', instance.match);
|
||||
writeNotNull('matching_algorithm',
|
||||
_$MatchingAlgorithmEnumMap[instance.matchingAlgorithm]);
|
||||
val['matching_algorithm'] =
|
||||
_$MatchingAlgorithmEnumMap[instance.matchingAlgorithm]!;
|
||||
writeNotNull('is_insensitive', instance.isInsensitive);
|
||||
writeNotNull('document_count', instance.documentCount);
|
||||
return val;
|
||||
@@ -42,6 +42,6 @@ const _$MatchingAlgorithmEnumMap = {
|
||||
MatchingAlgorithm.allWords: 2,
|
||||
MatchingAlgorithm.exactMatch: 3,
|
||||
MatchingAlgorithm.regex: 4,
|
||||
MatchingAlgorithm.similarWord: 5,
|
||||
MatchingAlgorithm.fuzzy: 5,
|
||||
MatchingAlgorithm.auto: 6,
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ abstract class Label extends Equatable implements Comparable {
|
||||
@JsonKey()
|
||||
final String? match;
|
||||
@JsonKey()
|
||||
final MatchingAlgorithm? matchingAlgorithm;
|
||||
final MatchingAlgorithm matchingAlgorithm;
|
||||
@JsonKey()
|
||||
final bool? isInsensitive;
|
||||
@JsonKey()
|
||||
@@ -30,8 +30,8 @@ abstract class Label extends Equatable implements Comparable {
|
||||
const Label({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.matchingAlgorithm,
|
||||
this.match,
|
||||
this.matchingAlgorithm,
|
||||
this.isInsensitive,
|
||||
this.documentCount,
|
||||
this.slug,
|
||||
|
||||
@@ -6,7 +6,7 @@ enum MatchingAlgorithm {
|
||||
allWords(2, "All: Match all of the following words"),
|
||||
exactMatch(3, "Exact: Match the following string"),
|
||||
regex(4, "Regex: Match the regular expression"),
|
||||
similarWord(5, "Similar: Match a similar word"),
|
||||
fuzzy(5, "Similar: Match a similar word"),
|
||||
auto(6, "Auto: Learn automatic assignment");
|
||||
|
||||
final int value;
|
||||
|
||||
@@ -13,7 +13,7 @@ class StoragePath extends Label {
|
||||
required super.name,
|
||||
super.slug,
|
||||
super.match,
|
||||
super.matchingAlgorithm,
|
||||
required super.matchingAlgorithm,
|
||||
super.isInsensitive,
|
||||
super.documentCount,
|
||||
required this.path,
|
||||
|
||||
@@ -11,8 +11,8 @@ StoragePath _$StoragePathFromJson(Map<String, dynamic> json) => StoragePath(
|
||||
name: json['name'] as String,
|
||||
slug: json['slug'] as String?,
|
||||
match: json['match'] as String?,
|
||||
matchingAlgorithm: $enumDecodeNullable(
|
||||
_$MatchingAlgorithmEnumMap, json['matching_algorithm']),
|
||||
matchingAlgorithm:
|
||||
$enumDecode(_$MatchingAlgorithmEnumMap, json['matching_algorithm']),
|
||||
isInsensitive: json['is_insensitive'] as bool?,
|
||||
documentCount: json['document_count'] as int?,
|
||||
path: json['path'] as String?,
|
||||
@@ -31,8 +31,8 @@ Map<String, dynamic> _$StoragePathToJson(StoragePath instance) {
|
||||
val['name'] = instance.name;
|
||||
writeNotNull('slug', instance.slug);
|
||||
writeNotNull('match', instance.match);
|
||||
writeNotNull('matching_algorithm',
|
||||
_$MatchingAlgorithmEnumMap[instance.matchingAlgorithm]);
|
||||
val['matching_algorithm'] =
|
||||
_$MatchingAlgorithmEnumMap[instance.matchingAlgorithm]!;
|
||||
writeNotNull('is_insensitive', instance.isInsensitive);
|
||||
writeNotNull('document_count', instance.documentCount);
|
||||
writeNotNull('path', instance.path);
|
||||
@@ -44,6 +44,6 @@ const _$MatchingAlgorithmEnumMap = {
|
||||
MatchingAlgorithm.allWords: 2,
|
||||
MatchingAlgorithm.exactMatch: 3,
|
||||
MatchingAlgorithm.regex: 4,
|
||||
MatchingAlgorithm.similarWord: 5,
|
||||
MatchingAlgorithm.fuzzy: 5,
|
||||
MatchingAlgorithm.auto: 6,
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ class Tag extends Label {
|
||||
super.documentCount,
|
||||
super.isInsensitive,
|
||||
super.match,
|
||||
super.matchingAlgorithm,
|
||||
required super.matchingAlgorithm,
|
||||
super.slug,
|
||||
Color? color,
|
||||
this.textColor,
|
||||
@@ -84,13 +84,14 @@ class Tag extends Label {
|
||||
match,
|
||||
];
|
||||
|
||||
//FIXME: Why is this not generated?!
|
||||
factory Tag.fromJson(Map<String, dynamic> json) {
|
||||
const $MatchingAlgorithmEnumMap = {
|
||||
MatchingAlgorithm.anyWord: 1,
|
||||
MatchingAlgorithm.allWords: 2,
|
||||
MatchingAlgorithm.exactMatch: 3,
|
||||
MatchingAlgorithm.regex: 4,
|
||||
MatchingAlgorithm.similarWord: 5,
|
||||
MatchingAlgorithm.fuzzy: 5,
|
||||
MatchingAlgorithm.auto: 6,
|
||||
};
|
||||
|
||||
@@ -100,8 +101,8 @@ class Tag extends Label {
|
||||
documentCount: json['document_count'] as int?,
|
||||
isInsensitive: json['is_insensitive'] as bool?,
|
||||
match: json['match'] as String?,
|
||||
matchingAlgorithm: $enumDecodeNullable(
|
||||
$MatchingAlgorithmEnumMap, json['matching_algorithm']),
|
||||
matchingAlgorithm:
|
||||
$enumDecode($MatchingAlgorithmEnumMap, json['matching_algorithm']),
|
||||
slug: json['slug'] as String?,
|
||||
textColor: _colorFromJson(json['text_color']),
|
||||
isInboxTag: json['is_inbox_tag'] as bool?,
|
||||
@@ -118,7 +119,7 @@ class Tag extends Label {
|
||||
MatchingAlgorithm.allWords: 2,
|
||||
MatchingAlgorithm.exactMatch: 3,
|
||||
MatchingAlgorithm.regex: 4,
|
||||
MatchingAlgorithm.similarWord: 5,
|
||||
MatchingAlgorithm.fuzzy: 5,
|
||||
MatchingAlgorithm.auto: 6,
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ class PagedSearchResult<T> extends Equatable {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get pageSize => results.length;
|
||||
|
||||
const PagedSearchResult({
|
||||
required this.count,
|
||||
required this.next,
|
||||
@@ -80,11 +82,11 @@ class PagedSearchResult<T> extends Equatable {
|
||||
return PagedSearchResult.fromJsonT(serializer.json, serializer.converter);
|
||||
}
|
||||
|
||||
PagedSearchResult copyWith({
|
||||
PagedSearchResult<T> copyWith({
|
||||
int? count,
|
||||
String? next,
|
||||
String? previous,
|
||||
List<DocumentModel>? results,
|
||||
List<T>? results,
|
||||
}) {
|
||||
return PagedSearchResult(
|
||||
count: count ?? this.count,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/src/constants.dart';
|
||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||
|
||||
import 'date_range_query.dart';
|
||||
import 'date_range_query_field.dart';
|
||||
@@ -8,7 +9,10 @@ part 'absolute_date_range_query.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class AbsoluteDateRangeQuery extends DateRangeQuery {
|
||||
@LocalDateTimeJsonConverter()
|
||||
final DateTime? after;
|
||||
|
||||
@LocalDateTimeJsonConverter()
|
||||
final DateTime? before;
|
||||
|
||||
const AbsoluteDateRangeQuery({this.after, this.before});
|
||||
|
||||
@@ -9,17 +9,29 @@ part of 'absolute_date_range_query.dart';
|
||||
AbsoluteDateRangeQuery _$AbsoluteDateRangeQueryFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
AbsoluteDateRangeQuery(
|
||||
after: json['after'] == null
|
||||
? null
|
||||
: DateTime.parse(json['after'] as String),
|
||||
before: json['before'] == null
|
||||
? null
|
||||
: DateTime.parse(json['before'] as String),
|
||||
after: _$JsonConverterFromJson<String, DateTime>(
|
||||
json['after'], const LocalDateTimeJsonConverter().fromJson),
|
||||
before: _$JsonConverterFromJson<String, DateTime>(
|
||||
json['before'], const LocalDateTimeJsonConverter().fromJson),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AbsoluteDateRangeQueryToJson(
|
||||
AbsoluteDateRangeQuery instance) =>
|
||||
<String, dynamic>{
|
||||
'after': instance.after?.toIso8601String(),
|
||||
'before': instance.before?.toIso8601String(),
|
||||
'after': _$JsonConverterToJson<String, DateTime>(
|
||||
instance.after, const LocalDateTimeJsonConverter().toJson),
|
||||
'before': _$JsonConverterToJson<String, DateTime>(
|
||||
instance.before, const LocalDateTimeJsonConverter().toJson),
|
||||
};
|
||||
|
||||
Value? _$JsonConverterFromJson<Json, Value>(
|
||||
Object? json,
|
||||
Value? Function(Json json) fromJson,
|
||||
) =>
|
||||
json == null ? null : fromJson(json as Json);
|
||||
|
||||
Json? _$JsonConverterToJson<Json, Value>(
|
||||
Value? value,
|
||||
Json? Function(Value value) toJson,
|
||||
) =>
|
||||
value == null ? null : toJson(value);
|
||||
|
||||
21
packages/paperless_api/lib/src/models/search_hit.dart
Normal file
21
packages/paperless_api/lib/src/models/search_hit.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'search_hit.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class SearchHit {
|
||||
final double? score;
|
||||
final String? highlights;
|
||||
final int? rank;
|
||||
|
||||
SearchHit({
|
||||
this.score,
|
||||
required this.highlights,
|
||||
required this.rank,
|
||||
});
|
||||
|
||||
factory SearchHit.fromJson(Map<String, dynamic> json) =>
|
||||
_$SearchHitFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$SearchHitToJson(this);
|
||||
}
|
||||
19
packages/paperless_api/lib/src/models/search_hit.g.dart
Normal file
19
packages/paperless_api/lib/src/models/search_hit.g.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'search_hit.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
SearchHit _$SearchHitFromJson(Map<String, dynamic> json) => SearchHit(
|
||||
score: (json['score'] as num?)?.toDouble(),
|
||||
highlights: json['highlights'] as String?,
|
||||
rank: json['rank'] as int?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SearchHitToJson(SearchHit instance) => <String, dynamic>{
|
||||
'score': instance.score,
|
||||
'highlights': instance.highlights,
|
||||
'rank': instance.rank,
|
||||
};
|
||||
@@ -1,6 +1,14 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||
import 'package:paperless_api/src/models/document_model.dart';
|
||||
import 'package:paperless_api/src/models/search_hit.dart';
|
||||
|
||||
part 'similar_document_model.g.dart';
|
||||
|
||||
@LocalDateTimeJsonConverter()
|
||||
@JsonSerializable()
|
||||
class SimilarDocumentModel extends DocumentModel {
|
||||
@JsonKey(name: '__search_hit__')
|
||||
final SearchHit searchHit;
|
||||
|
||||
const SimilarDocumentModel({
|
||||
@@ -20,39 +28,9 @@ class SimilarDocumentModel extends DocumentModel {
|
||||
super.tags,
|
||||
});
|
||||
|
||||
factory SimilarDocumentModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$SimilarDocumentModelFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = super.toJson();
|
||||
json['__search_hit__'] = searchHit.toJson();
|
||||
return json;
|
||||
}
|
||||
|
||||
SimilarDocumentModel.fromJson(Map<String, dynamic> json)
|
||||
: searchHit = SearchHit.fromJson(json),
|
||||
super.fromJson(json);
|
||||
}
|
||||
|
||||
class SearchHit {
|
||||
final double? score;
|
||||
final String? highlights;
|
||||
final int? rank;
|
||||
|
||||
SearchHit({
|
||||
this.score,
|
||||
required this.highlights,
|
||||
required this.rank,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'score': score,
|
||||
'highlights': highlights,
|
||||
'rank': rank,
|
||||
};
|
||||
}
|
||||
|
||||
SearchHit.fromJson(Map<String, dynamic> json)
|
||||
: score = json['score'],
|
||||
highlights = json['highlights'],
|
||||
rank = json['rank'];
|
||||
Map<String, dynamic> toJson() => _$SimilarDocumentModelToJson(this);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'similar_document_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
SimilarDocumentModel _$SimilarDocumentModelFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
SimilarDocumentModel(
|
||||
id: json['id'] as int,
|
||||
title: json['title'] as String,
|
||||
documentType: json['documentType'] as int?,
|
||||
correspondent: json['correspondent'] as int?,
|
||||
created: const LocalDateTimeJsonConverter()
|
||||
.fromJson(json['created'] as String),
|
||||
modified: const LocalDateTimeJsonConverter()
|
||||
.fromJson(json['modified'] as String),
|
||||
added:
|
||||
const LocalDateTimeJsonConverter().fromJson(json['added'] as String),
|
||||
originalFileName: json['originalFileName'] as String,
|
||||
searchHit:
|
||||
SearchHit.fromJson(json['__search_hit__'] as Map<String, dynamic>),
|
||||
archiveSerialNumber: json['archiveSerialNumber'] as int?,
|
||||
archivedFileName: json['archivedFileName'] as String?,
|
||||
content: json['content'] as String?,
|
||||
storagePath: json['storagePath'] as int?,
|
||||
tags: (json['tags'] as List<dynamic>?)?.map((e) => e as int) ??
|
||||
const <int>[],
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SimilarDocumentModelToJson(
|
||||
SimilarDocumentModel instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'title': instance.title,
|
||||
'content': instance.content,
|
||||
'tags': instance.tags.toList(),
|
||||
'documentType': instance.documentType,
|
||||
'correspondent': instance.correspondent,
|
||||
'storagePath': instance.storagePath,
|
||||
'created': const LocalDateTimeJsonConverter().toJson(instance.created),
|
||||
'modified': const LocalDateTimeJsonConverter().toJson(instance.modified),
|
||||
'added': const LocalDateTimeJsonConverter().toJson(instance.added),
|
||||
'archiveSerialNumber': instance.archiveSerialNumber,
|
||||
'originalFileName': instance.originalFileName,
|
||||
'archivedFileName': instance.archivedFileName,
|
||||
'__search_hit__': instance.searchHit,
|
||||
};
|
||||
@@ -1,10 +1,12 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||
import 'package:paperless_api/src/request_utils.dart';
|
||||
import 'task_status.dart';
|
||||
|
||||
part 'task.g.dart';
|
||||
|
||||
@LocalDateTimeJsonConverter()
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class Task extends Equatable {
|
||||
final int id;
|
||||
|
||||
@@ -10,10 +10,10 @@ Task _$TaskFromJson(Map<String, dynamic> json) => Task(
|
||||
id: json['id'] as int,
|
||||
taskId: json['task_id'] as String?,
|
||||
taskFileName: json['task_file_name'] as String?,
|
||||
dateCreated: DateTime.parse(json['date_created'] as String),
|
||||
dateDone: json['date_done'] == null
|
||||
? null
|
||||
: DateTime.parse(json['date_done'] as String),
|
||||
dateCreated: const LocalDateTimeJsonConverter()
|
||||
.fromJson(json['date_created'] as String),
|
||||
dateDone: _$JsonConverterFromJson<String, DateTime>(
|
||||
json['date_done'], const LocalDateTimeJsonConverter().fromJson),
|
||||
type: json['type'] as String?,
|
||||
status: $enumDecodeNullable(_$TaskStatusEnumMap, json['status']),
|
||||
acknowledged: json['acknowledged'] as bool? ?? false,
|
||||
@@ -25,8 +25,10 @@ Map<String, dynamic> _$TaskToJson(Task instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'task_id': instance.taskId,
|
||||
'task_file_name': instance.taskFileName,
|
||||
'date_created': instance.dateCreated.toIso8601String(),
|
||||
'date_done': instance.dateDone?.toIso8601String(),
|
||||
'date_created':
|
||||
const LocalDateTimeJsonConverter().toJson(instance.dateCreated),
|
||||
'date_done': _$JsonConverterToJson<String, DateTime>(
|
||||
instance.dateDone, const LocalDateTimeJsonConverter().toJson),
|
||||
'type': instance.type,
|
||||
'status': _$TaskStatusEnumMap[instance.status],
|
||||
'result': instance.result,
|
||||
@@ -34,9 +36,21 @@ Map<String, dynamic> _$TaskToJson(Task instance) => <String, dynamic>{
|
||||
'related_document': instance.relatedDocument,
|
||||
};
|
||||
|
||||
Value? _$JsonConverterFromJson<Json, Value>(
|
||||
Object? json,
|
||||
Value? Function(Json json) fromJson,
|
||||
) =>
|
||||
json == null ? null : fromJson(json as Json);
|
||||
|
||||
const _$TaskStatusEnumMap = {
|
||||
TaskStatus.started: 'STARTED',
|
||||
TaskStatus.pending: 'PENDING',
|
||||
TaskStatus.failure: 'FAILURE',
|
||||
TaskStatus.success: 'SUCCESS',
|
||||
};
|
||||
|
||||
Json? _$JsonConverterToJson<Json, Value>(
|
||||
Value? value,
|
||||
Json? Function(Value value) toJson,
|
||||
) =>
|
||||
value == null ? null : toJson(value);
|
||||
|
||||
@@ -2,10 +2,14 @@ import 'dart:convert';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_api/src/constants.dart';
|
||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||
|
||||
class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi {
|
||||
static const _dateTimeConverter = LocalDateTimeJsonConverter();
|
||||
|
||||
final Dio client;
|
||||
|
||||
PaperlessDocumentsApiImpl(this.client);
|
||||
@@ -21,16 +25,19 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi {
|
||||
int? correspondent,
|
||||
Iterable<int> tags = const [],
|
||||
}) async {
|
||||
final formData = FormData()
|
||||
..files.add(
|
||||
MapEntry(
|
||||
'document',
|
||||
MultipartFile.fromBytes(documentBytes, filename: filename),
|
||||
),
|
||||
)
|
||||
..fields.add(MapEntry('title', title));
|
||||
final formData = FormData();
|
||||
formData.files.add(
|
||||
MapEntry(
|
||||
'document',
|
||||
MultipartFile.fromBytes(documentBytes, filename: filename),
|
||||
),
|
||||
);
|
||||
formData.fields.add(MapEntry('title', title));
|
||||
|
||||
if (createdAt != null) {
|
||||
formData.fields.add(MapEntry('created', apiDateFormat.format(createdAt)));
|
||||
formData.fields.add(
|
||||
MapEntry('created', apiDateFormat.format(createdAt)),
|
||||
);
|
||||
}
|
||||
if (correspondent != null) {
|
||||
formData.fields.add(MapEntry('correspondent', jsonEncode(correspondent)));
|
||||
@@ -42,8 +49,10 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi {
|
||||
formData.fields.add(MapEntry('tags', tag.toString()));
|
||||
}
|
||||
try {
|
||||
final response =
|
||||
await client.post('/api/documents/post_document/', data: formData);
|
||||
final response = await client.post(
|
||||
'/api/documents/post_document/',
|
||||
data: formData,
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
if (response.data is String && response.data != "OK") {
|
||||
return response.data;
|
||||
|
||||
Reference in New Issue
Block a user