mirror of
https://github.com/immich-app/immich.git
synced 2026-06-04 13:15:22 -04:00
New getAllAlbumsSlim endpoint
- Add new endpoint - Add slim option to albumService.getAll (default false) - Use getAllAlbumsSlim in search-albums-section
This commit is contained in:
@@ -870,6 +870,60 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/albums/slim": {
|
||||
"get": {
|
||||
"operationId": "getAllAlbumsSlim",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "assetId",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Only returns albums that contain the asset\nIgnores the shared parameter\nundefined: get all albums",
|
||||
"schema": {
|
||||
"format": "uuid",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shared",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/AlbumResponseDto"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
},
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Albums"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/albums/statistics": {
|
||||
"get": {
|
||||
"operationId": "getAlbumStatistics",
|
||||
|
||||
@@ -1790,6 +1790,20 @@ export function createAlbum({ createAlbumDto }: {
|
||||
body: createAlbumDto
|
||||
})));
|
||||
}
|
||||
export function getAllAlbumsSlim({ assetId, shared }: {
|
||||
assetId?: string;
|
||||
shared?: boolean;
|
||||
}, opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchJson<{
|
||||
status: 200;
|
||||
data: AlbumResponseDto[];
|
||||
}>(`/albums/slim${QS.query(QS.explode({
|
||||
assetId,
|
||||
shared
|
||||
}))}`, {
|
||||
...opts
|
||||
}));
|
||||
}
|
||||
export function getAlbumStatistics(opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchJson<{
|
||||
status: 200;
|
||||
|
||||
@@ -37,6 +37,25 @@ describe(AlbumController.name, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /albums/slim', () => {
|
||||
it('should be an authenticated route', async () => {
|
||||
await request(ctx.getHttpServer()).post('/albums/slim');
|
||||
expect(ctx.authenticate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reject an invalid shared param', async () => {
|
||||
const { status, body } = await request(ctx.getHttpServer()).get('/albums/slim?shared=invalid');
|
||||
expect(status).toEqual(400);
|
||||
expect(body).toEqual(factory.responses.badRequest(['shared must be a boolean value']));
|
||||
});
|
||||
|
||||
it('should reject an invalid assetId param', async () => {
|
||||
const { status, body } = await request(ctx.getHttpServer()).get('/albums/slim?assetId=invalid');
|
||||
expect(status).toEqual(400);
|
||||
expect(body).toEqual(factory.responses.badRequest(['assetId must be a UUID']));
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /albums/:id', () => {
|
||||
it('should be an authenticated route', async () => {
|
||||
await request(ctx.getHttpServer()).get(`/albums/${factory.uuid()}`);
|
||||
|
||||
@@ -28,6 +28,13 @@ export class AlbumController {
|
||||
return this.service.getAll(auth, query);
|
||||
}
|
||||
|
||||
@Get('slim')
|
||||
@Authenticated({ permission: Permission.ALBUM_READ })
|
||||
getAllAlbumsSlim(@Auth() auth: AuthDto, @Query() query: GetAlbumsDto): Promise<AlbumResponseDto[]> {
|
||||
return this.service.getAll(auth, query, true);
|
||||
//asdf
|
||||
}
|
||||
|
||||
@Post()
|
||||
@Authenticated({ permission: Permission.ALBUM_CREATE })
|
||||
createAlbum(@Auth() auth: AuthDto, @Body() dto: CreateAlbumDto): Promise<AlbumResponseDto> {
|
||||
|
||||
@@ -37,7 +37,11 @@ export class AlbumService extends BaseService {
|
||||
};
|
||||
}
|
||||
|
||||
async getAll({ user: { id: ownerId } }: AuthDto, { assetId, shared }: GetAlbumsDto): Promise<AlbumResponseDto[]> {
|
||||
async getAll(
|
||||
{ user: { id: ownerId } }: AuthDto,
|
||||
{ assetId, shared }: GetAlbumsDto,
|
||||
slim: boolean = false,
|
||||
): Promise<AlbumResponseDto[]> {
|
||||
await this.albumRepository.updateThumbnails();
|
||||
|
||||
let albums: MapAlbumDto[];
|
||||
@@ -53,20 +57,24 @@ export class AlbumService extends BaseService {
|
||||
|
||||
// Get asset count for each album. Then map the result to an object:
|
||||
// { [albumId]: assetCount }
|
||||
const results = await this.albumRepository.getMetadataForIds(albums.map((album) => album.id));
|
||||
const albumMetadata: Record<string, AlbumAssetCount> = {};
|
||||
for (const metadata of results) {
|
||||
albumMetadata[metadata.albumId] = metadata;
|
||||
if (!slim) {
|
||||
const results = await this.albumRepository.getMetadataForIds(albums.map((album) => album.id));
|
||||
for (const metadata of results) {
|
||||
albumMetadata[metadata.albumId] = metadata;
|
||||
}
|
||||
}
|
||||
|
||||
return albums.map((album) => ({
|
||||
...mapAlbumWithoutAssets(album),
|
||||
sharedLinks: undefined,
|
||||
startDate: albumMetadata[album.id]?.startDate ?? undefined,
|
||||
endDate: albumMetadata[album.id]?.endDate ?? undefined,
|
||||
assetCount: albumMetadata[album.id]?.assetCount ?? 0,
|
||||
// lastModifiedAssetTimestamp is only used in mobile app, please remove if not need
|
||||
lastModifiedAssetTimestamp: albumMetadata[album.id]?.lastModifiedAssetTimestamp ?? undefined,
|
||||
...(!slim && {
|
||||
startDate: albumMetadata[album.id]?.startDate ?? undefined,
|
||||
endDate: albumMetadata[album.id]?.endDate ?? undefined,
|
||||
assetCount: albumMetadata[album.id]?.assetCount ?? 0,
|
||||
// lastModifiedAssetTimestamp is only used in mobile app, please remove if not need
|
||||
lastModifiedAssetTimestamp: albumMetadata[album.id]?.lastModifiedAssetTimestamp ?? undefined,
|
||||
}),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
|
||||
import { getAssetThumbnailUrl } from '$lib/utils';
|
||||
import { getAllAlbums, type AlbumResponseDto } from '@immich/sdk';
|
||||
import { getAllAlbumsSlim, type AlbumResponseDto } from '@immich/sdk';
|
||||
import { mdiClose } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -23,7 +23,7 @@
|
||||
);
|
||||
|
||||
onMount(async () => {
|
||||
allAlbums = await getAllAlbums({});
|
||||
allAlbums = await getAllAlbumsSlim({});
|
||||
});
|
||||
|
||||
const handleSelect = (option?: ComboBoxOption) => {
|
||||
|
||||
Reference in New Issue
Block a user