diff --git a/mobile/openapi/doc/AlbumResponseDto.md b/mobile/openapi/doc/AlbumResponseDto.md index 33ab5943b..3b65af276 100644 Binary files a/mobile/openapi/doc/AlbumResponseDto.md and b/mobile/openapi/doc/AlbumResponseDto.md differ diff --git a/mobile/openapi/lib/model/album_response_dto.dart b/mobile/openapi/lib/model/album_response_dto.dart index 3616c7549..615206a3c 100644 Binary files a/mobile/openapi/lib/model/album_response_dto.dart and b/mobile/openapi/lib/model/album_response_dto.dart differ diff --git a/server/apps/immich/src/api-v1/album/album-repository.ts b/server/apps/immich/src/api-v1/album/album-repository.ts index 7fa96169c..81f72db18 100644 --- a/server/apps/immich/src/api-v1/album/album-repository.ts +++ b/server/apps/immich/src/api-v1/album/album-repository.ts @@ -49,6 +49,7 @@ export class AlbumRepository implements IAlbumRepository { relations: { sharedLinks: true, assets: true, + owner: true, }, where: { ownerId, diff --git a/server/apps/immich/src/api-v1/album/album.service.spec.ts b/server/apps/immich/src/api-v1/album/album.service.spec.ts index 6733db560..c009e1650 100644 --- a/server/apps/immich/src/api-v1/album/album.service.spec.ts +++ b/server/apps/immich/src/api-v1/album/album.service.spec.ts @@ -1,8 +1,8 @@ import { AlbumService } from './album.service'; import { AuthUserDto } from '../../decorators/auth-user.decorator'; import { BadRequestException, NotFoundException, ForbiddenException } from '@nestjs/common'; -import { AlbumEntity } from '@app/infra'; -import { AlbumResponseDto, ICryptoRepository } from '@app/domain'; +import { AlbumEntity, UserEntity } from '@app/infra'; +import { AlbumResponseDto, ICryptoRepository, mapUser } from '@app/domain'; import { AddAssetsResponseDto } from './response-dto/add-assets-response.dto'; import { IAlbumRepository } from './album-repository'; import { DownloadService } from '../../modules/download/download.service'; @@ -21,6 +21,18 @@ describe('Album service', () => { email: 'auth@test.com', isAdmin: false, }); + + const albumOwner: UserEntity = Object.freeze({ + ...authUser, + firstName: 'auth', + lastName: 'user', + createdAt: 'date', + updatedAt: 'date', + profileImagePath: '', + shouldChangePassword: false, + oauthId: '', + tags: [], + }); const albumId = 'f19ab956-4761-41ea-a5d6-bae948308d58'; const sharedAlbumOwnerId = '2222'; const sharedAlbumSharedAlsoWithId = '3333'; @@ -28,7 +40,8 @@ describe('Album service', () => { const _getOwnedAlbum = () => { const albumEntity = new AlbumEntity(); - albumEntity.ownerId = authUser.id; + albumEntity.ownerId = albumOwner.id; + albumEntity.owner = albumOwner; albumEntity.id = albumId; albumEntity.albumName = 'name'; albumEntity.createdAt = 'date'; @@ -42,7 +55,8 @@ describe('Album service', () => { const _getOwnedSharedAlbum = () => { const albumEntity = new AlbumEntity(); - albumEntity.ownerId = authUser.id; + albumEntity.ownerId = albumOwner.id; + albumEntity.owner = albumOwner; albumEntity.id = albumId; albumEntity.albumName = 'name'; albumEntity.createdAt = 'date'; @@ -68,6 +82,7 @@ describe('Album service', () => { const _getSharedWithAuthUserAlbum = () => { const albumEntity = new AlbumEntity(); albumEntity.ownerId = sharedAlbumOwnerId; + albumEntity.owner = albumOwner; albumEntity.id = albumId; albumEntity.albumName = 'name'; albumEntity.createdAt = 'date'; @@ -174,22 +189,22 @@ describe('Album service', () => { }); it('gets an owned album', async () => { - const ownerId = authUser.id; const albumId = 'f19ab956-4761-41ea-a5d6-bae948308d58'; const albumEntity = _getOwnedAlbum(); albumRepositoryMock.get.mockImplementation(() => Promise.resolve(albumEntity)); const expectedResult: AlbumResponseDto = { + ownerId: albumOwner.id, + owner: mapUser(albumOwner), + id: albumId, albumName: 'name', - albumThumbnailAssetId: null, createdAt: 'date', updatedAt: 'date', - id: 'f19ab956-4761-41ea-a5d6-bae948308d58', - ownerId, - shared: false, - assets: [], sharedUsers: [], + assets: [], + albumThumbnailAssetId: null, + shared: false, assetCount: 0, }; await expect(sut.getAlbumInfo(authUser, albumId)).resolves.toEqual(expectedResult); @@ -473,6 +488,7 @@ describe('Album service', () => { const albumEntity = new AlbumEntity(); albumEntity.ownerId = authUser.id; + albumEntity.owner = albumOwner; albumEntity.id = albumId; albumEntity.albumName = 'name'; albumEntity.createdAt = 'date'; diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index 64484ee9f..bd7442c78 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -3400,7 +3400,8 @@ "albumThumbnailAssetId", "shared", "sharedUsers", - "assets" + "assets", + "owner" ] }, "SharedLinkResponseDto": { diff --git a/server/libs/domain/src/album/response-dto/album-response.dto.ts b/server/libs/domain/src/album/response-dto/album-response.dto.ts index 7e7458727..b7a52af8c 100644 --- a/server/libs/domain/src/album/response-dto/album-response.dto.ts +++ b/server/libs/domain/src/album/response-dto/album-response.dto.ts @@ -13,7 +13,7 @@ export class AlbumResponseDto { shared!: boolean; sharedUsers!: UserResponseDto[]; assets!: AssetResponseDto[]; - owner?: UserResponseDto; + owner!: UserResponseDto; @ApiProperty({ type: 'integer' }) assetCount!: number; } @@ -35,7 +35,7 @@ export function mapAlbum(entity: AlbumEntity): AlbumResponseDto { updatedAt: entity.updatedAt, id: entity.id, ownerId: entity.ownerId, - owner: entity.owner ? mapUser(entity.owner) : undefined, + owner: mapUser(entity.owner), sharedUsers, shared: sharedUsers.length > 0 || entity.sharedLinks?.length > 0, assets: entity.assets?.map((assetAlbum) => mapAsset(assetAlbum.assetInfo)) || [], @@ -60,7 +60,7 @@ export function mapAlbumExcludeAssetInfo(entity: AlbumEntity): AlbumResponseDto updatedAt: entity.updatedAt, id: entity.id, ownerId: entity.ownerId, - owner: entity.owner ? mapUser(entity.owner) : undefined, + owner: mapUser(entity.owner), sharedUsers, shared: sharedUsers.length > 0 || entity.sharedLinks?.length > 0, assets: [], diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index 078877269..4789ee960 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -281,7 +281,7 @@ export interface AlbumResponseDto { * @type {UserResponseDto} * @memberof AlbumResponseDto */ - 'owner'?: UserResponseDto; + 'owner': UserResponseDto; } /** * diff --git a/web/src/lib/components/shared-components/immich-thumbnail.svelte b/web/src/lib/components/shared-components/immich-thumbnail.svelte index 0f9390cf4..b4b10e9f3 100644 --- a/web/src/lib/components/shared-components/immich-thumbnail.svelte +++ b/web/src/lib/components/shared-components/immich-thumbnail.svelte @@ -34,6 +34,7 @@ let calculateVideoDurationIntervalHandler: NodeJS.Timer; let videoProgress = '00:00'; let videoUrl: string; + $: isPublicShared = publicSharedKey !== ''; const loadVideoData = async (isLivePhoto: boolean) => { isThumbnailVideoPlaying = false; @@ -183,7 +184,7 @@ {/if} - {#if asset.isFavorite} + {#if asset.isFavorite && !isPublicShared}