mirror of
https://github.com/immich-app/immich.git
synced 2026-03-25 11:08:56 +03:00
docs(openapi): add descriptions to OpenAPI specification (#25185)
* faces * add openapi descriptions * remove dto descriptions * gen openapi * dtos * fix dtos * fix more * fix build * more * complete dtos * descriptions on rebase * gen rebase * revert correct integer type conversion * gen after revert * revert correct nullables * regen after revert * actually incorrect adding default here * revert correct number type conversion * regen after revert * revert nullable usage * regen fully * readd some comments * one more * one more * use enum * add missing * add missing controllers * add missing dtos * complete it * more * describe global key and slug * add remaining body and param descriptions * lint and format * cleanup * response and schema descriptions * test patch according to suggestion * revert added api response objects * revert added api body objects * revert added api param object * revert added api query objects * revert reorganized http code objects * revert reorganize ApiOkResponse objects * revert added api response objects (2) * revert added api tag object * revert added api schema objects * migrate missing asset.dto.ts * regenerate openapi builds * delete generated mustache files * remove descriptions from properties that are schemas * lint * revert nullable type changes * revert int/num type changes * remove explicit default * readd comment * lint * pr fixes * last bits and pieces * lint and format * chore: remove rejected patches * fix: deleting asset from asset-viewer on search results (#25596) * fix: escape handling in search asset viewer (#25621) * fix: correctly show owner in album options modal (#25618) * fix: validation issues * fix: validation issues --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: Min Idzelis <min123@gmail.com> Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com> Co-authored-by: Paul Makles <me@insrt.uk>
This commit is contained in:
@@ -17,32 +17,35 @@ import { UserMetadata } from 'src/types';
|
||||
import { ValidateBoolean, ValidateDate, ValidateEnum, ValidateUUID } from 'src/validation';
|
||||
|
||||
export class AssetFullSyncDto {
|
||||
@ValidateUUID({ optional: true })
|
||||
@ValidateUUID({ optional: true, description: 'Last asset ID (pagination)' })
|
||||
lastId?: string;
|
||||
|
||||
@ValidateDate()
|
||||
@ValidateDate({ description: 'Sync assets updated until this date' })
|
||||
updatedUntil!: Date;
|
||||
|
||||
@ApiProperty({ type: 'integer', description: 'Maximum number of assets to return' })
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
@ApiProperty({ type: 'integer' })
|
||||
limit!: number;
|
||||
|
||||
@ValidateUUID({ optional: true })
|
||||
@ValidateUUID({ optional: true, description: 'Filter by user ID' })
|
||||
userId?: string;
|
||||
}
|
||||
|
||||
export class AssetDeltaSyncDto {
|
||||
@ValidateDate()
|
||||
@ValidateDate({ description: 'Sync assets updated after this date' })
|
||||
updatedAfter!: Date;
|
||||
|
||||
@ValidateUUID({ each: true })
|
||||
@ValidateUUID({ each: true, description: 'User IDs to sync' })
|
||||
userIds!: string[];
|
||||
}
|
||||
|
||||
export class AssetDeltaSyncResponseDto {
|
||||
@ApiProperty({ description: 'Whether full sync is needed' })
|
||||
needsFullSync!: boolean;
|
||||
@ApiProperty({ description: 'Upserted assets' })
|
||||
upserted!: AssetResponseDto[];
|
||||
@ApiProperty({ description: 'Deleted asset IDs' })
|
||||
deleted!: string[];
|
||||
}
|
||||
|
||||
@@ -57,21 +60,31 @@ export const ExtraModel = (): ClassDecorator => {
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncUserV1 {
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'User name' })
|
||||
name!: string;
|
||||
@ApiProperty({ description: 'User email' })
|
||||
email!: string;
|
||||
@ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', nullable: true })
|
||||
@ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', description: 'User avatar color' })
|
||||
avatarColor!: UserAvatarColor | null;
|
||||
@ApiProperty({ description: 'User deleted at' })
|
||||
deletedAt!: Date | null;
|
||||
@ApiProperty({ description: 'User has profile image' })
|
||||
hasProfileImage!: boolean;
|
||||
@ApiProperty({ description: 'User profile changed at' })
|
||||
profileChangedAt!: Date;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAuthUserV1 extends SyncUserV1 {
|
||||
@ApiProperty({ description: 'User is admin' })
|
||||
isAdmin!: boolean;
|
||||
@ApiProperty({ description: 'User pin code' })
|
||||
pinCode!: string | null;
|
||||
@ApiProperty({ description: 'User OAuth ID' })
|
||||
oauthId!: string;
|
||||
@ApiProperty({ description: 'User storage label' })
|
||||
storageLabel!: string | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
quotaSizeInBytes!: number | null;
|
||||
@@ -81,135 +94,189 @@ export class SyncAuthUserV1 extends SyncUserV1 {
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncUserDeleteV1 {
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncPartnerV1 {
|
||||
@ApiProperty({ description: 'Shared by ID' })
|
||||
sharedById!: string;
|
||||
@ApiProperty({ description: 'Shared with ID' })
|
||||
sharedWithId!: string;
|
||||
@ApiProperty({ description: 'In timeline' })
|
||||
inTimeline!: boolean;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncPartnerDeleteV1 {
|
||||
@ApiProperty({ description: 'Shared by ID' })
|
||||
sharedById!: string;
|
||||
@ApiProperty({ description: 'Shared with ID' })
|
||||
sharedWithId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
@ApiProperty({ description: 'Original file name' })
|
||||
originalFileName!: string;
|
||||
@ApiProperty({ description: 'Thumbhash' })
|
||||
thumbhash!: string | null;
|
||||
@ApiProperty({ description: 'Checksum' })
|
||||
checksum!: string;
|
||||
@ApiProperty({ description: 'File created at' })
|
||||
fileCreatedAt!: Date | null;
|
||||
@ApiProperty({ description: 'File modified at' })
|
||||
fileModifiedAt!: Date | null;
|
||||
@ApiProperty({ description: 'Local date time' })
|
||||
localDateTime!: Date | null;
|
||||
@ApiProperty({ description: 'Duration' })
|
||||
duration!: string | null;
|
||||
@ValidateEnum({ enum: AssetType, name: 'AssetTypeEnum' })
|
||||
@ValidateEnum({ enum: AssetType, name: 'AssetTypeEnum', description: 'Asset type' })
|
||||
type!: AssetType;
|
||||
@ApiProperty({ description: 'Deleted at' })
|
||||
deletedAt!: Date | null;
|
||||
@ApiProperty({ description: 'Is favorite' })
|
||||
isFavorite!: boolean;
|
||||
@ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility' })
|
||||
@ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', description: 'Asset visibility' })
|
||||
visibility!: AssetVisibility;
|
||||
@ApiProperty({ description: 'Live photo video ID' })
|
||||
livePhotoVideoId!: string | null;
|
||||
@ApiProperty({ description: 'Stack ID' })
|
||||
stackId!: string | null;
|
||||
@ApiProperty({ description: 'Library ID' })
|
||||
libraryId!: string | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
@ApiProperty({ type: 'integer', description: 'Asset width' })
|
||||
width!: number | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
@ApiProperty({ type: 'integer', description: 'Asset height' })
|
||||
height!: number | null;
|
||||
@ApiProperty({ type: 'boolean' })
|
||||
@ApiProperty({ description: 'Is edited' })
|
||||
isEdited!: boolean;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetDeleteV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetExifV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
@ApiProperty({ description: 'Description' })
|
||||
description!: string | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
@ApiProperty({ type: 'integer', description: 'Exif image width' })
|
||||
exifImageWidth!: number | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
@ApiProperty({ type: 'integer', description: 'Exif image height' })
|
||||
exifImageHeight!: number | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
@ApiProperty({ type: 'integer', description: 'File size in byte' })
|
||||
fileSizeInByte!: number | null;
|
||||
@ApiProperty({ description: 'Orientation' })
|
||||
orientation!: string | null;
|
||||
@ApiProperty({ description: 'Date time original' })
|
||||
dateTimeOriginal!: Date | null;
|
||||
@ApiProperty({ description: 'Modify date' })
|
||||
modifyDate!: Date | null;
|
||||
@ApiProperty({ description: 'Time zone' })
|
||||
timeZone!: string | null;
|
||||
@ApiProperty({ type: 'number', format: 'double' })
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'Latitude' })
|
||||
latitude!: number | null;
|
||||
@ApiProperty({ type: 'number', format: 'double' })
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'Longitude' })
|
||||
longitude!: number | null;
|
||||
@ApiProperty({ description: 'Projection type' })
|
||||
projectionType!: string | null;
|
||||
@ApiProperty({ description: 'City' })
|
||||
city!: string | null;
|
||||
@ApiProperty({ description: 'State' })
|
||||
state!: string | null;
|
||||
@ApiProperty({ description: 'Country' })
|
||||
country!: string | null;
|
||||
@ApiProperty({ description: 'Make' })
|
||||
make!: string | null;
|
||||
@ApiProperty({ description: 'Model' })
|
||||
model!: string | null;
|
||||
@ApiProperty({ description: 'Lens model' })
|
||||
lensModel!: string | null;
|
||||
@ApiProperty({ type: 'number', format: 'double' })
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'F number' })
|
||||
fNumber!: number | null;
|
||||
@ApiProperty({ type: 'number', format: 'double' })
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'Focal length' })
|
||||
focalLength!: number | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
@ApiProperty({ type: 'integer', description: 'ISO' })
|
||||
iso!: number | null;
|
||||
@ApiProperty({ description: 'Exposure time' })
|
||||
exposureTime!: string | null;
|
||||
@ApiProperty({ description: 'Profile description' })
|
||||
profileDescription!: string | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
@ApiProperty({ type: 'integer', description: 'Rating' })
|
||||
rating!: number | null;
|
||||
@ApiProperty({ type: 'number', format: 'double' })
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'FPS' })
|
||||
fps!: number | null;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetMetadataV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
@ApiProperty({ description: 'Key' })
|
||||
key!: string;
|
||||
@ApiProperty({ description: 'Value' })
|
||||
value!: object;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetMetadataDeleteV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
@ApiProperty({ description: 'Key' })
|
||||
key!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumDeleteV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumUserDeleteV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumUserV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
@ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole' })
|
||||
@ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole', description: 'Album user role' })
|
||||
role!: AlbumUserRole;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
@ApiProperty({ description: 'Album name' })
|
||||
name!: string;
|
||||
@ApiProperty({ description: 'Album description' })
|
||||
description!: string;
|
||||
@ApiProperty({ description: 'Created at' })
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ description: 'Updated at' })
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ description: 'Thumbnail asset ID' })
|
||||
thumbnailAssetId!: string | null;
|
||||
@ApiProperty({ description: 'Is activity enabled' })
|
||||
isActivityEnabled!: boolean;
|
||||
@ValidateEnum({ enum: AssetOrder, name: 'AssetOrder' })
|
||||
order!: AssetOrder;
|
||||
@@ -217,87 +284,127 @@ export class SyncAlbumV1 {
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumToAssetV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumToAssetDeleteV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncMemoryV1 {
|
||||
@ApiProperty({ description: 'Memory ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Created at' })
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ description: 'Updated at' })
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ description: 'Deleted at' })
|
||||
deletedAt!: Date | null;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
@ValidateEnum({ enum: MemoryType, name: 'MemoryType' })
|
||||
@ValidateEnum({ enum: MemoryType, name: 'MemoryType', description: 'Memory type' })
|
||||
type!: MemoryType;
|
||||
@ApiProperty({ description: 'Data' })
|
||||
data!: object;
|
||||
@ApiProperty({ description: 'Is saved' })
|
||||
isSaved!: boolean;
|
||||
@ApiProperty({ description: 'Memory at' })
|
||||
memoryAt!: Date;
|
||||
@ApiProperty({ description: 'Seen at' })
|
||||
seenAt!: Date | null;
|
||||
@ApiProperty({ description: 'Show at' })
|
||||
showAt!: Date | null;
|
||||
@ApiProperty({ description: 'Hide at' })
|
||||
hideAt!: Date | null;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncMemoryDeleteV1 {
|
||||
@ApiProperty({ description: 'Memory ID' })
|
||||
memoryId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncMemoryAssetV1 {
|
||||
@ApiProperty({ description: 'Memory ID' })
|
||||
memoryId!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncMemoryAssetDeleteV1 {
|
||||
@ApiProperty({ description: 'Memory ID' })
|
||||
memoryId!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncStackV1 {
|
||||
@ApiProperty({ description: 'Stack ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Created at' })
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ description: 'Updated at' })
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ description: 'Primary asset ID' })
|
||||
primaryAssetId!: string;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncStackDeleteV1 {
|
||||
@ApiProperty({ description: 'Stack ID' })
|
||||
stackId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncPersonV1 {
|
||||
@ApiProperty({ description: 'Person ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Created at' })
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ description: 'Updated at' })
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
@ApiProperty({ description: 'Person name' })
|
||||
name!: string;
|
||||
@ApiProperty({ description: 'Birth date' })
|
||||
birthDate!: Date | null;
|
||||
@ApiProperty({ description: 'Is hidden' })
|
||||
isHidden!: boolean;
|
||||
@ApiProperty({ description: 'Is favorite' })
|
||||
isFavorite!: boolean;
|
||||
@ApiProperty({ description: 'Color' })
|
||||
color!: string | null;
|
||||
@ApiProperty({ description: 'Face asset ID' })
|
||||
faceAssetId!: string | null;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncPersonDeleteV1 {
|
||||
@ApiProperty({ description: 'Person ID' })
|
||||
personId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetFaceV1 {
|
||||
@ApiProperty({ description: 'Asset face ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
@ApiProperty({ description: 'Person ID' })
|
||||
personId!: string | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
imageWidth!: number;
|
||||
@@ -311,26 +418,31 @@ export class SyncAssetFaceV1 {
|
||||
boundingBoxX2!: number;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
boundingBoxY2!: number;
|
||||
@ApiProperty({ description: 'Source type' })
|
||||
sourceType!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetFaceDeleteV1 {
|
||||
@ApiProperty({ description: 'Asset face ID' })
|
||||
assetFaceId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncUserMetadataV1 {
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
@ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey' })
|
||||
@ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey', description: 'User metadata key' })
|
||||
key!: UserMetadataKey;
|
||||
@ApiProperty({ description: 'User metadata value' })
|
||||
value!: UserMetadata[UserMetadataKey];
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncUserMetadataDeleteV1 {
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
@ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey' })
|
||||
@ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey', description: 'User metadata key' })
|
||||
key!: UserMetadataKey;
|
||||
}
|
||||
|
||||
@@ -394,26 +506,34 @@ export type SyncItem = {
|
||||
};
|
||||
|
||||
export class SyncStreamDto {
|
||||
@ValidateEnum({ enum: SyncRequestType, name: 'SyncRequestType', each: true })
|
||||
@ValidateEnum({ enum: SyncRequestType, name: 'SyncRequestType', each: true, description: 'Sync request types' })
|
||||
types!: SyncRequestType[];
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
@ValidateBoolean({ optional: true, description: 'Reset sync state' })
|
||||
reset?: boolean;
|
||||
}
|
||||
|
||||
export class SyncAckDto {
|
||||
@ValidateEnum({ enum: SyncEntityType, name: 'SyncEntityType' })
|
||||
@ValidateEnum({ enum: SyncEntityType, name: 'SyncEntityType', description: 'Sync entity type' })
|
||||
type!: SyncEntityType;
|
||||
@ApiProperty({ description: 'Acknowledgment ID' })
|
||||
ack!: string;
|
||||
}
|
||||
|
||||
export class SyncAckSetDto {
|
||||
@ApiProperty({ description: 'Acknowledgment IDs (max 1000)' })
|
||||
@ArrayMaxSize(1000)
|
||||
@IsString({ each: true })
|
||||
acks!: string[];
|
||||
}
|
||||
|
||||
export class SyncAckDeleteDto {
|
||||
@ValidateEnum({ enum: SyncEntityType, name: 'SyncEntityType', optional: true, each: true })
|
||||
@ValidateEnum({
|
||||
enum: SyncEntityType,
|
||||
name: 'SyncEntityType',
|
||||
optional: true,
|
||||
each: true,
|
||||
description: 'Sync entity types to delete acks for',
|
||||
})
|
||||
types?: SyncEntityType[];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user