mirror of
https://github.com/immich-app/immich.git
synced 2026-02-13 12:27:56 +03:00
feat: create job with data dto
This commit is contained in:
2
mobile/openapi/README.md
generated
2
mobile/openapi/README.md
generated
@@ -210,6 +210,7 @@ Class | Method | HTTP request | Description
|
||||
*QueuesApi* | [**getQueue**](doc//QueuesApi.md#getqueue) | **GET** /queues/{name} | Retrieve a queue
|
||||
*QueuesApi* | [**getQueueJobs**](doc//QueuesApi.md#getqueuejobs) | **GET** /queues/{name}/jobs | Retrieve queue jobs
|
||||
*QueuesApi* | [**getQueues**](doc//QueuesApi.md#getqueues) | **GET** /queues | List all queues
|
||||
*QueuesApi* | [**queueJob**](doc//QueuesApi.md#queuejob) | **POST** /queues/job | Create a manual job
|
||||
*QueuesApi* | [**updateQueue**](doc//QueuesApi.md#updatequeue) | **PUT** /queues/{name} | Update a queue
|
||||
*SearchApi* | [**getAssetsByCity**](doc//SearchApi.md#getassetsbycity) | **GET** /search/cities | Retrieve assets by city
|
||||
*SearchApi* | [**getExploreData**](doc//SearchApi.md#getexploredata) | **GET** /search/explore | Retrieve explore data
|
||||
@@ -495,6 +496,7 @@ Class | Method | HTTP request | Description
|
||||
- [QueueCommand](doc//QueueCommand.md)
|
||||
- [QueueCommandDto](doc//QueueCommandDto.md)
|
||||
- [QueueDeleteDto](doc//QueueDeleteDto.md)
|
||||
- [QueueJobCreateDto](doc//QueueJobCreateDto.md)
|
||||
- [QueueJobResponseDto](doc//QueueJobResponseDto.md)
|
||||
- [QueueJobStatus](doc//QueueJobStatus.md)
|
||||
- [QueueName](doc//QueueName.md)
|
||||
|
||||
1
mobile/openapi/lib/api.dart
generated
1
mobile/openapi/lib/api.dart
generated
@@ -241,6 +241,7 @@ 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_create_dto.dart';
|
||||
part 'model/queue_job_response_dto.dart';
|
||||
part 'model/queue_job_status.dart';
|
||||
part 'model/queue_name.dart';
|
||||
|
||||
48
mobile/openapi/lib/api/queues_api.dart
generated
48
mobile/openapi/lib/api/queues_api.dart
generated
@@ -245,6 +245,54 @@ class QueuesApi {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Create a manual job
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// Note: This method returns the HTTP [Response].
|
||||
///
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [QueueJobCreateDto] queueJobCreateDto (required):
|
||||
Future<Response> queueJobWithHttpInfo(QueueJobCreateDto queueJobCreateDto,) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final apiPath = r'/queues/job';
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody = queueJobCreateDto;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
const contentTypes = <String>['application/json'];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
apiPath,
|
||||
'POST',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a manual job
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [QueueJobCreateDto] queueJobCreateDto (required):
|
||||
Future<void> queueJob(QueueJobCreateDto queueJobCreateDto,) async {
|
||||
final response = await queueJobWithHttpInfo(queueJobCreateDto,);
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
}
|
||||
|
||||
/// Update a queue
|
||||
///
|
||||
/// Change the paused status of a specific queue.
|
||||
|
||||
2
mobile/openapi/lib/api_client.dart
generated
2
mobile/openapi/lib/api_client.dart
generated
@@ -530,6 +530,8 @@ class ApiClient {
|
||||
return QueueCommandDto.fromJson(value);
|
||||
case 'QueueDeleteDto':
|
||||
return QueueDeleteDto.fromJson(value);
|
||||
case 'QueueJobCreateDto':
|
||||
return QueueJobCreateDto.fromJson(value);
|
||||
case 'QueueJobResponseDto':
|
||||
return QueueJobResponseDto.fromJson(value);
|
||||
case 'QueueJobStatus':
|
||||
|
||||
99
mobile/openapi/lib/model/queue_job_create_dto.dart
generated
Normal file
99
mobile/openapi/lib/model/queue_job_create_dto.dart
generated
Normal file
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// 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 QueueJobCreateDto {
|
||||
/// Returns a new [QueueJobCreateDto] instance.
|
||||
QueueJobCreateDto({
|
||||
required this.job,
|
||||
});
|
||||
|
||||
Object job;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is QueueJobCreateDto &&
|
||||
other.job == job;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(job.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'QueueJobCreateDto[job=$job]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'job'] = this.job;
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [QueueJobCreateDto] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static QueueJobCreateDto? fromJson(dynamic value) {
|
||||
upgradeDto(value, "QueueJobCreateDto");
|
||||
if (value is Map) {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return QueueJobCreateDto(
|
||||
job: mapValueOfType<Object>(json, r'job')!,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<QueueJobCreateDto> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <QueueJobCreateDto>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = QueueJobCreateDto.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, QueueJobCreateDto> mapFromJson(dynamic json) {
|
||||
final map = <String, QueueJobCreateDto>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = QueueJobCreateDto.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of QueueJobCreateDto-objects as value to a dart map
|
||||
static Map<String, List<QueueJobCreateDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<QueueJobCreateDto>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
// ignore: parameter_assignments
|
||||
json = json.cast<String, dynamic>();
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = QueueJobCreateDto.listFromJson(entry.value, growable: growable,);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'job',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8476,6 +8476,56 @@
|
||||
"x-immich-state": "Alpha"
|
||||
}
|
||||
},
|
||||
"/queues/job": {
|
||||
"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": "queueJob",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/QueueJobCreateDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
},
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"summary": "Create a manual job",
|
||||
"tags": [
|
||||
"Queues"
|
||||
],
|
||||
"x-immich-admin-only": true,
|
||||
"x-immich-history": [
|
||||
{
|
||||
"version": "v2.5.0",
|
||||
"state": "Added"
|
||||
},
|
||||
{
|
||||
"version": "v2.5.0",
|
||||
"state": "Alpha"
|
||||
}
|
||||
],
|
||||
"x-immich-permission": "job.create",
|
||||
"x-immich-state": "Alpha"
|
||||
}
|
||||
},
|
||||
"/queues/{name}": {
|
||||
"get": {
|
||||
"description": "Retrieves a specific queue by its name.",
|
||||
@@ -19135,6 +19185,17 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"QueueJobCreateDto": {
|
||||
"properties": {
|
||||
"job": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"job"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"QueueJobResponseDto": {
|
||||
"properties": {
|
||||
"data": {
|
||||
|
||||
@@ -1038,6 +1038,9 @@ export type QueueResponseDto = {
|
||||
name: QueueName;
|
||||
statistics: QueueStatisticsDto;
|
||||
};
|
||||
export type QueueJobCreateDto = {
|
||||
job: object;
|
||||
};
|
||||
export type QueueUpdateDto = {
|
||||
isPaused?: boolean;
|
||||
};
|
||||
@@ -3834,6 +3837,18 @@ export function getQueues(opts?: Oazapfts.RequestOpts) {
|
||||
...opts
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* Create a manual job
|
||||
*/
|
||||
export function queueJob({ queueJobCreateDto }: {
|
||||
queueJobCreateDto: QueueJobCreateDto;
|
||||
}, opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchText("/queues/job", oazapfts.json({
|
||||
...opts,
|
||||
method: "POST",
|
||||
body: queueJobCreateDto
|
||||
})));
|
||||
}
|
||||
/**
|
||||
* Retrieve a queue
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Put, Query } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { Endpoint, HistoryBuilder } from 'src/decorators';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import {
|
||||
QueueDeleteDto,
|
||||
QueueJobCreateDto,
|
||||
QueueJobResponseDto,
|
||||
QueueJobSearchDto,
|
||||
QueueNameParamDto,
|
||||
@@ -19,6 +20,19 @@ import { QueueService } from 'src/services/queue.service';
|
||||
export class QueueController {
|
||||
constructor(private service: QueueService) {}
|
||||
|
||||
@Post('job')
|
||||
@Authenticated({ permission: Permission.JobCreate, admin: true })
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
@Endpoint({
|
||||
summary: 'Create a manual job',
|
||||
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.',
|
||||
history: new HistoryBuilder().added('v2.5.0').alpha('v2.5.0'),
|
||||
})
|
||||
queueJob(@Body() dto: QueueJobCreateDto): Promise<void> {
|
||||
return this.service.createJob(dto);
|
||||
}
|
||||
|
||||
@Get()
|
||||
@Authenticated({ permission: Permission.QueueRead, admin: true })
|
||||
@Endpoint({
|
||||
|
||||
@@ -1,7 +1,75 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ClassConstructor, Transform, Type } from 'class-transformer';
|
||||
import { Equals, IsBoolean, IsDefined, IsOptional, ValidateNested } from 'class-validator';
|
||||
import { HistoryBuilder, Property } from 'src/decorators';
|
||||
import { JobName, QueueCommand, QueueJobStatus, QueueName } from 'src/enum';
|
||||
import { ValidateBoolean, ValidateEnum } from 'src/validation';
|
||||
import { transformToOneOf, ValidateBoolean, ValidateEnum } from 'src/validation';
|
||||
|
||||
class BaseJobData {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
force?: boolean;
|
||||
}
|
||||
|
||||
class BaseJob {
|
||||
@ValidateNested()
|
||||
@Type(() => BaseJobData)
|
||||
data!: BaseJobData;
|
||||
}
|
||||
|
||||
class JobTagCleanup extends BaseJob {
|
||||
@Equals(JobName.TagCleanup)
|
||||
name!: JobName.TagCleanup;
|
||||
}
|
||||
|
||||
class JobPersonCleanup extends BaseJob {
|
||||
@Equals(JobName.PersonCleanup)
|
||||
name!: JobName.PersonCleanup;
|
||||
}
|
||||
|
||||
class JobUserDeleteCheck extends BaseJob {
|
||||
@Equals(JobName.UserDeleteCheck)
|
||||
name!: JobName.UserDeleteCheck;
|
||||
}
|
||||
|
||||
class JobMemoryCleanup extends BaseJob {
|
||||
@Equals(JobName.MemoryCleanup)
|
||||
name!: JobName.MemoryCleanup;
|
||||
}
|
||||
|
||||
class JobMemoryGenerate extends BaseJob {
|
||||
@Equals(JobName.MemoryGenerate)
|
||||
name!: JobName.MemoryGenerate;
|
||||
}
|
||||
|
||||
class JobDatabaseBackup extends BaseJob {
|
||||
@Equals(JobName.DatabaseBackup)
|
||||
name!: JobName.DatabaseBackup;
|
||||
}
|
||||
|
||||
const JOB_MAP: Record<string, ClassConstructor<object>> = {
|
||||
[JobName.TagCleanup]: JobTagCleanup,
|
||||
[JobName.PersonCleanup]: JobPersonCleanup,
|
||||
[JobName.UserDeleteCheck]: JobUserDeleteCheck,
|
||||
[JobName.MemoryCleanup]: JobMemoryCleanup,
|
||||
[JobName.MemoryGenerate]: JobMemoryGenerate,
|
||||
[JobName.DatabaseBackup]: JobDatabaseBackup,
|
||||
};
|
||||
|
||||
export class QueueJobCreateDto {
|
||||
@ValidateNested()
|
||||
@Transform(transformToOneOf(JOB_MAP))
|
||||
@IsDefined({
|
||||
message: `job.name must be one of ${Object.keys(JOB_MAP)}`,
|
||||
})
|
||||
job!:
|
||||
| JobTagCleanup
|
||||
| JobPersonCleanup
|
||||
| JobUserDeleteCheck
|
||||
| JobMemoryCleanup
|
||||
| JobMemoryGenerate
|
||||
| JobDatabaseBackup;
|
||||
}
|
||||
|
||||
export class QueueNameParamDto {
|
||||
@ValidateEnum({ enum: QueueName, name: 'QueueName' })
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
import {
|
||||
QueueCommandDto,
|
||||
QueueDeleteDto,
|
||||
QueueJobCreateDto,
|
||||
QueueJobResponseDto,
|
||||
QueueJobSearchDto,
|
||||
QueueResponseDto,
|
||||
@@ -100,6 +101,10 @@ export class QueueService extends BaseService {
|
||||
this.services = services;
|
||||
}
|
||||
|
||||
createJob(dto: QueueJobCreateDto): Promise<void> {
|
||||
return this.jobRepository.queue(dto.job);
|
||||
}
|
||||
|
||||
async runCommandLegacy(name: QueueName, dto: QueueCommandDto): Promise<QueueResponseLegacyDto> {
|
||||
this.logger.debug(`Handling command: queue=${name},command=${dto.command},force=${dto.force}`);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
applyDecorators,
|
||||
} from '@nestjs/common';
|
||||
import { ApiProperty, ApiPropertyOptions } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
import { ClassConstructor, Transform, TransformFnParams, plainToInstance } from 'class-transformer';
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
@@ -417,3 +417,8 @@ export function IsIPRange(options: IsIPRangeOptions, validationOptions?: Validat
|
||||
validationOptions,
|
||||
);
|
||||
}
|
||||
|
||||
export const transformToOneOf =
|
||||
<T extends Record<string, ClassConstructor<object>>>(map: T) =>
|
||||
({ value }: TransformFnParams) =>
|
||||
value && typeof value === 'object' && map[value.name] ? plainToInstance(map[value.name], value) : null;
|
||||
|
||||
Reference in New Issue
Block a user