From aec50aeb59dd942736315b447789253132043912 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Tue, 14 Apr 2026 22:32:03 -0400 Subject: [PATCH] chore!: queue endpoint migration --- mobile/openapi/README.md | 9 - mobile/openapi/lib/api.dart | 5 - mobile/openapi/lib/api/deprecated_api.dart | 109 ------- mobile/openapi/lib/api/jobs_api.dart | 109 ------- mobile/openapi/lib/api_client.dart | 10 - mobile/openapi/lib/api_helper.dart | 3 - mobile/openapi/lib/model/queue_command.dart | 94 ------ .../openapi/lib/model/queue_command_dto.dart | 117 -------- .../lib/model/queue_response_legacy_dto.dart | 107 ------- .../lib/model/queue_status_legacy_dto.dart | 109 ------- .../lib/model/queues_response_legacy_dto.dart | 235 --------------- open-api/immich-openapi-specs.json | 268 ------------------ open-api/typescript-sdk/src/fetch-client.ts | 137 +++------ server/src/controllers/job.controller.ts | 39 +-- server/src/dtos/queue-legacy.dto.ts | 64 ----- server/src/enum.ts | 17 -- server/src/services/queue.service.spec.ts | 170 +---------- server/src/services/queue.service.ts | 48 ---- server/test/small.factory.ts | 12 - 19 files changed, 38 insertions(+), 1624 deletions(-) delete mode 100644 mobile/openapi/lib/model/queue_command.dart delete mode 100644 mobile/openapi/lib/model/queue_command_dto.dart delete mode 100644 mobile/openapi/lib/model/queue_response_legacy_dto.dart delete mode 100644 mobile/openapi/lib/model/queue_status_legacy_dto.dart delete mode 100644 mobile/openapi/lib/model/queues_response_legacy_dto.dart delete mode 100644 server/src/dtos/queue-legacy.dto.ts diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 612a65ae4e..767d9f4bcb 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -145,8 +145,6 @@ Class | Method | HTTP request | Description *DeprecatedApi* | [**getAllUserAssetsByDeviceId**](doc//DeprecatedApi.md#getalluserassetsbydeviceid) | **GET** /assets/device/{deviceId} | Retrieve assets by device ID *DeprecatedApi* | [**getDeltaSync**](doc//DeprecatedApi.md#getdeltasync) | **POST** /sync/delta-sync | Get delta sync for user *DeprecatedApi* | [**getFullSyncForUser**](doc//DeprecatedApi.md#getfullsyncforuser) | **POST** /sync/full-sync | Get full sync for user -*DeprecatedApi* | [**getQueuesLegacy**](doc//DeprecatedApi.md#getqueueslegacy) | **GET** /jobs | Retrieve queue counts and status -*DeprecatedApi* | [**runQueueCommandLegacy**](doc//DeprecatedApi.md#runqueuecommandlegacy) | **PUT** /jobs/{name} | Run jobs *DownloadApi* | [**downloadArchive**](doc//DownloadApi.md#downloadarchive) | **POST** /download/archive | Download asset archive *DownloadApi* | [**getDownloadInfo**](doc//DownloadApi.md#getdownloadinfo) | **POST** /download/info | Retrieve download information *DuplicatesApi* | [**deleteDuplicate**](doc//DuplicatesApi.md#deleteduplicate) | **DELETE** /duplicates/{id} | Delete a duplicate @@ -158,8 +156,6 @@ Class | Method | HTTP request | Description *FacesApi* | [**getFaces**](doc//FacesApi.md#getfaces) | **GET** /faces | Retrieve faces for asset *FacesApi* | [**reassignFacesById**](doc//FacesApi.md#reassignfacesbyid) | **PUT** /faces/{id} | Re-assign a face to another person *JobsApi* | [**createJob**](doc//JobsApi.md#createjob) | **POST** /jobs | Create a manual job -*JobsApi* | [**getQueuesLegacy**](doc//JobsApi.md#getqueueslegacy) | **GET** /jobs | Retrieve queue counts and status -*JobsApi* | [**runQueueCommandLegacy**](doc//JobsApi.md#runqueuecommandlegacy) | **PUT** /jobs/{name} | Run jobs *LibrariesApi* | [**createLibrary**](doc//LibrariesApi.md#createlibrary) | **POST** /libraries | Create a library *LibrariesApi* | [**deleteLibrary**](doc//LibrariesApi.md#deletelibrary) | **DELETE** /libraries/{id} | Delete a library *LibrariesApi* | [**getAllLibraries**](doc//LibrariesApi.md#getalllibraries) | **GET** /libraries | Retrieve libraries @@ -511,18 +507,13 @@ Class | Method | HTTP request | Description - [PluginTriggerType](doc//PluginTriggerType.md) - [PurchaseResponse](doc//PurchaseResponse.md) - [PurchaseUpdate](doc//PurchaseUpdate.md) - - [QueueCommand](doc//QueueCommand.md) - - [QueueCommandDto](doc//QueueCommandDto.md) - [QueueDeleteDto](doc//QueueDeleteDto.md) - [QueueJobResponseDto](doc//QueueJobResponseDto.md) - [QueueJobStatus](doc//QueueJobStatus.md) - [QueueName](doc//QueueName.md) - [QueueResponseDto](doc//QueueResponseDto.md) - - [QueueResponseLegacyDto](doc//QueueResponseLegacyDto.md) - [QueueStatisticsDto](doc//QueueStatisticsDto.md) - - [QueueStatusLegacyDto](doc//QueueStatusLegacyDto.md) - [QueueUpdateDto](doc//QueueUpdateDto.md) - - [QueuesResponseLegacyDto](doc//QueuesResponseLegacyDto.md) - [RandomSearchDto](doc//RandomSearchDto.md) - [RatingsResponse](doc//RatingsResponse.md) - [RatingsUpdate](doc//RatingsUpdate.md) diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 9403852ef0..9414e61685 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -253,18 +253,13 @@ part 'model/plugin_trigger_response_dto.dart'; part 'model/plugin_trigger_type.dart'; part 'model/purchase_response.dart'; part 'model/purchase_update.dart'; -part 'model/queue_command.dart'; -part 'model/queue_command_dto.dart'; part 'model/queue_delete_dto.dart'; part 'model/queue_job_response_dto.dart'; part 'model/queue_job_status.dart'; part 'model/queue_name.dart'; part 'model/queue_response_dto.dart'; -part 'model/queue_response_legacy_dto.dart'; part 'model/queue_statistics_dto.dart'; -part 'model/queue_status_legacy_dto.dart'; part 'model/queue_update_dto.dart'; -part 'model/queues_response_legacy_dto.dart'; part 'model/random_search_dto.dart'; part 'model/ratings_response.dart'; part 'model/ratings_update.dart'; diff --git a/mobile/openapi/lib/api/deprecated_api.dart b/mobile/openapi/lib/api/deprecated_api.dart index a292c176fd..13f05fcb80 100644 --- a/mobile/openapi/lib/api/deprecated_api.dart +++ b/mobile/openapi/lib/api/deprecated_api.dart @@ -249,113 +249,4 @@ class DeprecatedApi { } return null; } - - /// Retrieve queue counts and status - /// - /// Retrieve the counts of the current queue, as well as the current status. - /// - /// Note: This method returns the HTTP [Response]. - Future getQueuesLegacyWithHttpInfo() async { - // ignore: prefer_const_declarations - final apiPath = r'/jobs'; - - // ignore: prefer_final_locals - Object? postBody; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = []; - - - return apiClient.invokeAPI( - apiPath, - 'GET', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Retrieve queue counts and status - /// - /// Retrieve the counts of the current queue, as well as the current status. - Future getQueuesLegacy() async { - final response = await getQueuesLegacyWithHttpInfo(); - if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); - } - // When a remote server returns no body with a status of 204, we shall not decode it. - // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" - // FormatException when trying to decode an empty string. - if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'QueuesResponseLegacyDto',) as QueuesResponseLegacyDto; - - } - return null; - } - - /// Run jobs - /// - /// Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets. - /// - /// Note: This method returns the HTTP [Response]. - /// - /// Parameters: - /// - /// * [QueueName] name (required): - /// - /// * [QueueCommandDto] queueCommandDto (required): - Future runQueueCommandLegacyWithHttpInfo(QueueName name, QueueCommandDto queueCommandDto,) async { - // ignore: prefer_const_declarations - final apiPath = r'/jobs/{name}' - .replaceAll('{name}', name.toString()); - - // ignore: prefer_final_locals - Object? postBody = queueCommandDto; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = ['application/json']; - - - return apiClient.invokeAPI( - apiPath, - 'PUT', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Run jobs - /// - /// Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets. - /// - /// Parameters: - /// - /// * [QueueName] name (required): - /// - /// * [QueueCommandDto] queueCommandDto (required): - Future runQueueCommandLegacy(QueueName name, QueueCommandDto queueCommandDto,) async { - final response = await runQueueCommandLegacyWithHttpInfo(name, queueCommandDto,); - if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); - } - // When a remote server returns no body with a status of 204, we shall not decode it. - // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" - // FormatException when trying to decode an empty string. - if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'QueueResponseLegacyDto',) as QueueResponseLegacyDto; - - } - return null; - } } diff --git a/mobile/openapi/lib/api/jobs_api.dart b/mobile/openapi/lib/api/jobs_api.dart index 9dda59a883..5730c4ad31 100644 --- a/mobile/openapi/lib/api/jobs_api.dart +++ b/mobile/openapi/lib/api/jobs_api.dart @@ -63,113 +63,4 @@ class JobsApi { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } } - - /// Retrieve queue counts and status - /// - /// Retrieve the counts of the current queue, as well as the current status. - /// - /// Note: This method returns the HTTP [Response]. - Future getQueuesLegacyWithHttpInfo() async { - // ignore: prefer_const_declarations - final apiPath = r'/jobs'; - - // ignore: prefer_final_locals - Object? postBody; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = []; - - - return apiClient.invokeAPI( - apiPath, - 'GET', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Retrieve queue counts and status - /// - /// Retrieve the counts of the current queue, as well as the current status. - Future getQueuesLegacy() async { - final response = await getQueuesLegacyWithHttpInfo(); - if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); - } - // When a remote server returns no body with a status of 204, we shall not decode it. - // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" - // FormatException when trying to decode an empty string. - if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'QueuesResponseLegacyDto',) as QueuesResponseLegacyDto; - - } - return null; - } - - /// Run jobs - /// - /// Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets. - /// - /// Note: This method returns the HTTP [Response]. - /// - /// Parameters: - /// - /// * [QueueName] name (required): - /// - /// * [QueueCommandDto] queueCommandDto (required): - Future runQueueCommandLegacyWithHttpInfo(QueueName name, QueueCommandDto queueCommandDto,) async { - // ignore: prefer_const_declarations - final apiPath = r'/jobs/{name}' - .replaceAll('{name}', name.toString()); - - // ignore: prefer_final_locals - Object? postBody = queueCommandDto; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = ['application/json']; - - - return apiClient.invokeAPI( - apiPath, - 'PUT', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Run jobs - /// - /// Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets. - /// - /// Parameters: - /// - /// * [QueueName] name (required): - /// - /// * [QueueCommandDto] queueCommandDto (required): - Future runQueueCommandLegacy(QueueName name, QueueCommandDto queueCommandDto,) async { - final response = await runQueueCommandLegacyWithHttpInfo(name, queueCommandDto,); - if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); - } - // When a remote server returns no body with a status of 204, we shall not decode it. - // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" - // FormatException when trying to decode an empty string. - if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'QueueResponseLegacyDto',) as QueueResponseLegacyDto; - - } - return null; - } } diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index 3ed1f7529f..e5c98ee575 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -552,10 +552,6 @@ class ApiClient { return PurchaseResponse.fromJson(value); case 'PurchaseUpdate': return PurchaseUpdate.fromJson(value); - case 'QueueCommand': - return QueueCommandTypeTransformer().decode(value); - case 'QueueCommandDto': - return QueueCommandDto.fromJson(value); case 'QueueDeleteDto': return QueueDeleteDto.fromJson(value); case 'QueueJobResponseDto': @@ -566,16 +562,10 @@ class ApiClient { return QueueNameTypeTransformer().decode(value); case 'QueueResponseDto': return QueueResponseDto.fromJson(value); - case 'QueueResponseLegacyDto': - return QueueResponseLegacyDto.fromJson(value); case 'QueueStatisticsDto': return QueueStatisticsDto.fromJson(value); - case 'QueueStatusLegacyDto': - return QueueStatusLegacyDto.fromJson(value); case 'QueueUpdateDto': return QueueUpdateDto.fromJson(value); - case 'QueuesResponseLegacyDto': - return QueuesResponseLegacyDto.fromJson(value); case 'RandomSearchDto': return RandomSearchDto.fromJson(value); case 'RatingsResponse': diff --git a/mobile/openapi/lib/api_helper.dart b/mobile/openapi/lib/api_helper.dart index 3b36b23d6c..af8c4c606a 100644 --- a/mobile/openapi/lib/api_helper.dart +++ b/mobile/openapi/lib/api_helper.dart @@ -148,9 +148,6 @@ String parameterToString(dynamic value) { if (value is PluginTriggerType) { return PluginTriggerTypeTypeTransformer().encode(value).toString(); } - if (value is QueueCommand) { - return QueueCommandTypeTransformer().encode(value).toString(); - } if (value is QueueJobStatus) { return QueueJobStatusTypeTransformer().encode(value).toString(); } diff --git a/mobile/openapi/lib/model/queue_command.dart b/mobile/openapi/lib/model/queue_command.dart deleted file mode 100644 index 3cf689a02d..0000000000 --- a/mobile/openapi/lib/model/queue_command.dart +++ /dev/null @@ -1,94 +0,0 @@ -// -// 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; - -/// Queue command to execute -class QueueCommand { - /// Instantiate a new enum with the provided [value]. - const QueueCommand._(this.value); - - /// The underlying value of this enum member. - final String value; - - @override - String toString() => value; - - String toJson() => value; - - static const start = QueueCommand._(r'start'); - static const pause = QueueCommand._(r'pause'); - static const resume = QueueCommand._(r'resume'); - static const empty = QueueCommand._(r'empty'); - static const clearFailed = QueueCommand._(r'clear-failed'); - - /// List of all possible values in this [enum][QueueCommand]. - static const values = [ - start, - pause, - resume, - empty, - clearFailed, - ]; - - static QueueCommand? fromJson(dynamic value) => QueueCommandTypeTransformer().decode(value); - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = QueueCommand.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } -} - -/// Transformation class that can [encode] an instance of [QueueCommand] to String, -/// and [decode] dynamic data back to [QueueCommand]. -class QueueCommandTypeTransformer { - factory QueueCommandTypeTransformer() => _instance ??= const QueueCommandTypeTransformer._(); - - const QueueCommandTypeTransformer._(); - - String encode(QueueCommand data) => data.value; - - /// Decodes a [dynamic value][data] to a QueueCommand. - /// - /// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully, - /// then null is returned. However, if [allowNull] is false and the [dynamic value][data] - /// cannot be decoded successfully, then an [UnimplementedError] is thrown. - /// - /// The [allowNull] is very handy when an API changes and a new enum value is added or removed, - /// and users are still using an old app with the old code. - QueueCommand? decode(dynamic data, {bool allowNull = true}) { - if (data != null) { - switch (data) { - case r'start': return QueueCommand.start; - case r'pause': return QueueCommand.pause; - case r'resume': return QueueCommand.resume; - case r'empty': return QueueCommand.empty; - case r'clear-failed': return QueueCommand.clearFailed; - default: - if (!allowNull) { - throw ArgumentError('Unknown enum value to decode: $data'); - } - } - } - return null; - } - - /// Singleton [QueueCommandTypeTransformer] instance. - static QueueCommandTypeTransformer? _instance; -} - diff --git a/mobile/openapi/lib/model/queue_command_dto.dart b/mobile/openapi/lib/model/queue_command_dto.dart deleted file mode 100644 index fb68d85583..0000000000 --- a/mobile/openapi/lib/model/queue_command_dto.dart +++ /dev/null @@ -1,117 +0,0 @@ -// -// 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 QueueCommandDto { - /// Returns a new [QueueCommandDto] instance. - QueueCommandDto({ - required this.command, - this.force, - }); - - QueueCommand command; - - /// Force the command execution (if applicable) - /// - /// Please note: This property should have been non-nullable! Since the specification file - /// does not include a default value (using the "default:" property), however, the generated - /// source code must fall back to having a nullable type. - /// Consider adding a "default:" property in the specification file to hide this note. - /// - bool? force; - - @override - bool operator ==(Object other) => identical(this, other) || other is QueueCommandDto && - other.command == command && - other.force == force; - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (command.hashCode) + - (force == null ? 0 : force!.hashCode); - - @override - String toString() => 'QueueCommandDto[command=$command, force=$force]'; - - Map toJson() { - final json = {}; - json[r'command'] = this.command; - if (this.force != null) { - json[r'force'] = this.force; - } else { - // json[r'force'] = null; - } - return json; - } - - /// Returns a new [QueueCommandDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static QueueCommandDto? fromJson(dynamic value) { - upgradeDto(value, "QueueCommandDto"); - if (value is Map) { - final json = value.cast(); - - return QueueCommandDto( - command: QueueCommand.fromJson(json[r'command'])!, - force: mapValueOfType(json, r'force'), - ); - } - return null; - } - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = QueueCommandDto.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } - - static Map mapFromJson(dynamic json) { - final map = {}; - if (json is Map && json.isNotEmpty) { - json = json.cast(); // ignore: parameter_assignments - for (final entry in json.entries) { - final value = QueueCommandDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of QueueCommandDto-objects as value to a dart map - static Map> mapListFromJson(dynamic json, {bool growable = false,}) { - final map = >{}; - if (json is Map && json.isNotEmpty) { - // ignore: parameter_assignments - json = json.cast(); - for (final entry in json.entries) { - map[entry.key] = QueueCommandDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - 'command', - }; -} - diff --git a/mobile/openapi/lib/model/queue_response_legacy_dto.dart b/mobile/openapi/lib/model/queue_response_legacy_dto.dart deleted file mode 100644 index 214b0b31f6..0000000000 --- a/mobile/openapi/lib/model/queue_response_legacy_dto.dart +++ /dev/null @@ -1,107 +0,0 @@ -// -// 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 QueueResponseLegacyDto { - /// Returns a new [QueueResponseLegacyDto] instance. - QueueResponseLegacyDto({ - required this.jobCounts, - required this.queueStatus, - }); - - QueueStatisticsDto jobCounts; - - QueueStatusLegacyDto queueStatus; - - @override - bool operator ==(Object other) => identical(this, other) || other is QueueResponseLegacyDto && - other.jobCounts == jobCounts && - other.queueStatus == queueStatus; - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (jobCounts.hashCode) + - (queueStatus.hashCode); - - @override - String toString() => 'QueueResponseLegacyDto[jobCounts=$jobCounts, queueStatus=$queueStatus]'; - - Map toJson() { - final json = {}; - json[r'jobCounts'] = this.jobCounts; - json[r'queueStatus'] = this.queueStatus; - return json; - } - - /// Returns a new [QueueResponseLegacyDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static QueueResponseLegacyDto? fromJson(dynamic value) { - upgradeDto(value, "QueueResponseLegacyDto"); - if (value is Map) { - final json = value.cast(); - - return QueueResponseLegacyDto( - jobCounts: QueueStatisticsDto.fromJson(json[r'jobCounts'])!, - queueStatus: QueueStatusLegacyDto.fromJson(json[r'queueStatus'])!, - ); - } - return null; - } - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = QueueResponseLegacyDto.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } - - static Map mapFromJson(dynamic json) { - final map = {}; - if (json is Map && json.isNotEmpty) { - json = json.cast(); // ignore: parameter_assignments - for (final entry in json.entries) { - final value = QueueResponseLegacyDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of QueueResponseLegacyDto-objects as value to a dart map - static Map> mapListFromJson(dynamic json, {bool growable = false,}) { - final map = >{}; - if (json is Map && json.isNotEmpty) { - // ignore: parameter_assignments - json = json.cast(); - for (final entry in json.entries) { - map[entry.key] = QueueResponseLegacyDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - 'jobCounts', - 'queueStatus', - }; -} - diff --git a/mobile/openapi/lib/model/queue_status_legacy_dto.dart b/mobile/openapi/lib/model/queue_status_legacy_dto.dart deleted file mode 100644 index de6ce63319..0000000000 --- a/mobile/openapi/lib/model/queue_status_legacy_dto.dart +++ /dev/null @@ -1,109 +0,0 @@ -// -// 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 QueueStatusLegacyDto { - /// Returns a new [QueueStatusLegacyDto] instance. - QueueStatusLegacyDto({ - required this.isActive, - required this.isPaused, - }); - - /// Whether the queue is currently active (has running jobs) - bool isActive; - - /// Whether the queue is paused - bool isPaused; - - @override - bool operator ==(Object other) => identical(this, other) || other is QueueStatusLegacyDto && - other.isActive == isActive && - other.isPaused == isPaused; - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (isActive.hashCode) + - (isPaused.hashCode); - - @override - String toString() => 'QueueStatusLegacyDto[isActive=$isActive, isPaused=$isPaused]'; - - Map toJson() { - final json = {}; - json[r'isActive'] = this.isActive; - json[r'isPaused'] = this.isPaused; - return json; - } - - /// Returns a new [QueueStatusLegacyDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static QueueStatusLegacyDto? fromJson(dynamic value) { - upgradeDto(value, "QueueStatusLegacyDto"); - if (value is Map) { - final json = value.cast(); - - return QueueStatusLegacyDto( - isActive: mapValueOfType(json, r'isActive')!, - isPaused: mapValueOfType(json, r'isPaused')!, - ); - } - return null; - } - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = QueueStatusLegacyDto.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } - - static Map mapFromJson(dynamic json) { - final map = {}; - if (json is Map && json.isNotEmpty) { - json = json.cast(); // ignore: parameter_assignments - for (final entry in json.entries) { - final value = QueueStatusLegacyDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of QueueStatusLegacyDto-objects as value to a dart map - static Map> mapListFromJson(dynamic json, {bool growable = false,}) { - final map = >{}; - if (json is Map && json.isNotEmpty) { - // ignore: parameter_assignments - json = json.cast(); - for (final entry in json.entries) { - map[entry.key] = QueueStatusLegacyDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - 'isActive', - 'isPaused', - }; -} - diff --git a/mobile/openapi/lib/model/queues_response_legacy_dto.dart b/mobile/openapi/lib/model/queues_response_legacy_dto.dart deleted file mode 100644 index c7bc23cb4d..0000000000 --- a/mobile/openapi/lib/model/queues_response_legacy_dto.dart +++ /dev/null @@ -1,235 +0,0 @@ -// -// 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 QueuesResponseLegacyDto { - /// Returns a new [QueuesResponseLegacyDto] instance. - QueuesResponseLegacyDto({ - required this.backgroundTask, - required this.backupDatabase, - required this.duplicateDetection, - required this.editor, - required this.faceDetection, - required this.facialRecognition, - required this.library_, - required this.metadataExtraction, - required this.migration, - required this.notifications, - required this.ocr, - required this.search, - required this.sidecar, - required this.smartSearch, - required this.storageTemplateMigration, - required this.thumbnailGeneration, - required this.videoConversion, - required this.workflow, - }); - - QueueResponseLegacyDto backgroundTask; - - QueueResponseLegacyDto backupDatabase; - - QueueResponseLegacyDto duplicateDetection; - - QueueResponseLegacyDto editor; - - QueueResponseLegacyDto faceDetection; - - QueueResponseLegacyDto facialRecognition; - - QueueResponseLegacyDto library_; - - QueueResponseLegacyDto metadataExtraction; - - QueueResponseLegacyDto migration; - - QueueResponseLegacyDto notifications; - - QueueResponseLegacyDto ocr; - - QueueResponseLegacyDto search; - - QueueResponseLegacyDto sidecar; - - QueueResponseLegacyDto smartSearch; - - QueueResponseLegacyDto storageTemplateMigration; - - QueueResponseLegacyDto thumbnailGeneration; - - QueueResponseLegacyDto videoConversion; - - QueueResponseLegacyDto workflow; - - @override - bool operator ==(Object other) => identical(this, other) || other is QueuesResponseLegacyDto && - other.backgroundTask == backgroundTask && - other.backupDatabase == backupDatabase && - other.duplicateDetection == duplicateDetection && - other.editor == editor && - other.faceDetection == faceDetection && - other.facialRecognition == facialRecognition && - other.library_ == library_ && - other.metadataExtraction == metadataExtraction && - other.migration == migration && - other.notifications == notifications && - other.ocr == ocr && - other.search == search && - other.sidecar == sidecar && - other.smartSearch == smartSearch && - other.storageTemplateMigration == storageTemplateMigration && - other.thumbnailGeneration == thumbnailGeneration && - other.videoConversion == videoConversion && - other.workflow == workflow; - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (backgroundTask.hashCode) + - (backupDatabase.hashCode) + - (duplicateDetection.hashCode) + - (editor.hashCode) + - (faceDetection.hashCode) + - (facialRecognition.hashCode) + - (library_.hashCode) + - (metadataExtraction.hashCode) + - (migration.hashCode) + - (notifications.hashCode) + - (ocr.hashCode) + - (search.hashCode) + - (sidecar.hashCode) + - (smartSearch.hashCode) + - (storageTemplateMigration.hashCode) + - (thumbnailGeneration.hashCode) + - (videoConversion.hashCode) + - (workflow.hashCode); - - @override - String toString() => 'QueuesResponseLegacyDto[backgroundTask=$backgroundTask, backupDatabase=$backupDatabase, duplicateDetection=$duplicateDetection, editor=$editor, faceDetection=$faceDetection, facialRecognition=$facialRecognition, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, notifications=$notifications, ocr=$ocr, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion, workflow=$workflow]'; - - Map toJson() { - final json = {}; - json[r'backgroundTask'] = this.backgroundTask; - json[r'backupDatabase'] = this.backupDatabase; - json[r'duplicateDetection'] = this.duplicateDetection; - json[r'editor'] = this.editor; - json[r'faceDetection'] = this.faceDetection; - json[r'facialRecognition'] = this.facialRecognition; - json[r'library'] = this.library_; - json[r'metadataExtraction'] = this.metadataExtraction; - json[r'migration'] = this.migration; - json[r'notifications'] = this.notifications; - json[r'ocr'] = this.ocr; - json[r'search'] = this.search; - json[r'sidecar'] = this.sidecar; - json[r'smartSearch'] = this.smartSearch; - json[r'storageTemplateMigration'] = this.storageTemplateMigration; - json[r'thumbnailGeneration'] = this.thumbnailGeneration; - json[r'videoConversion'] = this.videoConversion; - json[r'workflow'] = this.workflow; - return json; - } - - /// Returns a new [QueuesResponseLegacyDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static QueuesResponseLegacyDto? fromJson(dynamic value) { - upgradeDto(value, "QueuesResponseLegacyDto"); - if (value is Map) { - final json = value.cast(); - - return QueuesResponseLegacyDto( - backgroundTask: QueueResponseLegacyDto.fromJson(json[r'backgroundTask'])!, - backupDatabase: QueueResponseLegacyDto.fromJson(json[r'backupDatabase'])!, - duplicateDetection: QueueResponseLegacyDto.fromJson(json[r'duplicateDetection'])!, - editor: QueueResponseLegacyDto.fromJson(json[r'editor'])!, - faceDetection: QueueResponseLegacyDto.fromJson(json[r'faceDetection'])!, - facialRecognition: QueueResponseLegacyDto.fromJson(json[r'facialRecognition'])!, - library_: QueueResponseLegacyDto.fromJson(json[r'library'])!, - metadataExtraction: QueueResponseLegacyDto.fromJson(json[r'metadataExtraction'])!, - migration: QueueResponseLegacyDto.fromJson(json[r'migration'])!, - notifications: QueueResponseLegacyDto.fromJson(json[r'notifications'])!, - ocr: QueueResponseLegacyDto.fromJson(json[r'ocr'])!, - search: QueueResponseLegacyDto.fromJson(json[r'search'])!, - sidecar: QueueResponseLegacyDto.fromJson(json[r'sidecar'])!, - smartSearch: QueueResponseLegacyDto.fromJson(json[r'smartSearch'])!, - storageTemplateMigration: QueueResponseLegacyDto.fromJson(json[r'storageTemplateMigration'])!, - thumbnailGeneration: QueueResponseLegacyDto.fromJson(json[r'thumbnailGeneration'])!, - videoConversion: QueueResponseLegacyDto.fromJson(json[r'videoConversion'])!, - workflow: QueueResponseLegacyDto.fromJson(json[r'workflow'])!, - ); - } - return null; - } - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = QueuesResponseLegacyDto.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } - - static Map mapFromJson(dynamic json) { - final map = {}; - if (json is Map && json.isNotEmpty) { - json = json.cast(); // ignore: parameter_assignments - for (final entry in json.entries) { - final value = QueuesResponseLegacyDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of QueuesResponseLegacyDto-objects as value to a dart map - static Map> mapListFromJson(dynamic json, {bool growable = false,}) { - final map = >{}; - if (json is Map && json.isNotEmpty) { - // ignore: parameter_assignments - json = json.cast(); - for (final entry in json.entries) { - map[entry.key] = QueuesResponseLegacyDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - 'backgroundTask', - 'backupDatabase', - 'duplicateDetection', - 'editor', - 'faceDetection', - 'facialRecognition', - 'library', - 'metadataExtraction', - 'migration', - 'notifications', - 'ocr', - 'search', - 'sidecar', - 'smartSearch', - 'storageTemplateMigration', - 'thumbnailGeneration', - 'videoConversion', - 'workflow', - }; -} - diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 9422786605..980a672876 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -5525,61 +5525,6 @@ } }, "/jobs": { - "get": { - "deprecated": true, - "description": "Retrieve the counts of the current queue, as well as the current status.", - "operationId": "getQueuesLegacy", - "parameters": [], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueuesResponseLegacyDto" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "summary": "Retrieve queue counts and status", - "tags": [ - "Jobs", - "Deprecated" - ], - "x-immich-admin-only": true, - "x-immich-history": [ - { - "version": "v1", - "state": "Added" - }, - { - "version": "v1", - "state": "Beta" - }, - { - "version": "v2", - "state": "Stable" - }, - { - "version": "v2.4.0", - "state": "Deprecated" - } - ], - "x-immich-permission": "job.read", - "x-immich-state": "Deprecated" - }, "post": { "description": "Run a specific job. Most jobs are queued automatically, but this endpoint allows for manual creation of a handful of jobs, including various cleanup tasks, as well as creating a new database backup.", "operationId": "createJob", @@ -5633,82 +5578,6 @@ "x-immich-state": "Stable" } }, - "/jobs/{name}": { - "put": { - "deprecated": true, - "description": "Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets.", - "operationId": "runQueueCommandLegacy", - "parameters": [ - { - "name": "name", - "required": true, - "in": "path", - "schema": { - "$ref": "#/components/schemas/QueueName" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueueCommandDto" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "summary": "Run jobs", - "tags": [ - "Jobs", - "Deprecated" - ], - "x-immich-admin-only": true, - "x-immich-history": [ - { - "version": "v1", - "state": "Added" - }, - { - "version": "v1", - "state": "Beta" - }, - { - "version": "v2", - "state": "Stable" - }, - { - "version": "v2.4.0", - "state": "Deprecated" - } - ], - "x-immich-permission": "job.create", - "x-immich-state": "Deprecated" - } - }, "/libraries": { "get": { "description": "Retrieve a list of external libraries.", @@ -20539,32 +20408,6 @@ }, "type": "object" }, - "QueueCommand": { - "description": "Queue command to execute", - "enum": [ - "start", - "pause", - "resume", - "empty", - "clear-failed" - ], - "type": "string" - }, - "QueueCommandDto": { - "properties": { - "command": { - "$ref": "#/components/schemas/QueueCommand" - }, - "force": { - "description": "Force the command execution (if applicable)", - "type": "boolean" - } - }, - "required": [ - "command" - ], - "type": "object" - }, "QueueDeleteDto": { "properties": { "failed": { @@ -20669,21 +20512,6 @@ ], "type": "object" }, - "QueueResponseLegacyDto": { - "properties": { - "jobCounts": { - "$ref": "#/components/schemas/QueueStatisticsDto" - }, - "queueStatus": { - "$ref": "#/components/schemas/QueueStatusLegacyDto" - } - }, - "required": [ - "jobCounts", - "queueStatus" - ], - "type": "object" - }, "QueueStatisticsDto": { "properties": { "active": { @@ -20733,23 +20561,6 @@ ], "type": "object" }, - "QueueStatusLegacyDto": { - "properties": { - "isActive": { - "description": "Whether the queue is currently active (has running jobs)", - "type": "boolean" - }, - "isPaused": { - "description": "Whether the queue is paused", - "type": "boolean" - } - }, - "required": [ - "isActive", - "isPaused" - ], - "type": "object" - }, "QueueUpdateDto": { "properties": { "isPaused": { @@ -20759,85 +20570,6 @@ }, "type": "object" }, - "QueuesResponseLegacyDto": { - "properties": { - "backgroundTask": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "backupDatabase": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "duplicateDetection": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "editor": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "faceDetection": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "facialRecognition": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "library": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "metadataExtraction": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "migration": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "notifications": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "ocr": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "search": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "sidecar": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "smartSearch": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "storageTemplateMigration": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "thumbnailGeneration": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "videoConversion": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - }, - "workflow": { - "$ref": "#/components/schemas/QueueResponseLegacyDto" - } - }, - "required": [ - "backgroundTask", - "backupDatabase", - "duplicateDetection", - "editor", - "faceDetection", - "facialRecognition", - "library", - "metadataExtraction", - "migration", - "notifications", - "ocr", - "search", - "sidecar", - "smartSearch", - "storageTemplateMigration", - "thumbnailGeneration", - "videoConversion", - "workflow" - ], - "type": "object" - }, "RandomSearchDto": { "properties": { "albumIds": { diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index bd96223cb9..2401b89eec 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1205,58 +1205,9 @@ export type FaceDto = { /** Face ID */ id: string; }; -export type QueueStatisticsDto = { - /** Number of active jobs */ - active: number; - /** Number of completed jobs */ - completed: number; - /** Number of delayed jobs */ - delayed: number; - /** Number of failed jobs */ - failed: number; - /** Number of paused jobs */ - paused: number; - /** Number of waiting jobs */ - waiting: number; -}; -export type QueueStatusLegacyDto = { - /** Whether the queue is currently active (has running jobs) */ - isActive: boolean; - /** Whether the queue is paused */ - isPaused: boolean; -}; -export type QueueResponseLegacyDto = { - jobCounts: QueueStatisticsDto; - queueStatus: QueueStatusLegacyDto; -}; -export type QueuesResponseLegacyDto = { - backgroundTask: QueueResponseLegacyDto; - backupDatabase: QueueResponseLegacyDto; - duplicateDetection: QueueResponseLegacyDto; - editor: QueueResponseLegacyDto; - faceDetection: QueueResponseLegacyDto; - facialRecognition: QueueResponseLegacyDto; - library: QueueResponseLegacyDto; - metadataExtraction: QueueResponseLegacyDto; - migration: QueueResponseLegacyDto; - notifications: QueueResponseLegacyDto; - ocr: QueueResponseLegacyDto; - search: QueueResponseLegacyDto; - sidecar: QueueResponseLegacyDto; - smartSearch: QueueResponseLegacyDto; - storageTemplateMigration: QueueResponseLegacyDto; - thumbnailGeneration: QueueResponseLegacyDto; - videoConversion: QueueResponseLegacyDto; - workflow: QueueResponseLegacyDto; -}; export type JobCreateDto = { name: ManualJobName; }; -export type QueueCommandDto = { - command: QueueCommand; - /** Force the command execution (if applicable) */ - force?: boolean; -}; export type LibraryResponseDto = { /** Number of assets */ assetCount: number; @@ -1611,6 +1562,20 @@ export type PluginTriggerResponseDto = { contextType: PluginContextType; "type": PluginTriggerType; }; +export type QueueStatisticsDto = { + /** Number of active jobs */ + active: number; + /** Number of completed jobs */ + completed: number; + /** Number of delayed jobs */ + delayed: number; + /** Number of failed jobs */ + failed: number; + /** Number of paused jobs */ + paused: number; + /** Number of waiting jobs */ + waiting: number; +}; export type QueueResponseDto = { /** Whether the queue is paused */ isPaused: boolean; @@ -4553,17 +4518,6 @@ export function reassignFacesById({ id, faceDto }: { body: faceDto }))); } -/** - * Retrieve queue counts and status - */ -export function getQueuesLegacy(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: QueuesResponseLegacyDto; - }>("/jobs", { - ...opts - })); -} /** * Create a manual job */ @@ -4576,22 +4530,6 @@ export function createJob({ jobCreateDto }: { body: jobCreateDto }))); } -/** - * Run jobs - */ -export function runQueueCommandLegacy({ name, queueCommandDto }: { - name: QueueName; - queueCommandDto: QueueCommandDto; -}, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: QueueResponseLegacyDto; - }>(`/jobs/${encodeURIComponent(name)}`, oazapfts.json({ - ...opts, - method: "PUT", - body: queueCommandDto - }))); -} /** * Retrieve libraries */ @@ -7041,33 +6979,6 @@ export enum ManualJobName { MemoryCreate = "memory-create", BackupDatabase = "backup-database" } -export enum QueueName { - ThumbnailGeneration = "thumbnailGeneration", - MetadataExtraction = "metadataExtraction", - VideoConversion = "videoConversion", - FaceDetection = "faceDetection", - FacialRecognition = "facialRecognition", - SmartSearch = "smartSearch", - DuplicateDetection = "duplicateDetection", - BackgroundTask = "backgroundTask", - StorageTemplateMigration = "storageTemplateMigration", - Migration = "migration", - Search = "search", - Sidecar = "sidecar", - Library = "library", - Notifications = "notifications", - BackupDatabase = "backupDatabase", - Ocr = "ocr", - Workflow = "workflow", - Editor = "editor" -} -export enum QueueCommand { - Start = "start", - Pause = "pause", - Resume = "resume", - Empty = "empty", - ClearFailed = "clear-failed" -} export enum MemorySearchOrder { Asc = "asc", Desc = "desc", @@ -7098,6 +7009,26 @@ export enum PluginTriggerType { AssetCreate = "AssetCreate", PersonRecognized = "PersonRecognized" } +export enum QueueName { + ThumbnailGeneration = "thumbnailGeneration", + MetadataExtraction = "metadataExtraction", + VideoConversion = "videoConversion", + FaceDetection = "faceDetection", + FacialRecognition = "facialRecognition", + SmartSearch = "smartSearch", + DuplicateDetection = "duplicateDetection", + BackgroundTask = "backgroundTask", + StorageTemplateMigration = "storageTemplateMigration", + Migration = "migration", + Search = "search", + Sidecar = "sidecar", + Library = "library", + Notifications = "notifications", + BackupDatabase = "backupDatabase", + Ocr = "ocr", + Workflow = "workflow", + Editor = "editor" +} export enum QueueJobStatus { Active = "active", Failed = "failed", diff --git a/server/src/controllers/job.controller.ts b/server/src/controllers/job.controller.ts index 783d5a3133..f465490475 100644 --- a/server/src/controllers/job.controller.ts +++ b/server/src/controllers/job.controller.ts @@ -1,33 +1,15 @@ -import { Body, Controller, Get, HttpCode, HttpStatus, Param, Post, Put } from '@nestjs/common'; +import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { Endpoint, HistoryBuilder } from 'src/decorators'; -import { AuthDto } from 'src/dtos/auth.dto'; import { JobCreateDto } from 'src/dtos/job.dto'; -import { QueueResponseLegacyDto, QueuesResponseLegacyDto } from 'src/dtos/queue-legacy.dto'; -import { QueueCommandDto, QueueNameParamDto } from 'src/dtos/queue.dto'; import { ApiTag, Permission } from 'src/enum'; -import { Auth, Authenticated } from 'src/middleware/auth.guard'; +import { Authenticated } from 'src/middleware/auth.guard'; import { JobService } from 'src/services/job.service'; -import { QueueService } from 'src/services/queue.service'; @ApiTags(ApiTag.Jobs) @Controller('jobs') export class JobController { - constructor( - private service: JobService, - private queueService: QueueService, - ) {} - - @Get() - @Authenticated({ permission: Permission.JobRead, admin: true }) - @Endpoint({ - summary: 'Retrieve queue counts and status', - description: 'Retrieve the counts of the current queue, as well as the current status.', - history: new HistoryBuilder().added('v1').beta('v1').stable('v2').deprecated('v2.4.0'), - }) - getQueuesLegacy(@Auth() auth: AuthDto): Promise { - return this.queueService.getAllLegacy(auth); - } + constructor(private service: JobService) {} @Post() @Authenticated({ permission: Permission.JobCreate, admin: true }) @@ -41,19 +23,4 @@ export class JobController { createJob(@Body() dto: JobCreateDto): Promise { return this.service.create(dto); } - - @Put(':name') - @Authenticated({ permission: Permission.JobCreate, admin: true }) - @Endpoint({ - summary: 'Run jobs', - description: - 'Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets.', - history: new HistoryBuilder().added('v1').beta('v1').stable('v2').deprecated('v2.4.0'), - }) - runQueueCommandLegacy( - @Param() { name }: QueueNameParamDto, - @Body() dto: QueueCommandDto, - ): Promise { - return this.queueService.runCommandLegacy(name, dto); - } } diff --git a/server/src/dtos/queue-legacy.dto.ts b/server/src/dtos/queue-legacy.dto.ts deleted file mode 100644 index dbbcec2da5..0000000000 --- a/server/src/dtos/queue-legacy.dto.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { createZodDto } from 'nestjs-zod'; -import { QueueResponseDto, QueueStatisticsSchema } from 'src/dtos/queue.dto'; -import { QueueName } from 'src/enum'; -import z from 'zod'; - -const QueueStatusLegacySchema = z - .object({ - isActive: z.boolean().describe('Whether the queue is currently active (has running jobs)'), - isPaused: z.boolean().describe('Whether the queue is paused'), - }) - .meta({ id: 'QueueStatusLegacyDto' }); - -const QueueResponseLegacySchema = z - .object({ - queueStatus: QueueStatusLegacySchema, - jobCounts: QueueStatisticsSchema, - }) - .meta({ id: 'QueueResponseLegacyDto' }); - -const QueuesResponseLegacySchema = z - .object({ - [QueueName.ThumbnailGeneration]: QueueResponseLegacySchema, - [QueueName.MetadataExtraction]: QueueResponseLegacySchema, - [QueueName.VideoConversion]: QueueResponseLegacySchema, - [QueueName.SmartSearch]: QueueResponseLegacySchema, - [QueueName.StorageTemplateMigration]: QueueResponseLegacySchema, - [QueueName.Migration]: QueueResponseLegacySchema, - [QueueName.BackgroundTask]: QueueResponseLegacySchema, - [QueueName.Search]: QueueResponseLegacySchema, - [QueueName.DuplicateDetection]: QueueResponseLegacySchema, - [QueueName.FaceDetection]: QueueResponseLegacySchema, - [QueueName.FacialRecognition]: QueueResponseLegacySchema, - [QueueName.Sidecar]: QueueResponseLegacySchema, - [QueueName.Library]: QueueResponseLegacySchema, - [QueueName.Notification]: QueueResponseLegacySchema, - [QueueName.BackupDatabase]: QueueResponseLegacySchema, - [QueueName.Ocr]: QueueResponseLegacySchema, - [QueueName.Workflow]: QueueResponseLegacySchema, - [QueueName.Editor]: QueueResponseLegacySchema, - }) - .meta({ id: 'QueuesResponseLegacyDto' }); - -export class QueueResponseLegacyDto extends createZodDto(QueueResponseLegacySchema) {} -export class QueuesResponseLegacyDto extends createZodDto(QueuesResponseLegacySchema) {} - -export const mapQueueLegacy = (response: QueueResponseDto): QueueResponseLegacyDto => { - return { - queueStatus: { - isPaused: response.isPaused, - isActive: response.statistics.active > 0, - }, - jobCounts: response.statistics, - }; -}; - -export const mapQueuesLegacy = (responses: QueueResponseDto[]): QueuesResponseLegacyDto => { - const legacy = new QueuesResponseLegacyDto(); - - for (const response of responses) { - legacy[response.name] = mapQueueLegacy(response); - } - - return legacy; -}; diff --git a/server/src/enum.ts b/server/src/enum.ts index 067b5435e4..610316c4c2 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -826,23 +826,6 @@ export enum JobName { export const JobNameSchema = z.enum(JobName).describe('Job name').meta({ id: 'JobName' }); -export enum QueueCommand { - Start = 'start', - /** @deprecated Use `updateQueue` instead */ - Pause = 'pause', - /** @deprecated Use `updateQueue` instead */ - Resume = 'resume', - /** @deprecated Use `emptyQueue` instead */ - Empty = 'empty', - /** @deprecated Use `emptyQueue` instead */ - ClearFailed = 'clear-failed', -} - -export const QueueCommandSchema = z - .enum(QueueCommand) - .describe('Queue command to execute') - .meta({ id: 'QueueCommand' }); - export enum JobStatus { Success = 'success', Failed = 'failed', diff --git a/server/src/services/queue.service.spec.ts b/server/src/services/queue.service.spec.ts index 2c76fee877..bb68e4fa27 100644 --- a/server/src/services/queue.service.spec.ts +++ b/server/src/services/queue.service.spec.ts @@ -1,8 +1,6 @@ -import { BadRequestException } from '@nestjs/common'; import { defaults, SystemConfig } from 'src/config'; -import { ImmichWorker, JobName, QueueCommand, QueueName } from 'src/enum'; +import { ImmichWorker, JobName, QueueName } from 'src/enum'; import { QueueService } from 'src/services/queue.service'; -import { factory } from 'test/small.factory'; import { newTestService, ServiceMocks } from 'test/utils'; describe(QueueService.name, () => { @@ -50,170 +48,4 @@ describe(QueueService.name, () => { ]); }); }); - - describe('getAllJobStatus', () => { - it('should get all job statuses', async () => { - const stats = factory.queueStatistics({ active: 1 }); - const expected = { jobCounts: stats, queueStatus: { isActive: true, isPaused: true } }; - - mocks.job.getJobCounts.mockResolvedValue(stats); - mocks.job.isPaused.mockResolvedValue(true); - - await expect(sut.getAllLegacy(factory.auth())).resolves.toEqual({ - [QueueName.BackgroundTask]: expected, - [QueueName.DuplicateDetection]: expected, - [QueueName.SmartSearch]: expected, - [QueueName.MetadataExtraction]: expected, - [QueueName.Search]: expected, - [QueueName.StorageTemplateMigration]: expected, - [QueueName.Migration]: expected, - [QueueName.ThumbnailGeneration]: expected, - [QueueName.VideoConversion]: expected, - [QueueName.FaceDetection]: expected, - [QueueName.FacialRecognition]: expected, - [QueueName.Sidecar]: expected, - [QueueName.Library]: expected, - [QueueName.Notification]: expected, - [QueueName.BackupDatabase]: expected, - [QueueName.Ocr]: expected, - [QueueName.Workflow]: expected, - [QueueName.Editor]: expected, - }); - }); - }); - - describe('handleCommand', () => { - it('should handle a pause command', async () => { - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.MetadataExtraction, { command: QueueCommand.Pause, force: false }); - - expect(mocks.job.pause).toHaveBeenCalledWith(QueueName.MetadataExtraction); - }); - - it('should handle a resume command', async () => { - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.MetadataExtraction, { command: QueueCommand.Resume, force: false }); - - expect(mocks.job.resume).toHaveBeenCalledWith(QueueName.MetadataExtraction); - }); - - it('should handle an empty command', async () => { - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.MetadataExtraction, { command: QueueCommand.Empty, force: false }); - - expect(mocks.job.empty).toHaveBeenCalledWith(QueueName.MetadataExtraction); - }); - - it('should not start a job that is already running', async () => { - mocks.job.isActive.mockResolvedValue(true); - - await expect( - sut.runCommandLegacy(QueueName.VideoConversion, { command: QueueCommand.Start, force: false }), - ).rejects.toBeInstanceOf(BadRequestException); - - expect(mocks.job.queue).not.toHaveBeenCalled(); - expect(mocks.job.queueAll).not.toHaveBeenCalled(); - }); - - it('should handle a start video conversion command', async () => { - mocks.job.isActive.mockResolvedValue(false); - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.VideoConversion, { command: QueueCommand.Start, force: false }); - - expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.AssetEncodeVideoQueueAll, data: { force: false } }); - }); - - it('should handle a start storage template migration command', async () => { - mocks.job.isActive.mockResolvedValue(false); - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.StorageTemplateMigration, { command: QueueCommand.Start, force: false }); - - expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.StorageTemplateMigration }); - }); - - it('should handle a start smart search command', async () => { - mocks.job.isActive.mockResolvedValue(false); - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.SmartSearch, { command: QueueCommand.Start, force: false }); - - expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.SmartSearchQueueAll, data: { force: false } }); - }); - - it('should handle a start metadata extraction command', async () => { - mocks.job.isActive.mockResolvedValue(false); - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.MetadataExtraction, { command: QueueCommand.Start, force: false }); - - expect(mocks.job.queue).toHaveBeenCalledWith({ - name: JobName.AssetExtractMetadataQueueAll, - data: { force: false }, - }); - }); - - it('should handle a start sidecar command', async () => { - mocks.job.isActive.mockResolvedValue(false); - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.Sidecar, { command: QueueCommand.Start, force: false }); - - expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.SidecarQueueAll, data: { force: false } }); - }); - - it('should handle a start thumbnail generation command', async () => { - mocks.job.isActive.mockResolvedValue(false); - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.ThumbnailGeneration, { command: QueueCommand.Start, force: false }); - - expect(mocks.job.queue).toHaveBeenCalledWith({ - name: JobName.AssetGenerateThumbnailsQueueAll, - data: { force: false }, - }); - }); - - it('should handle a start face detection command', async () => { - mocks.job.isActive.mockResolvedValue(false); - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.FaceDetection, { command: QueueCommand.Start, force: false }); - - expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.AssetDetectFacesQueueAll, data: { force: false } }); - }); - - it('should handle a start facial recognition command', async () => { - mocks.job.isActive.mockResolvedValue(false); - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.FacialRecognition, { command: QueueCommand.Start, force: false }); - - expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.FacialRecognitionQueueAll, data: { force: false } }); - }); - - it('should handle a start backup database command', async () => { - mocks.job.isActive.mockResolvedValue(false); - mocks.job.getJobCounts.mockResolvedValue(factory.queueStatistics()); - - await sut.runCommandLegacy(QueueName.BackupDatabase, { command: QueueCommand.Start, force: false }); - - expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.DatabaseBackup, data: { force: false } }); - }); - - it('should throw a bad request when an invalid queue is used', async () => { - mocks.job.isActive.mockResolvedValue(false); - - await expect( - sut.runCommandLegacy(QueueName.BackgroundTask, { command: QueueCommand.Start, force: false }), - ).rejects.toBeInstanceOf(BadRequestException); - - expect(mocks.job.queue).not.toHaveBeenCalled(); - expect(mocks.job.queueAll).not.toHaveBeenCalled(); - }); - }); }); diff --git a/server/src/services/queue.service.ts b/server/src/services/queue.service.ts index 662ccbe618..c06d97b265 100644 --- a/server/src/services/queue.service.ts +++ b/server/src/services/queue.service.ts @@ -2,12 +2,6 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { SystemConfig } from 'src/config'; import { OnEvent } from 'src/decorators'; import { AuthDto } from 'src/dtos/auth.dto'; -import { - mapQueueLegacy, - mapQueuesLegacy, - QueueResponseLegacyDto, - QueuesResponseLegacyDto, -} from 'src/dtos/queue-legacy.dto'; import { QueueCommandDto, QueueDeleteDto, @@ -23,7 +17,6 @@ import { ImmichWorker, JobName, QueueCleanType, - QueueCommand, QueueName, } from 'src/enum'; import { ArgOf } from 'src/repositories/event.repository'; @@ -99,51 +92,10 @@ export class QueueService extends BaseService { this.services = services; } - async runCommandLegacy(name: QueueName, dto: QueueCommandDto): Promise { - this.logger.debug(`Handling command: queue=${name},command=${dto.command},force=${dto.force}`); - - switch (dto.command) { - case QueueCommand.Start: { - await this.start(name, dto); - break; - } - - case QueueCommand.Pause: { - await this.jobRepository.pause(name); - break; - } - - case QueueCommand.Resume: { - await this.jobRepository.resume(name); - break; - } - - case QueueCommand.Empty: { - await this.jobRepository.empty(name); - break; - } - - case QueueCommand.ClearFailed: { - const failedJobs = await this.jobRepository.clear(name, QueueCleanType.Failed); - this.logger.debug(`Cleared failed jobs: ${failedJobs}`); - break; - } - } - - const response = await this.getByName(name); - - return mapQueueLegacy(response); - } - async getAll(_auth: AuthDto): Promise { return Promise.all(Object.values(QueueName).map((name) => this.getByName(name))); } - async getAllLegacy(auth: AuthDto): Promise { - const responses = await this.getAll(auth); - return mapQueuesLegacy(responses); - } - get(auth: AuthDto, name: QueueName): Promise { return this.getByName(name); } diff --git a/server/test/small.factory.ts b/server/test/small.factory.ts index e4001d18ab..671a3b7ac2 100644 --- a/server/test/small.factory.ts +++ b/server/test/small.factory.ts @@ -1,6 +1,5 @@ import { AuthApiKey, AuthSharedLink, AuthUser, Exif, Library, UserAdmin } from 'src/database'; import { AuthDto } from 'src/dtos/auth.dto'; -import { QueueStatisticsDto } from 'src/dtos/queue.dto'; import { AssetFileType, Permission, UserStatus } from 'src/enum'; import { v4, v7 } from 'uuid'; @@ -100,16 +99,6 @@ const authUserFactory = (authUser: Partial = {}) => { return { id, isAdmin, name, email, quotaUsageInBytes, quotaSizeInBytes }; }; -const queueStatisticsFactory = (dto?: Partial) => ({ - active: 0, - completed: 0, - failed: 0, - delayed: 0, - waiting: 0, - paused: 0, - ...dto, -}); - const userAdminFactory = (user: Partial = {}) => { const { id = newUuid(), @@ -236,7 +225,6 @@ export const factory = { assetOcr: assetOcrFactory, auth: authFactory, library: libraryFactory, - queueStatistics: queueStatisticsFactory, versionHistory: versionHistoryFactory, jobAssets: { sidecarWrite: assetSidecarWriteFactory,