mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03: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": {
|
"/albums/statistics": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "getAlbumStatistics",
|
"operationId": "getAlbumStatistics",
|
||||||
|
|||||||
@@ -1790,6 +1790,20 @@ export function createAlbum({ createAlbumDto }: {
|
|||||||
body: 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) {
|
export function getAlbumStatistics(opts?: Oazapfts.RequestOpts) {
|
||||||
return oazapfts.ok(oazapfts.fetchJson<{
|
return oazapfts.ok(oazapfts.fetchJson<{
|
||||||
status: 200;
|
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', () => {
|
describe('GET /albums/:id', () => {
|
||||||
it('should be an authenticated route', async () => {
|
it('should be an authenticated route', async () => {
|
||||||
await request(ctx.getHttpServer()).get(`/albums/${factory.uuid()}`);
|
await request(ctx.getHttpServer()).get(`/albums/${factory.uuid()}`);
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ export class AlbumController {
|
|||||||
return this.service.getAll(auth, query);
|
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()
|
@Post()
|
||||||
@Authenticated({ permission: Permission.ALBUM_CREATE })
|
@Authenticated({ permission: Permission.ALBUM_CREATE })
|
||||||
createAlbum(@Auth() auth: AuthDto, @Body() dto: CreateAlbumDto): Promise<AlbumResponseDto> {
|
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();
|
await this.albumRepository.updateThumbnails();
|
||||||
|
|
||||||
let albums: MapAlbumDto[];
|
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:
|
// Get asset count for each album. Then map the result to an object:
|
||||||
// { [albumId]: assetCount }
|
// { [albumId]: assetCount }
|
||||||
const results = await this.albumRepository.getMetadataForIds(albums.map((album) => album.id));
|
|
||||||
const albumMetadata: Record<string, AlbumAssetCount> = {};
|
const albumMetadata: Record<string, AlbumAssetCount> = {};
|
||||||
for (const metadata of results) {
|
if (!slim) {
|
||||||
albumMetadata[metadata.albumId] = metadata;
|
const results = await this.albumRepository.getMetadataForIds(albums.map((album) => album.id));
|
||||||
|
for (const metadata of results) {
|
||||||
|
albumMetadata[metadata.albumId] = metadata;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return albums.map((album) => ({
|
return albums.map((album) => ({
|
||||||
...mapAlbumWithoutAssets(album),
|
...mapAlbumWithoutAssets(album),
|
||||||
sharedLinks: undefined,
|
sharedLinks: undefined,
|
||||||
startDate: albumMetadata[album.id]?.startDate ?? undefined,
|
...(!slim && {
|
||||||
endDate: albumMetadata[album.id]?.endDate ?? undefined,
|
startDate: albumMetadata[album.id]?.startDate ?? undefined,
|
||||||
assetCount: albumMetadata[album.id]?.assetCount ?? 0,
|
endDate: albumMetadata[album.id]?.endDate ?? undefined,
|
||||||
// lastModifiedAssetTimestamp is only used in mobile app, please remove if not need
|
assetCount: albumMetadata[album.id]?.assetCount ?? 0,
|
||||||
lastModifiedAssetTimestamp: albumMetadata[album.id]?.lastModifiedAssetTimestamp ?? undefined,
|
// 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 Icon from '$lib/components/elements/icon.svelte';
|
||||||
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
|
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
|
||||||
import { getAssetThumbnailUrl } from '$lib/utils';
|
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 { mdiClose } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
allAlbums = await getAllAlbums({});
|
allAlbums = await getAllAlbumsSlim({});
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSelect = (option?: ComboBoxOption) => {
|
const handleSelect = (option?: ComboBoxOption) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user