From 8e3a7caebd0ec23344af68f787d840277dae93aa Mon Sep 17 00:00:00 2001 From: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> Date: Thu, 6 Apr 2023 19:50:55 +0200 Subject: [PATCH] feat(server): improve validation of albums (#2188) * feat(server): improve validation of albums * regenerate openapi + fix downloadArchive for web --- mobile/openapi/doc/AlbumApi.md | Bin 22109 -> 22200 bytes mobile/openapi/doc/AssetApi.md | Bin 43548 -> 43639 bytes mobile/openapi/doc/CreateAlbumShareLinkDto.md | Bin 641 -> 658 bytes mobile/openapi/lib/api/album_api.dart | Bin 20865 -> 21051 bytes mobile/openapi/lib/api/asset_api.dart | Bin 45334 -> 45520 bytes .../model/create_album_share_link_dto.dart | Bin 7079 -> 7101 bytes mobile/openapi/test/album_api_test.dart | Bin 2501 -> 2514 bytes mobile/openapi/test/asset_api_test.dart | Bin 5155 -> 5168 bytes .../create_album_share_link_dto_test.dart | Bin 1114 -> 1116 bytes .../src/api-v1/album/album.controller.ts | 36 +++++++------- .../src/api-v1/album/dto/add-assets.dto.ts | 4 +- .../src/api-v1/album/dto/add-users.dto.ts | 4 +- .../src/api-v1/album/dto/album-id.dto.ts | 7 +-- .../album/dto/create-album-shared-link.dto.ts | 14 ++++-- .../src/api-v1/album/dto/create-album.dto.ts | 10 ++-- .../src/api-v1/album/dto/remove-assets.dto.ts | 4 +- .../src/api-v1/album/dto/update-album.dto.ts | 5 +- .../api-v1/asset/dto/download-library.dto.ts | 2 +- .../src/decorators/validate-uuid.decorator.ts | 17 +++++++ server/immich-openapi-specs.json | 40 ++++++++++++---- .../domain/src/album/dto/get-albums.dto.ts | 7 ++- web/src/api/open-api/api.ts | 44 ++++++++++++------ .../components/album-page/album-viewer.svelte | 1 + 23 files changed, 129 insertions(+), 66 deletions(-) create mode 100644 server/apps/immich/src/decorators/validate-uuid.decorator.ts diff --git a/mobile/openapi/doc/AlbumApi.md b/mobile/openapi/doc/AlbumApi.md index 72cb3392ed080fae7e6d9f9387f868e6ac5d9fe6..d71f4e297a5dd857dc50c5bacd64f2da6bcb86e4 100644 GIT binary patch delta 67 zcmcb+hH=MQ#tomVGtw|6Sd$jl%!K}%J MTnd|yYfsYx0FGN3nE(I) delta 33 pcmdn7mhtWy#tomfsX7XqZLCb0xj}3NTLlm`Ie)S2)es$; delta 40 wcmex?+G diff --git a/mobile/openapi/lib/api/album_api.dart b/mobile/openapi/lib/api/album_api.dart index 8f42545b8bd803821811a990b912aff99a0b9a73..8f7fe5ab37f55f4c0a6fdc8c7d04a679c4a024c3 100644 GIT binary patch delta 140 zcmZo%%(#0AhQ{x61UpF delta 44 ycmdnJgt2ikL2vs@} WIZ~6IH7Ao01{agqIUTbBI?s0>au=Ea diff --git a/mobile/openapi/lib/model/create_album_share_link_dto.dart b/mobile/openapi/lib/model/create_album_share_link_dto.dart index 46b3812a9465038198f4f30ca0af6f6058fa4474..43aadbe0561de3a5d98784657e6a2cfc967258c4 100644 GIT binary patch delta 98 zcmZ2(zSn%i6lM;W#FEsI%-qz?vzWEHq!sl_@=XK}uTnSo(&Nl|8Ax`yWD vhkWvrSMu_0{>019CI{1|kyV_Zr=w7$o?20mS(IArSfZ|@puSm7q>~*0fCeDG delta 47 zcmdmMzTAAn6lS*IlA_GK^v!dawYet$qd`WmiD(mF6Z0xLgiMgpdn^Ra5SpZ*w2Y3Jg delta 12 Tcmca4d{lTtD(mJV)&v#+A&mrP diff --git a/mobile/openapi/test/asset_api_test.dart b/mobile/openapi/test/asset_api_test.dart index cf428cb1862b6d58a9e15bab90cb0c829b32cbd9..3430b2e0399c0ba5ce85e1020a0ccece962913fb 100644 GIT binary patch delta 43 zcmZ3iu|Z?QS9Y=BlA_GKbcMXc+*BQfywY5S;_S=u~=inSN6?J9C|zeA}$0+ diff --git a/mobile/openapi/test/create_album_share_link_dto_test.dart b/mobile/openapi/test/create_album_share_link_dto_test.dart index 7b44683c5b55fd1fafcb5596723e5933a9601ad9..c9dfc63762f5b6e600fbb3ceede114cfd5e8547c 100644 GIT binary patch delta 35 qcmcb`aff4r50j8fVo7R9W^SrNYDGb2QEIVc$z(ld#m%)$cNqccR}8KI delta 30 mcmcb^af@Sv57Xp#%ZlMR>^H`g=WWds1TC<_Mw diff --git a/server/apps/immich/src/api-v1/album/album.controller.ts b/server/apps/immich/src/api-v1/album/album.controller.ts index d204f44af..fff93f140 100644 --- a/server/apps/immich/src/api-v1/album/album.controller.ts +++ b/server/apps/immich/src/api-v1/album/album.controller.ts @@ -1,16 +1,4 @@ -import { - Controller, - Get, - Post, - Body, - Patch, - Param, - Delete, - ValidationPipe, - Put, - Query, - Response, -} from '@nestjs/common'; +import { Controller, Get, Post, Body, Patch, Param, Delete, Put, Query, Response } from '@nestjs/common'; import { ParseMeUUIDPipe } from '../validation/parse-me-uuid-pipe'; import { AlbumService } from './album.service'; import { CreateAlbumDto } from './dto/create-album.dto'; @@ -33,9 +21,11 @@ import { import { DownloadDto } from '../asset/dto/download-library.dto'; import { CreateAlbumShareLinkDto as CreateAlbumSharedLinkDto } from './dto/create-album-shared-link.dto'; import { AlbumIdDto } from './dto/album-id.dto'; +import { UseValidation } from '../../decorators/use-validation.decorator'; @ApiTags('Album') @Controller('album') +@UseValidation() export class AlbumController { constructor(private readonly albumService: AlbumService) {} @@ -47,7 +37,8 @@ export class AlbumController { @Authenticated() @Post() - async createAlbum(@GetAuthUser() authUser: AuthUserDto, @Body(ValidationPipe) createAlbumDto: CreateAlbumDto) { + async createAlbum(@GetAuthUser() authUser: AuthUserDto, @Body() createAlbumDto: CreateAlbumDto) { + // TODO: Handle nonexistent sharedWithUserIds and assetIds. return this.albumService.create(authUser, createAlbumDto); } @@ -55,9 +46,10 @@ export class AlbumController { @Put('/:albumId/users') async addUsersToAlbum( @GetAuthUser() authUser: AuthUserDto, - @Body(ValidationPipe) addUsersDto: AddUsersDto, + @Body() addUsersDto: AddUsersDto, @Param() { albumId }: AlbumIdDto, ) { + // TODO: Handle nonexistent sharedUserIds. return this.albumService.addUsersToAlbum(authUser, addUsersDto, albumId); } @@ -65,9 +57,11 @@ export class AlbumController { @Put('/:albumId/assets') async addAssetsToAlbum( @GetAuthUser() authUser: AuthUserDto, - @Body(ValidationPipe) addAssetsDto: AddAssetsDto, + @Body() addAssetsDto: AddAssetsDto, @Param() { albumId }: AlbumIdDto, ): Promise { + // TODO: Handle nonexistent assetIds. + // TODO: Disallow adding assets of another user to an album. return this.albumService.addAssetsToAlbum(authUser, addAssetsDto, albumId); } @@ -81,7 +75,7 @@ export class AlbumController { @Delete('/:albumId/assets') async removeAssetFromAlbum( @GetAuthUser() authUser: AuthUserDto, - @Body(ValidationPipe) removeAssetsDto: RemoveAssetsDto, + @Body() removeAssetsDto: RemoveAssetsDto, @Param() { albumId }: AlbumIdDto, ): Promise { return this.albumService.removeAssetsFromAlbum(authUser, removeAssetsDto, albumId); @@ -107,9 +101,11 @@ export class AlbumController { @Patch('/:albumId') async updateAlbumInfo( @GetAuthUser() authUser: AuthUserDto, - @Body(ValidationPipe) updateAlbumInfoDto: UpdateAlbumDto, + @Body() updateAlbumInfoDto: UpdateAlbumDto, @Param() { albumId }: AlbumIdDto, ) { + // TODO: Handle nonexistent albumThumbnailAssetId. + // TODO: Disallow setting asset from other user as albumThumbnailAssetId. return this.albumService.updateAlbumInfo(authUser, updateAlbumInfoDto, albumId); } @@ -119,7 +115,7 @@ export class AlbumController { async downloadArchive( @GetAuthUser() authUser: AuthUserDto, @Param() { albumId }: AlbumIdDto, - @Query(new ValidationPipe({ transform: true })) dto: DownloadDto, + @Query() dto: DownloadDto, @Response({ passthrough: true }) res: Res, ) { this.albumService.checkDownloadAccess(authUser); @@ -140,7 +136,7 @@ export class AlbumController { @Post('/create-shared-link') async createAlbumSharedLink( @GetAuthUser() authUser: AuthUserDto, - @Body(ValidationPipe) createAlbumShareLinkDto: CreateAlbumSharedLinkDto, + @Body() createAlbumShareLinkDto: CreateAlbumSharedLinkDto, ) { return this.albumService.createAlbumSharedLink(authUser, createAlbumShareLinkDto); } diff --git a/server/apps/immich/src/api-v1/album/dto/add-assets.dto.ts b/server/apps/immich/src/api-v1/album/dto/add-assets.dto.ts index 18b29f7c8..bf0d53135 100644 --- a/server/apps/immich/src/api-v1/album/dto/add-assets.dto.ts +++ b/server/apps/immich/src/api-v1/album/dto/add-assets.dto.ts @@ -1,6 +1,6 @@ -import { IsNotEmpty } from 'class-validator'; +import { ValidateUUID } from 'apps/immich/src/decorators/validate-uuid.decorator'; export class AddAssetsDto { - @IsNotEmpty() + @ValidateUUID({ each: true }) assetIds!: string[]; } diff --git a/server/apps/immich/src/api-v1/album/dto/add-users.dto.ts b/server/apps/immich/src/api-v1/album/dto/add-users.dto.ts index 6a386053a..c4f3c677f 100644 --- a/server/apps/immich/src/api-v1/album/dto/add-users.dto.ts +++ b/server/apps/immich/src/api-v1/album/dto/add-users.dto.ts @@ -1,6 +1,6 @@ -import { IsNotEmpty } from 'class-validator'; +import { ValidateUUID } from 'apps/immich/src/decorators/validate-uuid.decorator'; export class AddUsersDto { - @IsNotEmpty() + @ValidateUUID({ each: true }) sharedUserIds!: string[]; } diff --git a/server/apps/immich/src/api-v1/album/dto/album-id.dto.ts b/server/apps/immich/src/api-v1/album/dto/album-id.dto.ts index c9bf09e32..5dbdf06c2 100644 --- a/server/apps/immich/src/api-v1/album/dto/album-id.dto.ts +++ b/server/apps/immich/src/api-v1/album/dto/album-id.dto.ts @@ -1,9 +1,6 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsUUID } from 'class-validator'; +import { ValidateUUID } from 'apps/immich/src/decorators/validate-uuid.decorator'; export class AlbumIdDto { - @IsNotEmpty() - @IsUUID('4') - @ApiProperty({ format: 'uuid' }) + @ValidateUUID() albumId!: string; } diff --git a/server/apps/immich/src/api-v1/album/dto/create-album-shared-link.dto.ts b/server/apps/immich/src/api-v1/album/dto/create-album-shared-link.dto.ts index e113b9d49..a35e52748 100644 --- a/server/apps/immich/src/api-v1/album/dto/create-album-shared-link.dto.ts +++ b/server/apps/immich/src/api-v1/album/dto/create-album-shared-link.dto.ts @@ -1,27 +1,33 @@ -import { IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { ValidateUUID } from 'apps/immich/src/decorators/validate-uuid.decorator'; +import { IsBoolean, IsISO8601, IsOptional, IsString } from 'class-validator'; export class CreateAlbumShareLinkDto { - @IsString() - @IsNotEmpty() + @ValidateUUID() albumId!: string; - @IsString() + @IsISO8601() @IsOptional() + @ApiProperty({ format: 'date-time' }) expiresAt?: string; @IsBoolean() @IsOptional() + @ApiProperty() allowUpload?: boolean; @IsBoolean() @IsOptional() + @ApiProperty() allowDownload?: boolean; @IsBoolean() @IsOptional() + @ApiProperty() showExif?: boolean; @IsString() @IsOptional() + @ApiProperty() description?: string; } diff --git a/server/apps/immich/src/api-v1/album/dto/create-album.dto.ts b/server/apps/immich/src/api-v1/album/dto/create-album.dto.ts index f6b1e9476..9857c26a3 100644 --- a/server/apps/immich/src/api-v1/album/dto/create-album.dto.ts +++ b/server/apps/immich/src/api-v1/album/dto/create-album.dto.ts @@ -1,12 +1,16 @@ -import { IsNotEmpty, IsOptional } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { ValidateUUID } from 'apps/immich/src/decorators/validate-uuid.decorator'; +import { IsNotEmpty, IsString } from 'class-validator'; export class CreateAlbumDto { @IsNotEmpty() + @IsString() + @ApiProperty() albumName!: string; - @IsOptional() + @ValidateUUID({ optional: true, each: true }) sharedWithUserIds?: string[]; - @IsOptional() + @ValidateUUID({ optional: true, each: true }) assetIds?: string[]; } diff --git a/server/apps/immich/src/api-v1/album/dto/remove-assets.dto.ts b/server/apps/immich/src/api-v1/album/dto/remove-assets.dto.ts index 73f2994d9..d1b2651ec 100644 --- a/server/apps/immich/src/api-v1/album/dto/remove-assets.dto.ts +++ b/server/apps/immich/src/api-v1/album/dto/remove-assets.dto.ts @@ -1,6 +1,6 @@ -import { IsNotEmpty } from 'class-validator'; +import { ValidateUUID } from 'apps/immich/src/decorators/validate-uuid.decorator'; export class RemoveAssetsDto { - @IsNotEmpty() + @ValidateUUID({ each: true }) assetIds!: string[]; } diff --git a/server/apps/immich/src/api-v1/album/dto/update-album.dto.ts b/server/apps/immich/src/api-v1/album/dto/update-album.dto.ts index 44b0764d5..50853cd5a 100644 --- a/server/apps/immich/src/api-v1/album/dto/update-album.dto.ts +++ b/server/apps/immich/src/api-v1/album/dto/update-album.dto.ts @@ -1,9 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { ValidateUUID } from 'apps/immich/src/decorators/validate-uuid.decorator'; import { IsOptional } from 'class-validator'; export class UpdateAlbumDto { @IsOptional() + @ApiProperty() albumName?: string; - @IsOptional() + @ValidateUUID({ optional: true }) albumThumbnailAssetId?: string; } diff --git a/server/apps/immich/src/api-v1/asset/dto/download-library.dto.ts b/server/apps/immich/src/api-v1/asset/dto/download-library.dto.ts index fdfeca1be..7e1dfd12d 100644 --- a/server/apps/immich/src/api-v1/asset/dto/download-library.dto.ts +++ b/server/apps/immich/src/api-v1/asset/dto/download-library.dto.ts @@ -4,7 +4,7 @@ import { IsNumber, IsOptional, IsPositive, IsString } from 'class-validator'; export class DownloadDto { @IsOptional() @IsString() - name = ''; + name?: string; @IsOptional() @IsPositive() diff --git a/server/apps/immich/src/decorators/validate-uuid.decorator.ts b/server/apps/immich/src/decorators/validate-uuid.decorator.ts new file mode 100644 index 000000000..16a2e1ad0 --- /dev/null +++ b/server/apps/immich/src/decorators/validate-uuid.decorator.ts @@ -0,0 +1,17 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiProperty } from '@nestjs/swagger'; +import { IsArray, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator'; + +export type Options = { + optional?: boolean; + each?: boolean; +}; + +export function ValidateUUID({ optional, each }: Options = { optional: false, each: false }) { + return applyDecorators( + IsUUID('4', { each }), + ApiProperty({ format: 'uuid' }), + optional ? IsOptional() : IsNotEmpty(), + each ? IsArray() : IsString(), + ); +} diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index 8111eae2b..7318739e2 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -1895,6 +1895,14 @@ "operationId": "downloadLibrary", "description": "Current this is not used in any UI element", "parameters": [ + { + "name": "name", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "skip", "required": false, @@ -3343,6 +3351,14 @@ "type": "string" } }, + { + "name": "name", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "skip", "required": false, @@ -5359,7 +5375,8 @@ "assetIds": { "type": "array", "items": { - "type": "string" + "type": "string", + "format": "uuid" } } }, @@ -5373,7 +5390,8 @@ "assetIds": { "type": "array", "items": { - "type": "string" + "type": "string", + "format": "uuid" } } }, @@ -5435,13 +5453,15 @@ "sharedWithUserIds": { "type": "array", "items": { - "type": "string" + "type": "string", + "format": "uuid" } }, "assetIds": { "type": "array", "items": { - "type": "string" + "type": "string", + "format": "uuid" } } }, @@ -5455,7 +5475,8 @@ "sharedUserIds": { "type": "array", "items": { - "type": "string" + "type": "string", + "format": "uuid" } } }, @@ -5491,7 +5512,8 @@ "type": "string" }, "albumThumbnailAssetId": { - "type": "string" + "type": "string", + "format": "uuid" } } }, @@ -5499,10 +5521,12 @@ "type": "object", "properties": { "albumId": { - "type": "string" + "type": "string", + "format": "uuid" }, "expiresAt": { - "type": "string" + "type": "string", + "format": "date-time" }, "allowUpload": { "type": "boolean" diff --git a/server/libs/domain/src/album/dto/get-albums.dto.ts b/server/libs/domain/src/album/dto/get-albums.dto.ts index afcde1f12..ea62ffc20 100644 --- a/server/libs/domain/src/album/dto/get-albums.dto.ts +++ b/server/libs/domain/src/album/dto/get-albums.dto.ts @@ -1,7 +1,8 @@ import { Transform } from 'class-transformer'; -import { IsBoolean, IsOptional, IsUUID } from 'class-validator'; +import { IsBoolean, IsOptional } from 'class-validator'; import { toBoolean } from 'apps/immich/src/utils/transform.util'; import { ApiProperty } from '@nestjs/swagger'; +import { ValidateUUID } from 'apps/immich/src/decorators/validate-uuid.decorator'; export class GetAlbumsDto { @IsOptional() @@ -20,8 +21,6 @@ export class GetAlbumsDto { * Ignores the shared parameter * undefined: get all albums */ - @IsOptional() - @IsUUID(4) - @ApiProperty({ format: 'uuid' }) + @ValidateUUID({ optional: true }) assetId?: string; } diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index bbfc64f7e..0ec6fc438 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -3160,12 +3160,13 @@ export const AlbumApiAxiosParamCreator = function (configuration?: Configuration /** * * @param {string} albumId + * @param {string} [name] * @param {number} [skip] * @param {string} [key] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - downloadArchive: async (albumId: string, skip?: number, key?: string, options: AxiosRequestConfig = {}): Promise => { + downloadArchive: async (albumId: string, name?: string, skip?: number, key?: string, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'albumId' is not null or undefined assertParamExists('downloadArchive', 'albumId', albumId) const localVarPath = `/album/{albumId}/download` @@ -3187,6 +3188,10 @@ export const AlbumApiAxiosParamCreator = function (configuration?: Configuration // authentication cookie required + if (name !== undefined) { + localVarQueryParameter['name'] = name; + } + if (skip !== undefined) { localVarQueryParameter['skip'] = skip; } @@ -3529,13 +3534,14 @@ export const AlbumApiFp = function(configuration?: Configuration) { /** * * @param {string} albumId + * @param {string} [name] * @param {number} [skip] * @param {string} [key] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async downloadArchive(albumId: string, skip?: number, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.downloadArchive(albumId, skip, key, options); + async downloadArchive(albumId: string, name?: string, skip?: number, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.downloadArchive(albumId, name, skip, key, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -3663,13 +3669,14 @@ export const AlbumApiFactory = function (configuration?: Configuration, basePath /** * * @param {string} albumId + * @param {string} [name] * @param {number} [skip] * @param {string} [key] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - downloadArchive(albumId: string, skip?: number, key?: string, options?: any): AxiosPromise { - return localVarFp.downloadArchive(albumId, skip, key, options).then((request) => request(axios, basePath)); + downloadArchive(albumId: string, name?: string, skip?: number, key?: string, options?: any): AxiosPromise { + return localVarFp.downloadArchive(albumId, name, skip, key, options).then((request) => request(axios, basePath)); }, /** * @@ -3800,14 +3807,15 @@ export class AlbumApi extends BaseAPI { /** * * @param {string} albumId + * @param {string} [name] * @param {number} [skip] * @param {string} [key] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AlbumApi */ - public downloadArchive(albumId: string, skip?: number, key?: string, options?: AxiosRequestConfig) { - return AlbumApiFp(this.configuration).downloadArchive(albumId, skip, key, options).then((request) => request(this.axios, this.basePath)); + public downloadArchive(albumId: string, name?: string, skip?: number, key?: string, options?: AxiosRequestConfig) { + return AlbumApiFp(this.configuration).downloadArchive(albumId, name, skip, key, options).then((request) => request(this.axios, this.basePath)); } /** @@ -4195,12 +4203,13 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration }, /** * Current this is not used in any UI element + * @param {string} [name] * @param {number} [skip] * @param {string} [key] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - downloadLibrary: async (skip?: number, key?: string, options: AxiosRequestConfig = {}): Promise => { + downloadLibrary: async (name?: string, skip?: number, key?: string, options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/asset/download-library`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -4219,6 +4228,10 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration // authentication cookie required + if (name !== undefined) { + localVarQueryParameter['name'] = name; + } + if (skip !== undefined) { localVarQueryParameter['skip'] = skip; } @@ -5029,13 +5042,14 @@ export const AssetApiFp = function(configuration?: Configuration) { }, /** * Current this is not used in any UI element + * @param {string} [name] * @param {number} [skip] * @param {string} [key] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async downloadLibrary(skip?: number, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.downloadLibrary(skip, key, options); + async downloadLibrary(name?: string, skip?: number, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.downloadLibrary(name, skip, key, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -5284,13 +5298,14 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath }, /** * Current this is not used in any UI element + * @param {string} [name] * @param {number} [skip] * @param {string} [key] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - downloadLibrary(skip?: number, key?: string, options?: any): AxiosPromise { - return localVarFp.downloadLibrary(skip, key, options).then((request) => request(axios, basePath)); + downloadLibrary(name?: string, skip?: number, key?: string, options?: any): AxiosPromise { + return localVarFp.downloadLibrary(name, skip, key, options).then((request) => request(axios, basePath)); }, /** * Get all AssetEntity belong to the user @@ -5537,14 +5552,15 @@ export class AssetApi extends BaseAPI { /** * Current this is not used in any UI element + * @param {string} [name] * @param {number} [skip] * @param {string} [key] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AssetApi */ - public downloadLibrary(skip?: number, key?: string, options?: AxiosRequestConfig) { - return AssetApiFp(this.configuration).downloadLibrary(skip, key, options).then((request) => request(this.axios, this.basePath)); + public downloadLibrary(name?: string, skip?: number, key?: string, options?: AxiosRequestConfig) { + return AssetApiFp(this.configuration).downloadLibrary(name, skip, key, options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index 4ce42a432..e7c4f42a5 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -264,6 +264,7 @@ const { data, status, headers } = await api.albumApi.downloadArchive( album.id, + undefined, skip || undefined, sharedLink?.key, {