diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index dfb4278b10..b36bab8889 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -83,7 +83,7 @@ Class | Method | HTTP request | Description *AlbumApi* | [**createAlbumSharedLink**](doc//AlbumApi.md#createalbumsharedlink) | **POST** /album/create-shared-link | *AlbumApi* | [**deleteAlbum**](doc//AlbumApi.md#deletealbum) | **DELETE** /album/{id} | *AlbumApi* | [**downloadArchive**](doc//AlbumApi.md#downloadarchive) | **GET** /album/{id}/download | -*AlbumApi* | [**getAlbumCountByUserId**](doc//AlbumApi.md#getalbumcountbyuserid) | **GET** /album/count-by-user-id | +*AlbumApi* | [**getAlbumCount**](doc//AlbumApi.md#getalbumcount) | **GET** /album/count | *AlbumApi* | [**getAlbumInfo**](doc//AlbumApi.md#getalbuminfo) | **GET** /album/{id} | *AlbumApi* | [**getAllAlbums**](doc//AlbumApi.md#getallalbums) | **GET** /album | *AlbumApi* | [**removeAssetFromAlbum**](doc//AlbumApi.md#removeassetfromalbum) | **DELETE** /album/{id}/assets | diff --git a/mobile/openapi/doc/AlbumApi.md b/mobile/openapi/doc/AlbumApi.md index 2924ce5c02..172cd14162 100644 --- a/mobile/openapi/doc/AlbumApi.md +++ b/mobile/openapi/doc/AlbumApi.md @@ -15,7 +15,7 @@ Method | HTTP request | Description [**createAlbumSharedLink**](AlbumApi.md#createalbumsharedlink) | **POST** /album/create-shared-link | [**deleteAlbum**](AlbumApi.md#deletealbum) | **DELETE** /album/{id} | [**downloadArchive**](AlbumApi.md#downloadarchive) | **GET** /album/{id}/download | -[**getAlbumCountByUserId**](AlbumApi.md#getalbumcountbyuserid) | **GET** /album/count-by-user-id | +[**getAlbumCount**](AlbumApi.md#getalbumcount) | **GET** /album/count | [**getAlbumInfo**](AlbumApi.md#getalbuminfo) | **GET** /album/{id} | [**getAllAlbums**](AlbumApi.md#getallalbums) | **GET** /album | [**removeAssetFromAlbum**](AlbumApi.md#removeassetfromalbum) | **DELETE** /album/{id}/assets | @@ -364,8 +364,8 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getAlbumCountByUserId** -> AlbumCountResponseDto getAlbumCountByUserId() +# **getAlbumCount** +> AlbumCountResponseDto getAlbumCount() @@ -390,10 +390,10 @@ import 'package:openapi/api.dart'; final api_instance = AlbumApi(); try { - final result = api_instance.getAlbumCountByUserId(); + final result = api_instance.getAlbumCount(); print(result); } catch (e) { - print('Exception when calling AlbumApi->getAlbumCountByUserId: $e\n'); + print('Exception when calling AlbumApi->getAlbumCount: $e\n'); } ``` diff --git a/mobile/openapi/doc/AlbumCountResponseDto.md b/mobile/openapi/doc/AlbumCountResponseDto.md index 94a2328f00..57b6e156c8 100644 --- a/mobile/openapi/doc/AlbumCountResponseDto.md +++ b/mobile/openapi/doc/AlbumCountResponseDto.md @@ -10,7 +10,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **owned** | **int** | | **shared** | **int** | | -**sharing** | **int** | | +**notShared** | **int** | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/mobile/openapi/lib/api/album_api.dart b/mobile/openapi/lib/api/album_api.dart index c1497afc7e..b17c838f5b 100644 --- a/mobile/openapi/lib/api/album_api.dart +++ b/mobile/openapi/lib/api/album_api.dart @@ -332,10 +332,10 @@ class AlbumApi { return null; } - /// Performs an HTTP 'GET /album/count-by-user-id' operation and returns the [Response]. - Future getAlbumCountByUserIdWithHttpInfo() async { + /// Performs an HTTP 'GET /album/count' operation and returns the [Response]. + Future getAlbumCountWithHttpInfo() async { // ignore: prefer_const_declarations - final path = r'/album/count-by-user-id'; + final path = r'/album/count'; // ignore: prefer_final_locals Object? postBody; @@ -358,8 +358,8 @@ class AlbumApi { ); } - Future getAlbumCountByUserId() async { - final response = await getAlbumCountByUserIdWithHttpInfo(); + Future getAlbumCount() async { + final response = await getAlbumCountWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/model/album_count_response_dto.dart b/mobile/openapi/lib/model/album_count_response_dto.dart index 10a5e21a45..1987175539 100644 --- a/mobile/openapi/lib/model/album_count_response_dto.dart +++ b/mobile/openapi/lib/model/album_count_response_dto.dart @@ -15,36 +15,36 @@ class AlbumCountResponseDto { AlbumCountResponseDto({ required this.owned, required this.shared, - required this.sharing, + required this.notShared, }); int owned; int shared; - int sharing; + int notShared; @override bool operator ==(Object other) => identical(this, other) || other is AlbumCountResponseDto && other.owned == owned && other.shared == shared && - other.sharing == sharing; + other.notShared == notShared; @override int get hashCode => // ignore: unnecessary_parenthesis (owned.hashCode) + (shared.hashCode) + - (sharing.hashCode); + (notShared.hashCode); @override - String toString() => 'AlbumCountResponseDto[owned=$owned, shared=$shared, sharing=$sharing]'; + String toString() => 'AlbumCountResponseDto[owned=$owned, shared=$shared, notShared=$notShared]'; Map toJson() { final json = {}; json[r'owned'] = this.owned; json[r'shared'] = this.shared; - json[r'sharing'] = this.sharing; + json[r'notShared'] = this.notShared; return json; } @@ -69,7 +69,7 @@ class AlbumCountResponseDto { return AlbumCountResponseDto( owned: mapValueOfType(json, r'owned')!, shared: mapValueOfType(json, r'shared')!, - sharing: mapValueOfType(json, r'sharing')!, + notShared: mapValueOfType(json, r'notShared')!, ); } return null; @@ -119,7 +119,7 @@ class AlbumCountResponseDto { static const requiredKeys = { 'owned', 'shared', - 'sharing', + 'notShared', }; } diff --git a/mobile/openapi/test/album_api_test.dart b/mobile/openapi/test/album_api_test.dart index 6a75449eeb..77f92590ee 100644 --- a/mobile/openapi/test/album_api_test.dart +++ b/mobile/openapi/test/album_api_test.dart @@ -47,8 +47,8 @@ void main() { // TODO }); - //Future getAlbumCountByUserId() async - test('test getAlbumCountByUserId', () async { + //Future getAlbumCount() async + test('test getAlbumCount', () async { // TODO }); diff --git a/mobile/openapi/test/album_count_response_dto_test.dart b/mobile/openapi/test/album_count_response_dto_test.dart index 33703a650e..2f294f463e 100644 --- a/mobile/openapi/test/album_count_response_dto_test.dart +++ b/mobile/openapi/test/album_count_response_dto_test.dart @@ -26,8 +26,8 @@ void main() { // TODO }); - // int sharing - test('to test the property `sharing`', () async { + // int notShared + test('to test the property `notShared`', () async { // TODO }); diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index 709b21f5f0..22d0c0d4d7 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -95,9 +95,9 @@ ] } }, - "/album/count-by-user-id": { + "/album/count": { "get": { - "operationId": "getAlbumCountByUserId", + "operationId": "getAlbumCount", "parameters": [], "responses": { "200": { @@ -4530,14 +4530,14 @@ "shared": { "type": "integer" }, - "sharing": { + "notShared": { "type": "integer" } }, "required": [ "owned", "shared", - "sharing" + "notShared" ] }, "AlbumResponseDto": { diff --git a/server/src/domain/album/response-dto/album-response.dto.ts b/server/src/domain/album/album-response.dto.ts similarity index 84% rename from server/src/domain/album/response-dto/album-response.dto.ts rename to server/src/domain/album/album-response.dto.ts index 629bc5e070..2af7810db3 100644 --- a/server/src/domain/album/response-dto/album-response.dto.ts +++ b/server/src/domain/album/album-response.dto.ts @@ -1,7 +1,7 @@ import { AlbumEntity } from '@app/infra/entities'; import { ApiProperty } from '@nestjs/swagger'; -import { AssetResponseDto, mapAsset } from '../../asset'; -import { mapUser, UserResponseDto } from '../../user'; +import { AssetResponseDto, mapAsset } from '../asset'; +import { mapUser, UserResponseDto } from '../user'; export class AlbumResponseDto { id!: string; @@ -63,3 +63,14 @@ export function mapAlbumExcludeAssetInfo(entity: AlbumEntity): AlbumResponseDto assetCount: entity.assets?.length || 0, }; } + +export class AlbumCountResponseDto { + @ApiProperty({ type: 'integer' }) + owned!: number; + + @ApiProperty({ type: 'integer' }) + shared!: number; + + @ApiProperty({ type: 'integer' }) + notShared!: number; +} diff --git a/server/src/domain/album/album.service.spec.ts b/server/src/domain/album/album.service.spec.ts index 43e5b0fc96..aeb9d0da31 100644 --- a/server/src/domain/album/album.service.spec.ts +++ b/server/src/domain/album/album.service.spec.ts @@ -35,6 +35,23 @@ describe(AlbumService.name, () => { 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}