Files
immich/server/src/controllers/album.controller.ts

194 lines
6.9 KiB
TypeScript
Raw Normal View History

import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, Put, Query } from '@nestjs/common';
2025-11-13 08:18:43 -05:00
import { ApiTags } from '@nestjs/swagger';
import { Endpoint, HistoryBuilder } from 'src/decorators';
import {
AddUsersDto,
AlbumInfoDto,
AlbumResponseDto,
AlbumsAddAssetsDto,
AlbumsAddAssetsResponseDto,
AlbumStatisticsResponseDto,
CreateAlbumDto,
GetAlbumsDto,
UpdateAlbumDto,
feat: readonly album sharing (#8720) * rename albums_shared_users_users to album_permissions and add readonly column * disable synchronize on the original join table * remove unnecessary FK names * set readonly=true as default for new album shares * separate and implement album READ and WRITE permission * expose albumPermissions on the API, deprecate sharedUsers * generate openapi * create readonly view on frontend * ??? move slideshow button out from ellipsis menu so that non-owners can have access too * correct sharedUsers joins * add album permission repository * remove a log * fix assetCount getting reset when adding users * fix lint * add set permission endpoint and UI * sort users * remove log * Revert "??? move slideshow button out from ellipsis menu so that non-owners can have access too" This reverts commit 1343bfa31125f7136f81db28f7aa4c5ef0204847. * rename stuff * fix db schema annotations * sql generate * change readonly default to follow migration * fix deprecation notice * change readonly boolean to role enum * fix joincolumn as primary key * rename albumUserRepository in album service * clean up userId and albumId * add write access to shared link * fix existing tests * switch to vitest * format and fix tests on web * add new test * fix one e2e test * rename new API field to albumUsers * capitalize serverside enum * remove unused ReadWrite type * missed rename from previous commit * rename to albumUsers in album entity as well * remove outdated Equals calls * unnecessary relation * rename to updateUser in album service * minor renamery * move sorting to backend * rename and separate ALBUM_WRITE as ADD_ASSET and REMOVE_ASSET * fix tests * fix "should migrate single moving picture" test failing on European system timezone * generated changes after merge * lint fix * fix correct page to open after removing user from album * fix e2e tests and some bugs * rename updateAlbumUser rest endpoint * add new e2e tests for updateAlbumUser endpoint * small optimizations * refactor album e2e test, add new album shared with viewer * add new test to check if viewer can see the album * add new e2e tests for readonly share * failing test: User delete doesn't cascade to UserAlbum entity * fix: handle deleted users * use lodash for sort * add role to addUsersToAlbum endpoint * add UI for adding editors * lint fixes * change role back to editor as DB default * fix server tests * redesign user selection modal editor selector * style tweaks * fix type error * Revert "style tweaks" This reverts commit ab604f4c8f3a6f12ab0b5fe2dd2ede723aa68775. * Revert "redesign user selection modal editor selector" This reverts commit e6f344856c6c05e4eb5c78f0dffb9f52498795f4. * chore: cleanup and improve add user modal * chore: open api * small styling --------- Co-authored-by: mgabor <> Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-04-25 06:19:49 +02:00
UpdateAlbumUserDto,
} from 'src/dtos/album.dto';
import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
import { AuthDto } from 'src/dtos/auth.dto';
2025-11-11 17:01:14 -05:00
import { ApiTag, Permission } from 'src/enum';
import { Auth, Authenticated } from 'src/middleware/auth.guard';
import { AlbumService } from 'src/services/album.service';
import { ParseMeUUIDPipe, UUIDParamDto } from 'src/validation';
2025-11-11 17:01:14 -05:00
@ApiTags(ApiTag.Albums)
@Controller('albums')
export class AlbumController {
constructor(private service: AlbumService) {}
@Get()
2025-07-15 14:50:13 -04:00
@Authenticated({ permission: Permission.AlbumRead })
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'List all albums',
description: 'Retrieve a list of albums available to the authenticated user.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
getAllAlbums(@Auth() auth: AuthDto, @Query() query: GetAlbumsDto): Promise<AlbumResponseDto[]> {
return this.service.getAll(auth, query);
2023-05-24 22:10:45 -04:00
}
@Post()
2025-07-15 14:50:13 -04:00
@Authenticated({ permission: Permission.AlbumCreate })
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Create an album',
description: 'Create a new album. The album can also be created with initial users and assets.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
createAlbum(@Auth() auth: AuthDto, @Body() dto: CreateAlbumDto): Promise<AlbumResponseDto> {
return this.service.create(auth, dto);
}
@Get('statistics')
2025-07-15 14:50:13 -04:00
@Authenticated({ permission: Permission.AlbumStatistics })
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Retrieve album statistics',
description: 'Returns statistics about the albums available to the authenticated user.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
getAlbumStatistics(@Auth() auth: AuthDto): Promise<AlbumStatisticsResponseDto> {
return this.service.getStatistics(auth);
}
2025-07-15 14:50:13 -04:00
@Authenticated({ permission: Permission.AlbumRead, sharedLink: true })
@Get(':id')
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Retrieve an album',
description: 'Retrieve information about a specific album by its ID.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
getAlbumInfo(
@Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto,
@Query() dto: AlbumInfoDto,
): Promise<AlbumResponseDto> {
return this.service.get(auth, id, dto);
}
@Patch(':id')
2025-07-15 14:50:13 -04:00
@Authenticated({ permission: Permission.AlbumUpdate })
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Update an album',
description:
'Update the information of a specific album by its ID. This endpoint can be used to update the album name, description, sort order, etc. However, it is not used to add or remove assets or users from the album.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
updateAlbumInfo(
@Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto,
@Body() dto: UpdateAlbumDto,
): Promise<AlbumResponseDto> {
return this.service.update(auth, id, dto);
}
2023-05-26 09:04:09 -04:00
@Delete(':id')
2025-07-15 14:50:13 -04:00
@Authenticated({ permission: Permission.AlbumDelete })
@HttpCode(HttpStatus.NO_CONTENT)
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Delete an album',
description:
'Delete a specific album by its ID. Note the album is initially trashed and then immediately scheduled for deletion, but relies on a background job to complete the process.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
deleteAlbum(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto) {
return this.service.delete(auth, id);
2023-05-26 09:04:09 -04:00
}
@Put(':id/assets')
@Authenticated({ permission: Permission.AlbumAssetCreate, sharedLink: true })
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Add assets to an album',
description: 'Add multiple assets to a specific album by its ID.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
addAssetsToAlbum(
@Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto,
@Body() dto: BulkIdsDto,
): Promise<BulkIdResponseDto[]> {
return this.service.addAssets(auth, id, dto);
}
@Put('assets')
@Authenticated({ permission: Permission.AlbumAssetCreate, sharedLink: true })
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Add assets to albums',
description: 'Send a list of asset IDs and album IDs to add each asset to each album.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
addAssetsToAlbums(@Auth() auth: AuthDto, @Body() dto: AlbumsAddAssetsDto): Promise<AlbumsAddAssetsResponseDto> {
return this.service.addAssetsToAlbums(auth, dto);
}
@Delete(':id/assets')
@Authenticated({ permission: Permission.AlbumAssetDelete })
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Remove assets from an album',
description: 'Remove multiple assets from a specific album by its ID.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
removeAssetFromAlbum(
@Auth() auth: AuthDto,
@Body() dto: BulkIdsDto,
@Param() { id }: UUIDParamDto,
): Promise<BulkIdResponseDto[]> {
return this.service.removeAssets(auth, id, dto);
}
@Put(':id/users')
@Authenticated({ permission: Permission.AlbumUserCreate })
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Share album with users',
description: 'Share an album with multiple users. Each user can be given a specific role in the album.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
addUsersToAlbum(
@Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto,
@Body() dto: AddUsersDto,
): Promise<AlbumResponseDto> {
return this.service.addUsers(auth, id, dto);
}
feat: readonly album sharing (#8720) * rename albums_shared_users_users to album_permissions and add readonly column * disable synchronize on the original join table * remove unnecessary FK names * set readonly=true as default for new album shares * separate and implement album READ and WRITE permission * expose albumPermissions on the API, deprecate sharedUsers * generate openapi * create readonly view on frontend * ??? move slideshow button out from ellipsis menu so that non-owners can have access too * correct sharedUsers joins * add album permission repository * remove a log * fix assetCount getting reset when adding users * fix lint * add set permission endpoint and UI * sort users * remove log * Revert "??? move slideshow button out from ellipsis menu so that non-owners can have access too" This reverts commit 1343bfa31125f7136f81db28f7aa4c5ef0204847. * rename stuff * fix db schema annotations * sql generate * change readonly default to follow migration * fix deprecation notice * change readonly boolean to role enum * fix joincolumn as primary key * rename albumUserRepository in album service * clean up userId and albumId * add write access to shared link * fix existing tests * switch to vitest * format and fix tests on web * add new test * fix one e2e test * rename new API field to albumUsers * capitalize serverside enum * remove unused ReadWrite type * missed rename from previous commit * rename to albumUsers in album entity as well * remove outdated Equals calls * unnecessary relation * rename to updateUser in album service * minor renamery * move sorting to backend * rename and separate ALBUM_WRITE as ADD_ASSET and REMOVE_ASSET * fix tests * fix "should migrate single moving picture" test failing on European system timezone * generated changes after merge * lint fix * fix correct page to open after removing user from album * fix e2e tests and some bugs * rename updateAlbumUser rest endpoint * add new e2e tests for updateAlbumUser endpoint * small optimizations * refactor album e2e test, add new album shared with viewer * add new test to check if viewer can see the album * add new e2e tests for readonly share * failing test: User delete doesn't cascade to UserAlbum entity * fix: handle deleted users * use lodash for sort * add role to addUsersToAlbum endpoint * add UI for adding editors * lint fixes * change role back to editor as DB default * fix server tests * redesign user selection modal editor selector * style tweaks * fix type error * Revert "style tweaks" This reverts commit ab604f4c8f3a6f12ab0b5fe2dd2ede723aa68775. * Revert "redesign user selection modal editor selector" This reverts commit e6f344856c6c05e4eb5c78f0dffb9f52498795f4. * chore: cleanup and improve add user modal * chore: open api * small styling --------- Co-authored-by: mgabor <> Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-04-25 06:19:49 +02:00
@Put(':id/user/:userId')
@Authenticated({ permission: Permission.AlbumUserUpdate })
@HttpCode(HttpStatus.NO_CONTENT)
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Update user role',
description: 'Change the role for a specific user in a specific album.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
feat: readonly album sharing (#8720) * rename albums_shared_users_users to album_permissions and add readonly column * disable synchronize on the original join table * remove unnecessary FK names * set readonly=true as default for new album shares * separate and implement album READ and WRITE permission * expose albumPermissions on the API, deprecate sharedUsers * generate openapi * create readonly view on frontend * ??? move slideshow button out from ellipsis menu so that non-owners can have access too * correct sharedUsers joins * add album permission repository * remove a log * fix assetCount getting reset when adding users * fix lint * add set permission endpoint and UI * sort users * remove log * Revert "??? move slideshow button out from ellipsis menu so that non-owners can have access too" This reverts commit 1343bfa31125f7136f81db28f7aa4c5ef0204847. * rename stuff * fix db schema annotations * sql generate * change readonly default to follow migration * fix deprecation notice * change readonly boolean to role enum * fix joincolumn as primary key * rename albumUserRepository in album service * clean up userId and albumId * add write access to shared link * fix existing tests * switch to vitest * format and fix tests on web * add new test * fix one e2e test * rename new API field to albumUsers * capitalize serverside enum * remove unused ReadWrite type * missed rename from previous commit * rename to albumUsers in album entity as well * remove outdated Equals calls * unnecessary relation * rename to updateUser in album service * minor renamery * move sorting to backend * rename and separate ALBUM_WRITE as ADD_ASSET and REMOVE_ASSET * fix tests * fix "should migrate single moving picture" test failing on European system timezone * generated changes after merge * lint fix * fix correct page to open after removing user from album * fix e2e tests and some bugs * rename updateAlbumUser rest endpoint * add new e2e tests for updateAlbumUser endpoint * small optimizations * refactor album e2e test, add new album shared with viewer * add new test to check if viewer can see the album * add new e2e tests for readonly share * failing test: User delete doesn't cascade to UserAlbum entity * fix: handle deleted users * use lodash for sort * add role to addUsersToAlbum endpoint * add UI for adding editors * lint fixes * change role back to editor as DB default * fix server tests * redesign user selection modal editor selector * style tweaks * fix type error * Revert "style tweaks" This reverts commit ab604f4c8f3a6f12ab0b5fe2dd2ede723aa68775. * Revert "redesign user selection modal editor selector" This reverts commit e6f344856c6c05e4eb5c78f0dffb9f52498795f4. * chore: cleanup and improve add user modal * chore: open api * small styling --------- Co-authored-by: mgabor <> Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-04-25 06:19:49 +02:00
updateAlbumUser(
@Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto,
@Param('userId', new ParseMeUUIDPipe({ version: '4' })) userId: string,
@Body() dto: UpdateAlbumUserDto,
): Promise<void> {
return this.service.updateUser(auth, id, userId, dto);
}
@Delete(':id/user/:userId')
@Authenticated({ permission: Permission.AlbumUserDelete })
@HttpCode(HttpStatus.NO_CONTENT)
2025-11-13 08:18:43 -05:00
@Endpoint({
2025-11-11 17:01:14 -05:00
summary: 'Remove user from album',
description: 'Remove a user from an album. Use an ID of "me" to leave a shared album.',
2025-11-13 08:18:43 -05:00
history: new HistoryBuilder().added('v1').beta('v1').stable('v2'),
2025-11-11 17:01:14 -05:00
})
removeUserFromAlbum(
@Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto,
@Param('userId', new ParseMeUUIDPipe({ version: '4' })) userId: string,
): Promise<void> {
return this.service.removeUser(auth, id, userId);
}
}