Selaa lähdekoodia

chore(server): make owner as required response for AlbumResponseDto (#1579)

Alex 2 vuotta sitten
vanhempi
commit
43fd7737f1

+ 1 - 1
mobile/openapi/doc/AlbumResponseDto.md

@@ -18,7 +18,7 @@ Name | Type | Description | Notes
 **shared** | **bool** |  | 
 **sharedUsers** | [**List<UserResponseDto>**](UserResponseDto.md) |  | [default to const []]
 **assets** | [**List<AssetResponseDto>**](AssetResponseDto.md) |  | [default to const []]
-**owner** | [**UserResponseDto**](UserResponseDto.md) |  | [optional] 
+**owner** | [**UserResponseDto**](UserResponseDto.md) |  | 
 
 [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 

+ 5 - 14
mobile/openapi/lib/model/album_response_dto.dart

@@ -23,7 +23,7 @@ class AlbumResponseDto {
     required this.shared,
     this.sharedUsers = const [],
     this.assets = const [],
-    this.owner,
+    required this.owner,
   });
 
   int assetCount;
@@ -46,13 +46,7 @@ class AlbumResponseDto {
 
   List<AssetResponseDto> assets;
 
-  ///
-  /// Please note: This property should have been non-nullable! Since the specification file
-  /// does not include a default value (using the "default:" property), however, the generated
-  /// source code must fall back to having a nullable type.
-  /// Consider adding a "default:" property in the specification file to hide this note.
-  ///
-  UserResponseDto? owner;
+  UserResponseDto owner;
 
   @override
   bool operator ==(Object other) => identical(this, other) || other is AlbumResponseDto &&
@@ -81,7 +75,7 @@ class AlbumResponseDto {
     (shared.hashCode) +
     (sharedUsers.hashCode) +
     (assets.hashCode) +
-    (owner == null ? 0 : owner!.hashCode);
+    (owner.hashCode);
 
   @override
   String toString() => 'AlbumResponseDto[assetCount=$assetCount, id=$id, ownerId=$ownerId, albumName=$albumName, createdAt=$createdAt, updatedAt=$updatedAt, albumThumbnailAssetId=$albumThumbnailAssetId, shared=$shared, sharedUsers=$sharedUsers, assets=$assets, owner=$owner]';
@@ -102,11 +96,7 @@ class AlbumResponseDto {
       json[r'shared'] = this.shared;
       json[r'sharedUsers'] = this.sharedUsers;
       json[r'assets'] = this.assets;
-    if (this.owner != null) {
       json[r'owner'] = this.owner;
-    } else {
-      // json[r'owner'] = null;
-    }
     return json;
   }
 
@@ -139,7 +129,7 @@ class AlbumResponseDto {
         shared: mapValueOfType<bool>(json, r'shared')!,
         sharedUsers: UserResponseDto.listFromJson(json[r'sharedUsers'])!,
         assets: AssetResponseDto.listFromJson(json[r'assets'])!,
-        owner: UserResponseDto.fromJson(json[r'owner']),
+        owner: UserResponseDto.fromJson(json[r'owner'])!,
       );
     }
     return null;
@@ -199,6 +189,7 @@ class AlbumResponseDto {
     'shared',
     'sharedUsers',
     'assets',
+    'owner',
   };
 }
 

+ 1 - 0
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,

+ 26 - 10
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>(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';

+ 2 - 1
server/immich-openapi-specs.json

@@ -3400,7 +3400,8 @@
           "albumThumbnailAssetId",
           "shared",
           "sharedUsers",
-          "assets"
+          "assets",
+          "owner"
         ]
       },
       "SharedLinkResponseDto": {

+ 3 - 3
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: [],

+ 1 - 1
web/src/api/open-api/api.ts

@@ -281,7 +281,7 @@ export interface AlbumResponseDto {
      * @type {UserResponseDto}
      * @memberof AlbumResponseDto
      */
-    'owner'?: UserResponseDto;
+    'owner': UserResponseDto;
 }
 /**
  * 

+ 2 - 1
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 @@
 			</div>
 		{/if}
 
-		{#if asset.isFavorite}
+		{#if asset.isFavorite && !isPublicShared}
 			<div class="w-full absolute bottom-2 left-2 z-10">
 				<Star size="24" color={'white'} />
 			</div>