From 07f7fffae7fc1702bbab326afb92a94e929d9247 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Fri, 16 Jun 2023 11:48:48 -0400 Subject: [PATCH] refactor(server): album count (#2746) * refactor(server): album count * chore: open api --- mobile/openapi/README.md | Bin 17855 -> 17828 bytes mobile/openapi/doc/AlbumApi.md | Bin 25864 -> 25805 bytes mobile/openapi/doc/AlbumCountResponseDto.md | Bin 468 -> 470 bytes mobile/openapi/lib/api/album_api.dart | Bin 20743 -> 20697 bytes .../lib/model/album_count_response_dto.dart | Bin 3821 -> 3845 bytes mobile/openapi/test/album_api_test.dart | Bin 2294 -> 2278 bytes .../test/album_count_response_dto_test.dart | Bin 768 -> 772 bytes server/immich-openapi-specs.json | 8 ++++---- .../{response-dto => }/album-response.dto.ts | 15 +++++++++++++-- server/src/domain/album/album.service.spec.ts | 17 +++++++++++++++++ server/src/domain/album/album.service.ts | 16 +++++++++++++++- server/src/domain/album/index.ts | 2 +- server/src/domain/album/response-dto/index.ts | 1 - .../immich/api-v1/album/album-repository.ts | 10 ---------- .../immich/api-v1/album/album.controller.ts | 6 ------ .../immich/api-v1/album/album.service.spec.ts | 1 - .../src/immich/api-v1/album/album.service.ts | 5 ----- .../response-dto/album-count-response.dto.ts | 18 ------------------ .../immich/controllers/album.controller.ts | 14 +++++++++++++- web/src/api/open-api/api.ts | 18 +++++++++--------- .../side-bar/side-bar.svelte | 16 ++++------------ 21 files changed, 76 insertions(+), 71 deletions(-) rename server/src/domain/album/{response-dto => }/album-response.dto.ts (84%) delete mode 100644 server/src/domain/album/response-dto/index.ts delete mode 100644 server/src/immich/api-v1/album/response-dto/album-count-response.dto.ts diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index dfb4278b10f95023c648de9d9c828ec8c0992318..b36bab88898f75fbc1c77ee4917ca703d469b596 100644 GIT binary patch delta 55 zcmdnr&A6nSal;Xw$rE{{6p~7Flk-dSN;DN}6tuM5T|>0A6!a5wfWrD<@yUg}lADcq Gdo2JcArjgE delta 57 zcmZ3|&A7jtal;WF4yVe{;?yF~l*xr$qLXj(@J<#I6%)-#D$UhT&M(a?(M_tP}DU;7K$#NuBmI67MDU%JEg$0uHOY=%}lPYyVV!D|r wo0*vTjS%VuO*J@Snl&~nxX7|h4!1Nx2u)U$3YdJyk{6+4fv3V|POBqY0M%P6(f|Me diff --git a/mobile/openapi/doc/AlbumCountResponseDto.md b/mobile/openapi/doc/AlbumCountResponseDto.md index 94a2328f0075ef6b4179282dfeceb99129fd472f..57b6e156c834179bc52deb87a300060f3a00aac0 100644 GIT binary patch delta 21 ccmcb@e2sa7C?jWHeo1gfVo_?!WEsXC08`ipkN^Mx delta 19 acmcb{e1&;~C?k7uMq*KBUixG?#vK4f76#M+ diff --git a/mobile/openapi/lib/api/album_api.dart b/mobile/openapi/lib/api/album_api.dart index c1497afc7e436cc0a4c4d98698ef8ad6978496d2..b17c838f5b70622aad3b89764e7abae047e00cb4 100644 GIT binary patch delta 57 zcmZo)#CUTdSWlocvCogVi~|G_Pc`x>o$=iCVW988s#^P*9y5U<{Sm JyiO-l1ptU>6)XS% delta 116 zcmcb)kgc$7FdSxydrBXD2J_=y1YRYfKjOQx#25Epg0AD$RAyFU>1~No{V>iBtgqUmYlZ diff --git a/mobile/openapi/lib/model/album_count_response_dto.dart b/mobile/openapi/lib/model/album_count_response_dto.dart index 10a5e21a45db7c14e608421a53396c9f02043503..198717553967b777bd7ad49c4a5e8c5e28a88db0 100644 GIT binary patch delta 180 zcmaDW+bXx=3L|G;eo1gfVo_?!!)3L|@QMq*KBUi##_j5=_(5YsjxsJMcytpZHRJ*Eb@l62-&0jRjG3QWNR z=0y@vwtB3BtwKpgX0aYrVDmhdm&}s`I9QlLwkdGP!Hn9xox_R^W}UhYmx4mAHCHVc F7XS^ZITQc@ diff --git a/mobile/openapi/test/album_api_test.dart b/mobile/openapi/test/album_api_test.dart index 6a75449eebfcd1d9e5cead74748d8fb15f05b87c..77f92590ee493675c97e4857c946a043385a139d 100644 GIT binary patch delta 32 ocmew+_)KuaG*(89$p@LlC;PB*usY|L=9NtT$mX({pY1sl0K$z6S^xk5 delta 43 tcmaDR_)T!bG*(Wh%FyD}BF_|!$p@LlC$D4W<$#Gye#qvs`9JG(CID+25U&6L diff --git a/mobile/openapi/test/album_count_response_dto_test.dart b/mobile/openapi/test/album_count_response_dto_test.dart index 33703a650e291a143ec5f5a63974e5b5a439ae3e..2f294f463ef241fdaadc7de43f795cd8651b4b72 100644 GIT binary patch delta 42 qcmZo*Yhl~4kcmAnza%&#v1sxuMrAl#fJuXkOF^Ml)0&H`mJ0wbqYQ2U delta 35 jcmZo+Yhc^3kcquGBe5tmFMaYGMnyQgfJtrgFD5Pk { expect(sut).toBeDefined(); }); + describe('getCount', () => { + it('should get the album count', async () => { + albumMock.getOwned.mockResolvedValue([]), + albumMock.getShared.mockResolvedValue([]), + albumMock.getNotShared.mockResolvedValue([]), + await expect(sut.getCount(authStub.admin)).resolves.toEqual({ + owned: 0, + shared: 0, + notShared: 0, + }); + + expect(albumMock.getOwned).toHaveBeenCalledWith(authStub.admin.id); + expect(albumMock.getShared).toHaveBeenCalledWith(authStub.admin.id); + expect(albumMock.getNotShared).toHaveBeenCalledWith(authStub.admin.id); + }); + }); + describe('getAll', () => { it('gets list of albums for auth user', async () => { albumMock.getOwned.mockResolvedValue([albumStub.empty, albumStub.sharedWithUser]); diff --git a/server/src/domain/album/album.service.ts b/server/src/domain/album/album.service.ts index 6bad729531..21461fe271 100644 --- a/server/src/domain/album/album.service.ts +++ b/server/src/domain/album/album.service.ts @@ -4,9 +4,9 @@ import { IAssetRepository, mapAsset } from '../asset'; import { AuthUserDto } from '../auth'; import { IJobRepository, JobName } from '../job'; import { IUserRepository } from '../user'; +import { AlbumCountResponseDto, AlbumResponseDto, mapAlbum } from './album-response.dto'; import { IAlbumRepository } from './album.repository'; import { AddUsersDto, CreateAlbumDto, GetAlbumsDto, UpdateAlbumDto } from './dto'; -import { AlbumResponseDto, mapAlbum } from './response-dto'; @Injectable() export class AlbumService { @@ -17,6 +17,20 @@ export class AlbumService { @Inject(IUserRepository) private userRepository: IUserRepository, ) {} + async getCount(authUser: AuthUserDto): Promise { + const [owned, shared, notShared] = await Promise.all([ + this.albumRepository.getOwned(authUser.id), + this.albumRepository.getShared(authUser.id), + this.albumRepository.getNotShared(authUser.id), + ]); + + return { + owned: owned.length, + shared: shared.length, + notShared: notShared.length, + }; + } + async getAll({ id: ownerId }: AuthUserDto, { assetId, shared }: GetAlbumsDto): Promise { await this.updateInvalidThumbnails(); diff --git a/server/src/domain/album/index.ts b/server/src/domain/album/index.ts index f80717b257..5042b0f446 100644 --- a/server/src/domain/album/index.ts +++ b/server/src/domain/album/index.ts @@ -1,4 +1,4 @@ +export * from './album-response.dto'; export * from './album.repository'; export * from './album.service'; export * from './dto'; -export * from './response-dto'; diff --git a/server/src/domain/album/response-dto/index.ts b/server/src/domain/album/response-dto/index.ts deleted file mode 100644 index d3b278b7dd..0000000000 --- a/server/src/domain/album/response-dto/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './album-response.dto'; diff --git a/server/src/immich/api-v1/album/album-repository.ts b/server/src/immich/api-v1/album/album-repository.ts index b32f83a96e..f73e36f20a 100644 --- a/server/src/immich/api-v1/album/album-repository.ts +++ b/server/src/immich/api-v1/album/album-repository.ts @@ -5,7 +5,6 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { AddAssetsDto } from './dto/add-assets.dto'; import { RemoveAssetsDto } from './dto/remove-assets.dto'; -import { AlbumCountResponseDto } from './response-dto/album-count-response.dto'; import { AddAssetsResponseDto } from './response-dto/add-assets-response.dto'; export interface IAlbumRepository { @@ -13,7 +12,6 @@ export interface IAlbumRepository { removeAssets(album: AlbumEntity, removeAssets: RemoveAssetsDto): Promise; addAssets(album: AlbumEntity, addAssetsDto: AddAssetsDto): Promise; updateThumbnails(): Promise; - getCountByUserId(userId: string): Promise; getSharedWithUserAlbumCount(userId: string, assetId: string): Promise; } @@ -26,14 +24,6 @@ export class AlbumRepository implements IAlbumRepository { @InjectRepository(AssetEntity) private assetRepository: Repository, ) {} - async getCountByUserId(userId: string): Promise { - const ownedAlbums = await this.albumRepository.find({ where: { ownerId: userId }, relations: ['sharedUsers'] }); - const sharedAlbums = await this.albumRepository.count({ where: { sharedUsers: { id: userId } } }); - const sharedAlbumCount = ownedAlbums.filter((album) => album.sharedUsers?.length > 0).length; - - return new AlbumCountResponseDto(ownedAlbums.length, sharedAlbums, sharedAlbumCount); - } - async get(albumId: string): Promise { return this.albumRepository.findOne({ where: { id: albumId }, diff --git a/server/src/immich/api-v1/album/album.controller.ts b/server/src/immich/api-v1/album/album.controller.ts index 02d06280a6..5d84a018f7 100644 --- a/server/src/immich/api-v1/album/album.controller.ts +++ b/server/src/immich/api-v1/album/album.controller.ts @@ -6,7 +6,6 @@ import { AddAssetsDto } from './dto/add-assets.dto'; import { RemoveAssetsDto } from './dto/remove-assets.dto'; import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { AlbumResponseDto } from '@app/domain'; -import { AlbumCountResponseDto } from './response-dto/album-count-response.dto'; import { AddAssetsResponseDto } from './response-dto/add-assets-response.dto'; import { Response as Res } from 'express'; import { DownloadDto } from '../asset/dto/download-library.dto'; @@ -22,11 +21,6 @@ import { handleDownload } from '../../app.utils'; export class AlbumController { constructor(private readonly service: AlbumService) {} - @Get('count-by-user-id') - getAlbumCountByUserId(@GetAuthUser() authUser: AuthUserDto): Promise { - return this.service.getCountByUserId(authUser); - } - @SharedLinkRoute() @Put(':id/assets') addAssetsToAlbum( diff --git a/server/src/immich/api-v1/album/album.service.spec.ts b/server/src/immich/api-v1/album/album.service.spec.ts index c864d767ac..81e66bfd49 100644 --- a/server/src/immich/api-v1/album/album.service.spec.ts +++ b/server/src/immich/api-v1/album/album.service.spec.ts @@ -98,7 +98,6 @@ describe('Album service', () => { get: jest.fn(), removeAssets: jest.fn(), updateThumbnails: jest.fn(), - getCountByUserId: jest.fn(), getSharedWithUserAlbumCount: jest.fn(), }; diff --git a/server/src/immich/api-v1/album/album.service.ts b/server/src/immich/api-v1/album/album.service.ts index 8db380a5ae..bda00573aa 100644 --- a/server/src/immich/api-v1/album/album.service.ts +++ b/server/src/immich/api-v1/album/album.service.ts @@ -4,7 +4,6 @@ import { AlbumEntity, SharedLinkType } from '@app/infra/entities'; import { RemoveAssetsDto } from './dto/remove-assets.dto'; import { AlbumResponseDto, mapAlbum } from '@app/domain'; import { IAlbumRepository } from './album-repository'; -import { AlbumCountResponseDto } from './response-dto/album-count-response.dto'; import { AddAssetsResponseDto } from './response-dto/add-assets-response.dto'; import { AddAssetsDto } from './dto/add-assets.dto'; import { DownloadService } from '../../modules/download/download.service'; @@ -90,10 +89,6 @@ export class AlbumService { }; } - async getCountByUserId(authUser: AuthUserDto): Promise { - return this.albumRepository.getCountByUserId(authUser.id); - } - async downloadArchive(authUser: AuthUserDto, albumId: string, dto: DownloadDto) { this.shareCore.checkDownloadAccess(authUser); diff --git a/server/src/immich/api-v1/album/response-dto/album-count-response.dto.ts b/server/src/immich/api-v1/album/response-dto/album-count-response.dto.ts deleted file mode 100644 index 9f5ae515f5..0000000000 --- a/server/src/immich/api-v1/album/response-dto/album-count-response.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; - -export class AlbumCountResponseDto { - @ApiProperty({ type: 'integer' }) - owned!: number; - - @ApiProperty({ type: 'integer' }) - shared!: number; - - @ApiProperty({ type: 'integer' }) - sharing!: number; - - constructor(owned: number, shared: number, sharing: number) { - this.owned = owned; - this.shared = shared; - this.sharing = sharing; - } -} diff --git a/server/src/immich/controllers/album.controller.ts b/server/src/immich/controllers/album.controller.ts index b00858a302..416275712a 100644 --- a/server/src/immich/controllers/album.controller.ts +++ b/server/src/immich/controllers/album.controller.ts @@ -1,4 +1,11 @@ -import { AddUsersDto, AlbumService, AuthUserDto, CreateAlbumDto, UpdateAlbumDto } from '@app/domain'; +import { + AddUsersDto, + AlbumCountResponseDto, + AlbumService, + AuthUserDto, + CreateAlbumDto, + UpdateAlbumDto, +} from '@app/domain'; import { GetAlbumsDto } from '@app/domain/album/dto/get-albums.dto'; import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; @@ -15,6 +22,11 @@ import { UUIDParamDto } from './dto/uuid-param.dto'; export class AlbumController { constructor(private service: AlbumService) {} + @Get('count') + getAlbumCount(@GetAuthUser() authUser: AuthUserDto): Promise { + return this.service.getCount(authUser); + } + @Get() getAllAlbums(@GetAuthUser() authUser: AuthUserDto, @Query() query: GetAlbumsDto) { return this.service.getAll(authUser, query); diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index a55acbb527..7876a9e5ed 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -210,7 +210,7 @@ export interface AlbumCountResponseDto { * @type {number} * @memberof AlbumCountResponseDto */ - 'sharing': number; + 'notShared': number; } /** * @@ -3678,8 +3678,8 @@ export const AlbumApiAxiosParamCreator = function (configuration?: Configuration * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAlbumCountByUserId: async (options: AxiosRequestConfig = {}): Promise => { - const localVarPath = `/album/count-by-user-id`; + getAlbumCount: async (options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/album/count`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -4029,8 +4029,8 @@ export const AlbumApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getAlbumCountByUserId(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getAlbumCountByUserId(options); + async getAlbumCount(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getAlbumCount(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -4163,8 +4163,8 @@ export const AlbumApiFactory = function (configuration?: Configuration, basePath * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAlbumCountByUserId(options?: any): AxiosPromise { - return localVarFp.getAlbumCountByUserId(options).then((request) => request(axios, basePath)); + getAlbumCount(options?: any): AxiosPromise { + return localVarFp.getAlbumCount(options).then((request) => request(axios, basePath)); }, /** * @@ -4529,8 +4529,8 @@ export class AlbumApi extends BaseAPI { * @throws {RequiredError} * @memberof AlbumApi */ - public getAlbumCountByUserId(options?: AxiosRequestConfig) { - return AlbumApiFp(this.configuration).getAlbumCountByUserId(options).then((request) => request(this.axios, this.basePath)); + public getAlbumCount(options?: AxiosRequestConfig) { + return AlbumApiFp(this.configuration).getAlbumCount(options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/web/src/lib/components/shared-components/side-bar/side-bar.svelte b/web/src/lib/components/shared-components/side-bar/side-bar.svelte index 92db34f738..12513701f2 100644 --- a/web/src/lib/components/shared-components/side-bar/side-bar.svelte +++ b/web/src/lib/components/shared-components/side-bar/side-bar.svelte @@ -47,18 +47,10 @@ const getAlbumCount = async () => { try { - const { data: albumCount } = await api.albumApi.getAlbumCountByUserId(); - return { - shared: albumCount.shared, - sharing: albumCount.sharing, - owned: albumCount.owned - }; + const { data: albumCount } = await api.albumApi.getAlbumCount(); + return albumCount; } catch { - return { - shared: 0, - sharing: 0, - owned: 0 - }; + return { owned: 0, shared: 0, notShared: 0 }; } }; @@ -133,7 +125,7 @@ {:then data}
-

{(data.shared + data.sharing).toLocaleString($locale)} Albums

+

{data.shared.toLocaleString($locale)} Albums

{/await}