1
0
mirror of https://github.com/immich-app/immich.git synced 2024-11-24 08:52:28 +02:00

fix(server): album statistics endpoint (#11924)

This commit is contained in:
Jason Rasmussen 2024-08-20 07:50:36 -04:00 committed by GitHub
parent cde0458dc8
commit ef9a06be5c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 47 additions and 47 deletions

View File

@ -344,16 +344,16 @@ describe('/albums', () => {
}); });
}); });
describe('GET /albums/count', () => { describe('GET /albums/statistics', () => {
it('should require authentication', async () => { it('should require authentication', async () => {
const { status, body } = await request(app).get('/albums/count'); const { status, body } = await request(app).get('/albums/statistics');
expect(status).toBe(401); expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized); expect(body).toEqual(errorDto.unauthorized);
}); });
it('should return total count of albums the user has access to', async () => { it('should return total count of albums the user has access to', async () => {
const { status, body } = await request(app) const { status, body } = await request(app)
.get('/albums/count') .get('/albums/statistics')
.set('Authorization', `Bearer ${user1.accessToken}`); .set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200); expect(status).toBe(200);

BIN
mobile/openapi/README.md generated

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -660,16 +660,16 @@
] ]
} }
}, },
"/albums/count": { "/albums/statistics": {
"get": { "get": {
"operationId": "getAlbumCount", "operationId": "getAlbumStatistics",
"parameters": [], "parameters": [],
"responses": { "responses": {
"200": { "200": {
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/AlbumCountResponseDto" "$ref": "#/components/schemas/AlbumStatisticsResponseDto"
} }
} }
}, },
@ -7505,25 +7505,6 @@
], ],
"type": "object" "type": "object"
}, },
"AlbumCountResponseDto": {
"properties": {
"notShared": {
"type": "integer"
},
"owned": {
"type": "integer"
},
"shared": {
"type": "integer"
}
},
"required": [
"notShared",
"owned",
"shared"
],
"type": "object"
},
"AlbumResponseDto": { "AlbumResponseDto": {
"properties": { "properties": {
"albumName": { "albumName": {
@ -7611,6 +7592,25 @@
], ],
"type": "object" "type": "object"
}, },
"AlbumStatisticsResponseDto": {
"properties": {
"notShared": {
"type": "integer"
},
"owned": {
"type": "integer"
},
"shared": {
"type": "integer"
}
},
"required": [
"notShared",
"owned",
"shared"
],
"type": "object"
},
"AlbumUserAddDto": { "AlbumUserAddDto": {
"properties": { "properties": {
"role": { "role": {

View File

@ -268,7 +268,7 @@ export type CreateAlbumDto = {
assetIds?: string[]; assetIds?: string[];
description?: string; description?: string;
}; };
export type AlbumCountResponseDto = { export type AlbumStatisticsResponseDto = {
notShared: number; notShared: number;
owned: number; owned: number;
shared: number; shared: number;
@ -1369,11 +1369,11 @@ export function createAlbum({ createAlbumDto }: {
body: createAlbumDto body: createAlbumDto
}))); })));
} }
export function getAlbumCount(opts?: Oazapfts.RequestOpts) { export function getAlbumStatistics(opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{ return oazapfts.ok(oazapfts.fetchJson<{
status: 200; status: 200;
data: AlbumCountResponseDto; data: AlbumStatisticsResponseDto;
}>("/albums/count", { }>("/albums/statistics", {
...opts ...opts
})); }));
} }

View File

@ -2,9 +2,9 @@ import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query } from '@
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { import {
AddUsersDto, AddUsersDto,
AlbumCountResponseDto,
AlbumInfoDto, AlbumInfoDto,
AlbumResponseDto, AlbumResponseDto,
AlbumStatisticsResponseDto,
CreateAlbumDto, CreateAlbumDto,
GetAlbumsDto, GetAlbumsDto,
UpdateAlbumDto, UpdateAlbumDto,
@ -22,12 +22,6 @@ import { ParseMeUUIDPipe, UUIDParamDto } from 'src/validation';
export class AlbumController { export class AlbumController {
constructor(private service: AlbumService) {} constructor(private service: AlbumService) {}
@Get('count')
@Authenticated({ permission: Permission.ALBUM_STATISTICS })
getAlbumCount(@Auth() auth: AuthDto): Promise<AlbumCountResponseDto> {
return this.service.getCount(auth);
}
@Get() @Get()
@Authenticated({ permission: Permission.ALBUM_READ }) @Authenticated({ permission: Permission.ALBUM_READ })
getAllAlbums(@Auth() auth: AuthDto, @Query() query: GetAlbumsDto): Promise<AlbumResponseDto[]> { getAllAlbums(@Auth() auth: AuthDto, @Query() query: GetAlbumsDto): Promise<AlbumResponseDto[]> {
@ -40,6 +34,12 @@ export class AlbumController {
return this.service.create(auth, dto); return this.service.create(auth, dto);
} }
@Get('statistics')
@Authenticated({ permission: Permission.ALBUM_STATISTICS })
getAlbumStatistics(@Auth() auth: AuthDto): Promise<AlbumStatisticsResponseDto> {
return this.service.getStatistics(auth);
}
@Authenticated({ permission: Permission.ALBUM_READ, sharedLink: true }) @Authenticated({ permission: Permission.ALBUM_READ, sharedLink: true })
@Get(':id') @Get(':id')
getAlbumInfo( getAlbumInfo(

View File

@ -95,7 +95,7 @@ export class GetAlbumsDto {
assetId?: string; assetId?: string;
} }
export class AlbumCountResponseDto { export class AlbumStatisticsResponseDto {
@ApiProperty({ type: 'integer' }) @ApiProperty({ type: 'integer' })
owned!: number; owned!: number;

View File

@ -43,12 +43,12 @@ describe(AlbumService.name, () => {
expect(sut).toBeDefined(); expect(sut).toBeDefined();
}); });
describe('getCount', () => { describe('getStatistics', () => {
it('should get the album count', async () => { it('should get the album count', async () => {
albumMock.getOwned.mockResolvedValue([]); albumMock.getOwned.mockResolvedValue([]);
albumMock.getShared.mockResolvedValue([]); albumMock.getShared.mockResolvedValue([]);
albumMock.getNotShared.mockResolvedValue([]); albumMock.getNotShared.mockResolvedValue([]);
await expect(sut.getCount(authStub.admin)).resolves.toEqual({ await expect(sut.getStatistics(authStub.admin)).resolves.toEqual({
owned: 0, owned: 0,
shared: 0, shared: 0,
notShared: 0, notShared: 0,

View File

@ -1,9 +1,9 @@
import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { import {
AddUsersDto, AddUsersDto,
AlbumCountResponseDto,
AlbumInfoDto, AlbumInfoDto,
AlbumResponseDto, AlbumResponseDto,
AlbumStatisticsResponseDto,
CreateAlbumDto, CreateAlbumDto,
GetAlbumsDto, GetAlbumsDto,
UpdateAlbumDto, UpdateAlbumDto,
@ -37,7 +37,7 @@ export class AlbumService {
@Inject(IAlbumUserRepository) private albumUserRepository: IAlbumUserRepository, @Inject(IAlbumUserRepository) private albumUserRepository: IAlbumUserRepository,
) {} ) {}
async getCount(auth: AuthDto): Promise<AlbumCountResponseDto> { async getStatistics(auth: AuthDto): Promise<AlbumStatisticsResponseDto> {
const [owned, shared, notShared] = await Promise.all([ const [owned, shared, notShared] = await Promise.all([
this.albumRepository.getOwned(auth.user.id), this.albumRepository.getOwned(auth.user.id),
this.albumRepository.getShared(auth.user.id), this.albumRepository.getShared(auth.user.id),

View File

@ -1,13 +1,13 @@
<script lang="ts"> <script lang="ts">
import { type AlbumCountResponseDto, getAlbumCount } from '@immich/sdk'; import { type AlbumStatisticsResponseDto, getAlbumStatistics } from '@immich/sdk';
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
export let albumCountType: keyof AlbumCountResponseDto; export let albumType: keyof AlbumStatisticsResponseDto;
const handleAlbumCount = async () => { const handleAlbumCount = async () => {
try { try {
return await getAlbumCount(); return await getAlbumStatistics();
} catch { } catch {
return { owned: 0, shared: 0, notShared: 0 }; return { owned: 0, shared: 0, notShared: 0 };
} }
@ -18,6 +18,6 @@
<LoadingSpinner /> <LoadingSpinner />
{:then data} {:then data}
<div> <div>
<p>{$t('albums_count', { values: { count: data[albumCountType] } })}</p> <p>{$t('albums_count', { values: { count: data[albumType] } })}</p>
</div> </div>
{/await} {/await}

View File

@ -79,7 +79,7 @@
bind:isSelected={isSharingSelected} bind:isSelected={isSharingSelected}
> >
<svelte:fragment slot="moreInformation"> <svelte:fragment slot="moreInformation">
<MoreInformationAlbums albumCountType="shared" /> <MoreInformationAlbums albumType="shared" />
</svelte:fragment> </svelte:fragment>
</SideBarLink> </SideBarLink>
{/if} {/if}
@ -100,7 +100,7 @@
</SideBarLink> </SideBarLink>
<SideBarLink title={$t('albums')} routeId="/(user)/albums" icon={mdiImageAlbum} flippedLogo> <SideBarLink title={$t('albums')} routeId="/(user)/albums" icon={mdiImageAlbum} flippedLogo>
<svelte:fragment slot="moreInformation"> <svelte:fragment slot="moreInformation">
<MoreInformationAlbums albumCountType="owned" /> <MoreInformationAlbums albumType="owned" />
</svelte:fragment> </svelte:fragment>
</SideBarLink> </SideBarLink>