immich/server/src/dtos/user-preferences.dto.ts
Timon 8db61d341f
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>
2026-01-29 08:49:15 -05:00

303 lines
9.5 KiB
TypeScript

import { ApiProperty, ApiPropertyOptional, ApiSchema } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IsDateString, IsInt, IsPositive, ValidateNested } from 'class-validator';
import { AssetOrder, UserAvatarColor } from 'src/enum';
import { UserPreferences } from 'src/types';
import { Optional, ValidateBoolean, ValidateEnum } from 'src/validation';
class AvatarUpdate {
@ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', optional: true, description: 'Avatar color' })
color?: UserAvatarColor;
}
class MemoriesUpdate {
@ValidateBoolean({ optional: true, description: 'Whether memories are enabled' })
enabled?: boolean;
@Optional()
@IsInt()
@IsPositive()
@ApiProperty({ type: 'integer', description: 'Memory duration in seconds' })
duration?: number;
}
class RatingsUpdate {
@ValidateBoolean({ optional: true, description: 'Whether ratings are enabled' })
enabled?: boolean;
}
@ApiSchema({ description: 'Album preferences' })
class AlbumsUpdate {
@ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', optional: true, description: 'Default asset order for albums' })
defaultAssetOrder?: AssetOrder;
}
class FoldersUpdate {
@ValidateBoolean({ optional: true, description: 'Whether folders are enabled' })
enabled?: boolean;
@ValidateBoolean({ optional: true, description: 'Whether folders appear in web sidebar' })
sidebarWeb?: boolean;
}
class PeopleUpdate {
@ValidateBoolean({ optional: true, description: 'Whether people are enabled' })
enabled?: boolean;
@ValidateBoolean({ optional: true, description: 'Whether people appear in web sidebar' })
sidebarWeb?: boolean;
}
class SharedLinksUpdate {
@ValidateBoolean({ optional: true, description: 'Whether shared links are enabled' })
enabled?: boolean;
@ValidateBoolean({ optional: true, description: 'Whether shared links appear in web sidebar' })
sidebarWeb?: boolean;
}
class TagsUpdate {
@ValidateBoolean({ optional: true, description: 'Whether tags are enabled' })
enabled?: boolean;
@ValidateBoolean({ optional: true, description: 'Whether tags appear in web sidebar' })
sidebarWeb?: boolean;
}
class EmailNotificationsUpdate {
@ValidateBoolean({ optional: true, description: 'Whether email notifications are enabled' })
enabled?: boolean;
@ValidateBoolean({ optional: true, description: 'Whether to receive email notifications for album invites' })
albumInvite?: boolean;
@ValidateBoolean({ optional: true, description: 'Whether to receive email notifications for album updates' })
albumUpdate?: boolean;
}
class DownloadUpdate implements Partial<DownloadResponse> {
@Optional()
@IsInt()
@IsPositive()
@ApiPropertyOptional({ type: 'integer', description: 'Maximum archive size in bytes' })
archiveSize?: number;
@ValidateBoolean({ optional: true, description: 'Whether to include embedded videos in downloads' })
includeEmbeddedVideos?: boolean;
}
class PurchaseUpdate {
@ValidateBoolean({ optional: true, description: 'Whether to show support badge' })
showSupportBadge?: boolean;
@ApiPropertyOptional({ description: 'Date until which to hide buy button' })
@IsDateString()
@Optional()
hideBuyButtonUntil?: string;
}
class CastUpdate {
@ValidateBoolean({ optional: true, description: 'Whether Google Cast is enabled' })
gCastEnabled?: boolean;
}
export class UserPreferencesUpdateDto {
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => AlbumsUpdate)
albums?: AlbumsUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => FoldersUpdate)
folders?: FoldersUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => MemoriesUpdate)
memories?: MemoriesUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => PeopleUpdate)
people?: PeopleUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => RatingsUpdate)
ratings?: RatingsUpdate;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined, required: false })
@Optional()
@ValidateNested()
@Type(() => SharedLinksUpdate)
sharedLinks?: SharedLinksUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => TagsUpdate)
tags?: TagsUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => AvatarUpdate)
avatar?: AvatarUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => EmailNotificationsUpdate)
emailNotifications?: EmailNotificationsUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => DownloadUpdate)
download?: DownloadUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => PurchaseUpdate)
purchase?: PurchaseUpdate;
// Description lives on schema to avoid duplication
@ApiPropertyOptional({ description: undefined })
@Optional()
@ValidateNested()
@Type(() => CastUpdate)
cast?: CastUpdate;
}
class AlbumsResponse {
@ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', description: 'Default asset order for albums' })
defaultAssetOrder: AssetOrder = AssetOrder.Desc;
}
class RatingsResponse {
@ApiProperty({ description: 'Whether ratings are enabled' })
enabled: boolean = false;
}
class MemoriesResponse {
@ApiProperty({ description: 'Whether memories are enabled' })
enabled: boolean = true;
@ApiProperty({ type: 'integer', description: 'Memory duration in seconds' })
duration: number = 5;
}
class FoldersResponse {
@ApiProperty({ description: 'Whether folders are enabled' })
enabled: boolean = false;
@ApiProperty({ description: 'Whether folders appear in web sidebar' })
sidebarWeb: boolean = false;
}
class PeopleResponse {
@ApiProperty({ description: 'Whether people are enabled' })
enabled: boolean = true;
@ApiProperty({ description: 'Whether people appear in web sidebar' })
sidebarWeb: boolean = false;
}
class TagsResponse {
@ApiProperty({ description: 'Whether tags are enabled' })
enabled: boolean = true;
@ApiProperty({ description: 'Whether tags appear in web sidebar' })
sidebarWeb: boolean = true;
}
class SharedLinksResponse {
@ApiProperty({ description: 'Whether shared links are enabled' })
enabled: boolean = true;
@ApiProperty({ description: 'Whether shared links appear in web sidebar' })
sidebarWeb: boolean = false;
}
class EmailNotificationsResponse {
@ApiProperty({ description: 'Whether email notifications are enabled' })
enabled!: boolean;
@ApiProperty({ description: 'Whether to receive email notifications for album invites' })
albumInvite!: boolean;
@ApiProperty({ description: 'Whether to receive email notifications for album updates' })
albumUpdate!: boolean;
}
class DownloadResponse {
@ApiProperty({ type: 'integer', description: 'Maximum archive size in bytes' })
archiveSize!: number;
@ApiProperty({ description: 'Whether to include embedded videos in downloads' })
includeEmbeddedVideos: boolean = false;
}
class PurchaseResponse {
@ApiProperty({ description: 'Whether to show support badge' })
showSupportBadge!: boolean;
@ApiProperty({ description: 'Date until which to hide buy button' })
hideBuyButtonUntil!: string;
}
class CastResponse {
@ApiProperty({ description: 'Whether Google Cast is enabled' })
gCastEnabled: boolean = false;
}
export class UserPreferencesResponseDto implements UserPreferences {
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
albums!: AlbumsResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
folders!: FoldersResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
memories!: MemoriesResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
people!: PeopleResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
ratings!: RatingsResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
sharedLinks!: SharedLinksResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
tags!: TagsResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
emailNotifications!: EmailNotificationsResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
download!: DownloadResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
purchase!: PurchaseResponse;
// Description lives on schema to avoid duplication
@ApiProperty({ description: undefined })
cast!: CastResponse;
}
export const mapPreferences = (preferences: UserPreferences): UserPreferencesResponseDto => {
return preferences;
};