mirror of
https://github.com/immich-app/immich.git
synced 2025-12-19 17:23:21 +03:00
feat: add config options & cron entries for checks
This commit is contained in:
3
mobile/openapi/README.md
generated
3
mobile/openapi/README.md
generated
@@ -569,6 +569,9 @@ Class | Method | HTTP request | Description
|
||||
- [SystemConfigGeneratedFullsizeImageDto](doc//SystemConfigGeneratedFullsizeImageDto.md)
|
||||
- [SystemConfigGeneratedImageDto](doc//SystemConfigGeneratedImageDto.md)
|
||||
- [SystemConfigImageDto](doc//SystemConfigImageDto.md)
|
||||
- [SystemConfigIntegrityChecks](doc//SystemConfigIntegrityChecks.md)
|
||||
- [SystemConfigIntegrityChecksumJob](doc//SystemConfigIntegrityChecksumJob.md)
|
||||
- [SystemConfigIntegrityJob](doc//SystemConfigIntegrityJob.md)
|
||||
- [SystemConfigJobDto](doc//SystemConfigJobDto.md)
|
||||
- [SystemConfigLibraryDto](doc//SystemConfigLibraryDto.md)
|
||||
- [SystemConfigLibraryScanDto](doc//SystemConfigLibraryScanDto.md)
|
||||
|
||||
3
mobile/openapi/lib/api.dart
generated
3
mobile/openapi/lib/api.dart
generated
@@ -321,6 +321,9 @@ part 'model/system_config_faces_dto.dart';
|
||||
part 'model/system_config_generated_fullsize_image_dto.dart';
|
||||
part 'model/system_config_generated_image_dto.dart';
|
||||
part 'model/system_config_image_dto.dart';
|
||||
part 'model/system_config_integrity_checks.dart';
|
||||
part 'model/system_config_integrity_checksum_job.dart';
|
||||
part 'model/system_config_integrity_job.dart';
|
||||
part 'model/system_config_job_dto.dart';
|
||||
part 'model/system_config_library_dto.dart';
|
||||
part 'model/system_config_library_scan_dto.dart';
|
||||
|
||||
6
mobile/openapi/lib/api_client.dart
generated
6
mobile/openapi/lib/api_client.dart
generated
@@ -690,6 +690,12 @@ class ApiClient {
|
||||
return SystemConfigGeneratedImageDto.fromJson(value);
|
||||
case 'SystemConfigImageDto':
|
||||
return SystemConfigImageDto.fromJson(value);
|
||||
case 'SystemConfigIntegrityChecks':
|
||||
return SystemConfigIntegrityChecks.fromJson(value);
|
||||
case 'SystemConfigIntegrityChecksumJob':
|
||||
return SystemConfigIntegrityChecksumJob.fromJson(value);
|
||||
case 'SystemConfigIntegrityJob':
|
||||
return SystemConfigIntegrityJob.fromJson(value);
|
||||
case 'SystemConfigJobDto':
|
||||
return SystemConfigJobDto.fromJson(value);
|
||||
case 'SystemConfigLibraryDto':
|
||||
|
||||
10
mobile/openapi/lib/model/system_config_dto.dart
generated
10
mobile/openapi/lib/model/system_config_dto.dart
generated
@@ -16,6 +16,7 @@ class SystemConfigDto {
|
||||
required this.backup,
|
||||
required this.ffmpeg,
|
||||
required this.image,
|
||||
required this.integrityChecks,
|
||||
required this.job,
|
||||
required this.library_,
|
||||
required this.logging,
|
||||
@@ -42,6 +43,8 @@ class SystemConfigDto {
|
||||
|
||||
SystemConfigImageDto image;
|
||||
|
||||
SystemConfigIntegrityChecks integrityChecks;
|
||||
|
||||
SystemConfigJobDto job;
|
||||
|
||||
SystemConfigLibraryDto library_;
|
||||
@@ -83,6 +86,7 @@ class SystemConfigDto {
|
||||
other.backup == backup &&
|
||||
other.ffmpeg == ffmpeg &&
|
||||
other.image == image &&
|
||||
other.integrityChecks == integrityChecks &&
|
||||
other.job == job &&
|
||||
other.library_ == library_ &&
|
||||
other.logging == logging &&
|
||||
@@ -108,6 +112,7 @@ class SystemConfigDto {
|
||||
(backup.hashCode) +
|
||||
(ffmpeg.hashCode) +
|
||||
(image.hashCode) +
|
||||
(integrityChecks.hashCode) +
|
||||
(job.hashCode) +
|
||||
(library_.hashCode) +
|
||||
(logging.hashCode) +
|
||||
@@ -128,13 +133,14 @@ class SystemConfigDto {
|
||||
(user.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SystemConfigDto[backup=$backup, ffmpeg=$ffmpeg, image=$image, job=$job, library_=$library_, logging=$logging, machineLearning=$machineLearning, map=$map, metadata=$metadata, newVersionCheck=$newVersionCheck, nightlyTasks=$nightlyTasks, notifications=$notifications, oauth=$oauth, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, server=$server, storageTemplate=$storageTemplate, templates=$templates, theme=$theme, trash=$trash, user=$user]';
|
||||
String toString() => 'SystemConfigDto[backup=$backup, ffmpeg=$ffmpeg, image=$image, integrityChecks=$integrityChecks, job=$job, library_=$library_, logging=$logging, machineLearning=$machineLearning, map=$map, metadata=$metadata, newVersionCheck=$newVersionCheck, nightlyTasks=$nightlyTasks, notifications=$notifications, oauth=$oauth, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, server=$server, storageTemplate=$storageTemplate, templates=$templates, theme=$theme, trash=$trash, user=$user]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'backup'] = this.backup;
|
||||
json[r'ffmpeg'] = this.ffmpeg;
|
||||
json[r'image'] = this.image;
|
||||
json[r'integrityChecks'] = this.integrityChecks;
|
||||
json[r'job'] = this.job;
|
||||
json[r'library'] = this.library_;
|
||||
json[r'logging'] = this.logging;
|
||||
@@ -168,6 +174,7 @@ class SystemConfigDto {
|
||||
backup: SystemConfigBackupsDto.fromJson(json[r'backup'])!,
|
||||
ffmpeg: SystemConfigFFmpegDto.fromJson(json[r'ffmpeg'])!,
|
||||
image: SystemConfigImageDto.fromJson(json[r'image'])!,
|
||||
integrityChecks: SystemConfigIntegrityChecks.fromJson(json[r'integrityChecks'])!,
|
||||
job: SystemConfigJobDto.fromJson(json[r'job'])!,
|
||||
library_: SystemConfigLibraryDto.fromJson(json[r'library'])!,
|
||||
logging: SystemConfigLoggingDto.fromJson(json[r'logging'])!,
|
||||
@@ -236,6 +243,7 @@ class SystemConfigDto {
|
||||
'backup',
|
||||
'ffmpeg',
|
||||
'image',
|
||||
'integrityChecks',
|
||||
'job',
|
||||
'library',
|
||||
'logging',
|
||||
|
||||
115
mobile/openapi/lib/model/system_config_integrity_checks.dart
generated
Normal file
115
mobile/openapi/lib/model/system_config_integrity_checks.dart
generated
Normal file
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.18
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
class SystemConfigIntegrityChecks {
|
||||
/// Returns a new [SystemConfigIntegrityChecks] instance.
|
||||
SystemConfigIntegrityChecks({
|
||||
required this.checksumFiles,
|
||||
required this.missingFiles,
|
||||
required this.orphanedFiles,
|
||||
});
|
||||
|
||||
SystemConfigIntegrityChecksumJob checksumFiles;
|
||||
|
||||
SystemConfigIntegrityJob missingFiles;
|
||||
|
||||
SystemConfigIntegrityJob orphanedFiles;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is SystemConfigIntegrityChecks &&
|
||||
other.checksumFiles == checksumFiles &&
|
||||
other.missingFiles == missingFiles &&
|
||||
other.orphanedFiles == orphanedFiles;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(checksumFiles.hashCode) +
|
||||
(missingFiles.hashCode) +
|
||||
(orphanedFiles.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SystemConfigIntegrityChecks[checksumFiles=$checksumFiles, missingFiles=$missingFiles, orphanedFiles=$orphanedFiles]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'checksumFiles'] = this.checksumFiles;
|
||||
json[r'missingFiles'] = this.missingFiles;
|
||||
json[r'orphanedFiles'] = this.orphanedFiles;
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [SystemConfigIntegrityChecks] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static SystemConfigIntegrityChecks? fromJson(dynamic value) {
|
||||
upgradeDto(value, "SystemConfigIntegrityChecks");
|
||||
if (value is Map) {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return SystemConfigIntegrityChecks(
|
||||
checksumFiles: SystemConfigIntegrityChecksumJob.fromJson(json[r'checksumFiles'])!,
|
||||
missingFiles: SystemConfigIntegrityJob.fromJson(json[r'missingFiles'])!,
|
||||
orphanedFiles: SystemConfigIntegrityJob.fromJson(json[r'orphanedFiles'])!,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<SystemConfigIntegrityChecks> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <SystemConfigIntegrityChecks>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = SystemConfigIntegrityChecks.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, SystemConfigIntegrityChecks> mapFromJson(dynamic json) {
|
||||
final map = <String, SystemConfigIntegrityChecks>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = SystemConfigIntegrityChecks.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of SystemConfigIntegrityChecks-objects as value to a dart map
|
||||
static Map<String, List<SystemConfigIntegrityChecks>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<SystemConfigIntegrityChecks>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
// ignore: parameter_assignments
|
||||
json = json.cast<String, dynamic>();
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = SystemConfigIntegrityChecks.listFromJson(entry.value, growable: growable,);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'checksumFiles',
|
||||
'missingFiles',
|
||||
'orphanedFiles',
|
||||
};
|
||||
}
|
||||
|
||||
123
mobile/openapi/lib/model/system_config_integrity_checksum_job.dart
generated
Normal file
123
mobile/openapi/lib/model/system_config_integrity_checksum_job.dart
generated
Normal file
@@ -0,0 +1,123 @@
|
||||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.18
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
class SystemConfigIntegrityChecksumJob {
|
||||
/// Returns a new [SystemConfigIntegrityChecksumJob] instance.
|
||||
SystemConfigIntegrityChecksumJob({
|
||||
required this.cronExpression,
|
||||
required this.enabled,
|
||||
required this.percentageLimit,
|
||||
required this.timeLimit,
|
||||
});
|
||||
|
||||
String cronExpression;
|
||||
|
||||
bool enabled;
|
||||
|
||||
num percentageLimit;
|
||||
|
||||
num timeLimit;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is SystemConfigIntegrityChecksumJob &&
|
||||
other.cronExpression == cronExpression &&
|
||||
other.enabled == enabled &&
|
||||
other.percentageLimit == percentageLimit &&
|
||||
other.timeLimit == timeLimit;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(cronExpression.hashCode) +
|
||||
(enabled.hashCode) +
|
||||
(percentageLimit.hashCode) +
|
||||
(timeLimit.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SystemConfigIntegrityChecksumJob[cronExpression=$cronExpression, enabled=$enabled, percentageLimit=$percentageLimit, timeLimit=$timeLimit]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'cronExpression'] = this.cronExpression;
|
||||
json[r'enabled'] = this.enabled;
|
||||
json[r'percentageLimit'] = this.percentageLimit;
|
||||
json[r'timeLimit'] = this.timeLimit;
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [SystemConfigIntegrityChecksumJob] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static SystemConfigIntegrityChecksumJob? fromJson(dynamic value) {
|
||||
upgradeDto(value, "SystemConfigIntegrityChecksumJob");
|
||||
if (value is Map) {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return SystemConfigIntegrityChecksumJob(
|
||||
cronExpression: mapValueOfType<String>(json, r'cronExpression')!,
|
||||
enabled: mapValueOfType<bool>(json, r'enabled')!,
|
||||
percentageLimit: num.parse('${json[r'percentageLimit']}'),
|
||||
timeLimit: num.parse('${json[r'timeLimit']}'),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<SystemConfigIntegrityChecksumJob> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <SystemConfigIntegrityChecksumJob>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = SystemConfigIntegrityChecksumJob.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, SystemConfigIntegrityChecksumJob> mapFromJson(dynamic json) {
|
||||
final map = <String, SystemConfigIntegrityChecksumJob>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = SystemConfigIntegrityChecksumJob.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of SystemConfigIntegrityChecksumJob-objects as value to a dart map
|
||||
static Map<String, List<SystemConfigIntegrityChecksumJob>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<SystemConfigIntegrityChecksumJob>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
// ignore: parameter_assignments
|
||||
json = json.cast<String, dynamic>();
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = SystemConfigIntegrityChecksumJob.listFromJson(entry.value, growable: growable,);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'cronExpression',
|
||||
'enabled',
|
||||
'percentageLimit',
|
||||
'timeLimit',
|
||||
};
|
||||
}
|
||||
|
||||
107
mobile/openapi/lib/model/system_config_integrity_job.dart
generated
Normal file
107
mobile/openapi/lib/model/system_config_integrity_job.dart
generated
Normal file
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.18
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
class SystemConfigIntegrityJob {
|
||||
/// Returns a new [SystemConfigIntegrityJob] instance.
|
||||
SystemConfigIntegrityJob({
|
||||
required this.cronExpression,
|
||||
required this.enabled,
|
||||
});
|
||||
|
||||
String cronExpression;
|
||||
|
||||
bool enabled;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is SystemConfigIntegrityJob &&
|
||||
other.cronExpression == cronExpression &&
|
||||
other.enabled == enabled;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(cronExpression.hashCode) +
|
||||
(enabled.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SystemConfigIntegrityJob[cronExpression=$cronExpression, enabled=$enabled]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'cronExpression'] = this.cronExpression;
|
||||
json[r'enabled'] = this.enabled;
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [SystemConfigIntegrityJob] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static SystemConfigIntegrityJob? fromJson(dynamic value) {
|
||||
upgradeDto(value, "SystemConfigIntegrityJob");
|
||||
if (value is Map) {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return SystemConfigIntegrityJob(
|
||||
cronExpression: mapValueOfType<String>(json, r'cronExpression')!,
|
||||
enabled: mapValueOfType<bool>(json, r'enabled')!,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<SystemConfigIntegrityJob> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <SystemConfigIntegrityJob>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = SystemConfigIntegrityJob.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, SystemConfigIntegrityJob> mapFromJson(dynamic json) {
|
||||
final map = <String, SystemConfigIntegrityJob>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = SystemConfigIntegrityJob.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of SystemConfigIntegrityJob-objects as value to a dart map
|
||||
static Map<String, List<SystemConfigIntegrityJob>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<SystemConfigIntegrityJob>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
// ignore: parameter_assignments
|
||||
json = json.cast<String, dynamic>();
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = SystemConfigIntegrityJob.listFromJson(entry.value, growable: growable,);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'cronExpression',
|
||||
'enabled',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21237,6 +21237,9 @@
|
||||
"image": {
|
||||
"$ref": "#/components/schemas/SystemConfigImageDto"
|
||||
},
|
||||
"integrityChecks": {
|
||||
"$ref": "#/components/schemas/SystemConfigIntegrityChecks"
|
||||
},
|
||||
"job": {
|
||||
"$ref": "#/components/schemas/SystemConfigJobDto"
|
||||
},
|
||||
@@ -21296,6 +21299,7 @@
|
||||
"backup",
|
||||
"ffmpeg",
|
||||
"image",
|
||||
"integrityChecks",
|
||||
"job",
|
||||
"library",
|
||||
"logging",
|
||||
@@ -21542,6 +21546,63 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"SystemConfigIntegrityChecks": {
|
||||
"properties": {
|
||||
"checksumFiles": {
|
||||
"$ref": "#/components/schemas/SystemConfigIntegrityChecksumJob"
|
||||
},
|
||||
"missingFiles": {
|
||||
"$ref": "#/components/schemas/SystemConfigIntegrityJob"
|
||||
},
|
||||
"orphanedFiles": {
|
||||
"$ref": "#/components/schemas/SystemConfigIntegrityJob"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"checksumFiles",
|
||||
"missingFiles",
|
||||
"orphanedFiles"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"SystemConfigIntegrityChecksumJob": {
|
||||
"properties": {
|
||||
"cronExpression": {
|
||||
"type": "string"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"percentageLimit": {
|
||||
"type": "number"
|
||||
},
|
||||
"timeLimit": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cronExpression",
|
||||
"enabled",
|
||||
"percentageLimit",
|
||||
"timeLimit"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"SystemConfigIntegrityJob": {
|
||||
"properties": {
|
||||
"cronExpression": {
|
||||
"type": "string"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cronExpression",
|
||||
"enabled"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"SystemConfigJobDto": {
|
||||
"properties": {
|
||||
"backgroundTask": {
|
||||
|
||||
@@ -1454,6 +1454,21 @@ export type SystemConfigImageDto = {
|
||||
preview: SystemConfigGeneratedImageDto;
|
||||
thumbnail: SystemConfigGeneratedImageDto;
|
||||
};
|
||||
export type SystemConfigIntegrityChecksumJob = {
|
||||
cronExpression: string;
|
||||
enabled: boolean;
|
||||
percentageLimit: number;
|
||||
timeLimit: number;
|
||||
};
|
||||
export type SystemConfigIntegrityJob = {
|
||||
cronExpression: string;
|
||||
enabled: boolean;
|
||||
};
|
||||
export type SystemConfigIntegrityChecks = {
|
||||
checksumFiles: SystemConfigIntegrityChecksumJob;
|
||||
missingFiles: SystemConfigIntegrityJob;
|
||||
orphanedFiles: SystemConfigIntegrityJob;
|
||||
};
|
||||
export type JobSettingsDto = {
|
||||
concurrency: number;
|
||||
};
|
||||
@@ -1606,6 +1621,7 @@ export type SystemConfigDto = {
|
||||
backup: SystemConfigBackupsDto;
|
||||
ffmpeg: SystemConfigFFmpegDto;
|
||||
image: SystemConfigImageDto;
|
||||
integrityChecks: SystemConfigIntegrityChecks;
|
||||
job: SystemConfigJobDto;
|
||||
library: SystemConfigLibraryDto;
|
||||
logging: SystemConfigLoggingDto;
|
||||
|
||||
@@ -46,6 +46,22 @@ export interface SystemConfig {
|
||||
accelDecode: boolean;
|
||||
tonemap: ToneMapping;
|
||||
};
|
||||
integrityChecks: {
|
||||
missingFiles: {
|
||||
enabled: boolean;
|
||||
cronExpression: string;
|
||||
};
|
||||
orphanedFiles: {
|
||||
enabled: boolean;
|
||||
cronExpression: string;
|
||||
};
|
||||
checksumFiles: {
|
||||
enabled: boolean;
|
||||
cronExpression: string;
|
||||
timeLimit: number;
|
||||
percentageLimit: number;
|
||||
};
|
||||
};
|
||||
job: Record<ConcurrentQueueName, { concurrency: number }>;
|
||||
logging: {
|
||||
enabled: boolean;
|
||||
@@ -222,6 +238,22 @@ export const defaults = Object.freeze<SystemConfig>({
|
||||
accel: TranscodeHardwareAcceleration.Disabled,
|
||||
accelDecode: false,
|
||||
},
|
||||
integrityChecks: {
|
||||
missingFiles: {
|
||||
enabled: true,
|
||||
cronExpression: CronExpression.EVERY_DAY_AT_3AM,
|
||||
},
|
||||
orphanedFiles: {
|
||||
enabled: true,
|
||||
cronExpression: CronExpression.EVERY_DAY_AT_3AM,
|
||||
},
|
||||
checksumFiles: {
|
||||
enabled: true,
|
||||
cronExpression: CronExpression.EVERY_DAY_AT_3AM,
|
||||
timeLimit: 60 * 60 * 1000, // 1 hour
|
||||
percentageLimit: 1.0, // 100% of assets
|
||||
},
|
||||
},
|
||||
job: {
|
||||
[QueueName.BackgroundTask]: { concurrency: 5 },
|
||||
[QueueName.SmartSearch]: { concurrency: 2 },
|
||||
|
||||
@@ -38,6 +38,7 @@ const isOAuthEnabled = (config: SystemConfigOAuthDto) => config.enabled;
|
||||
const isOAuthOverrideEnabled = (config: SystemConfigOAuthDto) => config.mobileOverrideEnabled;
|
||||
const isEmailNotificationEnabled = (config: SystemConfigSmtpDto) => config.enabled;
|
||||
const isDatabaseBackupEnabled = (config: DatabaseBackupConfig) => config.enabled;
|
||||
const isEnabledProperty = (config: { enabled: boolean }) => config.enabled;
|
||||
|
||||
export class DatabaseBackupConfig {
|
||||
@ValidateBoolean()
|
||||
@@ -145,6 +146,42 @@ export class SystemConfigFFmpegDto {
|
||||
tonemap!: ToneMapping;
|
||||
}
|
||||
|
||||
class SystemConfigIntegrityJob {
|
||||
@ValidateBoolean()
|
||||
enabled!: boolean;
|
||||
|
||||
@ValidateIf(isEnabledProperty)
|
||||
@IsNotEmpty()
|
||||
@IsCronExpression()
|
||||
@IsString()
|
||||
cronExpression!: string;
|
||||
}
|
||||
|
||||
class SystemConfigIntegrityChecksumJob extends SystemConfigIntegrityJob {
|
||||
@IsInt()
|
||||
timeLimit!: number;
|
||||
|
||||
@IsNumber()
|
||||
percentageLimit!: number;
|
||||
}
|
||||
|
||||
class SystemConfigIntegrityChecks {
|
||||
@Type(() => SystemConfigIntegrityJob)
|
||||
@ValidateNested()
|
||||
@IsObject()
|
||||
missingFiles!: SystemConfigIntegrityJob;
|
||||
|
||||
@Type(() => SystemConfigIntegrityJob)
|
||||
@ValidateNested()
|
||||
@IsObject()
|
||||
orphanedFiles!: SystemConfigIntegrityJob;
|
||||
|
||||
@Type(() => SystemConfigIntegrityChecksumJob)
|
||||
@ValidateNested()
|
||||
@IsObject()
|
||||
checksumFiles!: SystemConfigIntegrityChecksumJob;
|
||||
}
|
||||
|
||||
class JobSettingsDto {
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
@@ -649,6 +686,11 @@ export class SystemConfigDto implements SystemConfig {
|
||||
@IsObject()
|
||||
ffmpeg!: SystemConfigFFmpegDto;
|
||||
|
||||
@Type(() => SystemConfigIntegrityChecks)
|
||||
@ValidateNested()
|
||||
@IsObject()
|
||||
integrityChecks!: SystemConfigIntegrityChecks;
|
||||
|
||||
@Type(() => SystemConfigLoggingDto)
|
||||
@ValidateNested()
|
||||
@IsObject()
|
||||
|
||||
@@ -694,6 +694,7 @@ export enum DatabaseLock {
|
||||
GetSystemConfig = 69,
|
||||
BackupDatabase = 42,
|
||||
MemoryCreation = 777,
|
||||
IntegrityCheck = 67,
|
||||
}
|
||||
|
||||
export enum MaintenanceAction {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { JOBS_LIBRARY_PAGINATION_SIZE } from 'src/constants';
|
||||
import { StorageCore } from 'src/cores/storage.core';
|
||||
import { OnEvent, OnJob } from 'src/decorators';
|
||||
import {
|
||||
DatabaseLock,
|
||||
ImmichWorker,
|
||||
IntegrityReportType,
|
||||
JobName,
|
||||
@@ -19,6 +20,7 @@ import {
|
||||
import { ArgOf } from 'src/repositories/event.repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { IIntegrityOrphanedFilesJob, IIntegrityPathWithReportJob } from 'src/types';
|
||||
import { handlePromiseError } from 'src/utils/misc';
|
||||
|
||||
async function* chunk<T>(generator: AsyncIterableIterator<T>, n: number) {
|
||||
let chunk: T[] = [];
|
||||
@@ -38,25 +40,49 @@ async function* chunk<T>(generator: AsyncIterableIterator<T>, n: number) {
|
||||
|
||||
@Injectable()
|
||||
export class IntegrityService extends BaseService {
|
||||
// private backupLock = false;
|
||||
private integrityLock = false;
|
||||
|
||||
@OnEvent({ name: 'ConfigInit', workers: [ImmichWorker.Microservices] })
|
||||
async onConfigInit({
|
||||
newConfig: {
|
||||
backup: { database },
|
||||
integrityChecks: { orphanedFiles, missingFiles, checksumFiles },
|
||||
},
|
||||
}: ArgOf<'ConfigInit'>) {
|
||||
// this.backupLock = await this.databaseRepository.tryLock(DatabaseLock.BackupDatabase);
|
||||
// if (this.backupLock) {
|
||||
// this.cronRepository.create({
|
||||
// name: 'backupDatabase',
|
||||
// expression: database.cronExpression,
|
||||
// onTick: () => handlePromiseError(this.jobRepository.queue({ name: JobName.DatabaseBackup }), this.logger),
|
||||
// start: database.enabled,
|
||||
// });
|
||||
// }
|
||||
this.integrityLock = await this.databaseRepository.tryLock(DatabaseLock.IntegrityCheck);
|
||||
if (this.integrityLock) {
|
||||
this.cronRepository.create({
|
||||
name: 'integrityOrphanedFiles',
|
||||
expression: orphanedFiles.cronExpression,
|
||||
onTick: () =>
|
||||
handlePromiseError(
|
||||
this.jobRepository.queue({ name: JobName.IntegrityOrphanedFilesQueueAll, data: {} }),
|
||||
this.logger,
|
||||
),
|
||||
start: orphanedFiles.enabled,
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.cronRepository.create({
|
||||
name: 'integrityMissingFiles',
|
||||
expression: missingFiles.cronExpression,
|
||||
onTick: () =>
|
||||
handlePromiseError(
|
||||
this.jobRepository.queue({ name: JobName.IntegrityMissingFilesQueueAll, data: {} }),
|
||||
this.logger,
|
||||
),
|
||||
start: missingFiles.enabled,
|
||||
});
|
||||
|
||||
this.cronRepository.create({
|
||||
name: 'integrityChecksumFiles',
|
||||
expression: checksumFiles.cronExpression,
|
||||
onTick: () =>
|
||||
handlePromiseError(this.jobRepository.queue({ name: JobName.IntegrityChecksumFiles, data: {} }), this.logger),
|
||||
start: checksumFiles.enabled,
|
||||
});
|
||||
}
|
||||
|
||||
// debug: run on boot
|
||||
setImmediate(() => {
|
||||
this.jobRepository.queue({
|
||||
name: JobName.IntegrityOrphanedFilesQueueAll,
|
||||
data: {},
|
||||
@@ -71,19 +97,36 @@ export class IntegrityService extends BaseService {
|
||||
name: JobName.IntegrityChecksumFiles,
|
||||
data: {},
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'ConfigUpdate', server: true })
|
||||
async onConfigUpdate({ newConfig: { backup } }: ArgOf<'ConfigUpdate'>) {
|
||||
// if (!this.backupLock) {
|
||||
// return;
|
||||
// }
|
||||
// this.cronRepository.update({
|
||||
// name: 'backupDatabase',
|
||||
// expression: backup.database.cronExpression,
|
||||
// start: backup.database.enabled,
|
||||
// });
|
||||
async onConfigUpdate({
|
||||
newConfig: {
|
||||
integrityChecks: { orphanedFiles, missingFiles, checksumFiles },
|
||||
},
|
||||
}: ArgOf<'ConfigUpdate'>) {
|
||||
if (!this.integrityLock) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cronRepository.update({
|
||||
name: 'integrityOrphanedFiles',
|
||||
expression: orphanedFiles.cronExpression,
|
||||
start: orphanedFiles.enabled,
|
||||
});
|
||||
|
||||
this.cronRepository.update({
|
||||
name: 'integrityMissingFiles',
|
||||
expression: missingFiles.cronExpression,
|
||||
start: missingFiles.enabled,
|
||||
});
|
||||
|
||||
this.cronRepository.update({
|
||||
name: 'integrityChecksumFiles',
|
||||
expression: checksumFiles.cronExpression,
|
||||
start: checksumFiles.enabled,
|
||||
});
|
||||
}
|
||||
|
||||
@OnJob({ name: JobName.IntegrityOrphanedFilesQueueAll, queue: QueueName.BackgroundTask })
|
||||
|
||||
Reference in New Issue
Block a user