mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 02:27:08 -04:00 
			
		
		
		
	refactor: access repository (#15490)
This commit is contained in:
		
							parent
							
								
									318dd32363
								
							
						
					
					
						commit
						b0cdd8f475
					
				| @ -1,53 +0,0 @@ | |||||||
| import { AlbumUserRole } from 'src/enum'; |  | ||||||
| 
 |  | ||||||
| export const IAccessRepository = 'IAccessRepository'; |  | ||||||
| 
 |  | ||||||
| export interface IAccessRepository { |  | ||||||
|   activity: { |  | ||||||
|     checkOwnerAccess(userId: string, activityIds: Set<string>): Promise<Set<string>>; |  | ||||||
|     checkAlbumOwnerAccess(userId: string, activityIds: Set<string>): Promise<Set<string>>; |  | ||||||
|     checkCreateAccess(userId: string, albumIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   asset: { |  | ||||||
|     checkOwnerAccess(userId: string, assetIds: Set<string>): Promise<Set<string>>; |  | ||||||
|     checkAlbumAccess(userId: string, assetIds: Set<string>): Promise<Set<string>>; |  | ||||||
|     checkPartnerAccess(userId: string, assetIds: Set<string>): Promise<Set<string>>; |  | ||||||
|     checkSharedLinkAccess(sharedLinkId: string, assetIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   authDevice: { |  | ||||||
|     checkOwnerAccess(userId: string, deviceIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   album: { |  | ||||||
|     checkOwnerAccess(userId: string, albumIds: Set<string>): Promise<Set<string>>; |  | ||||||
|     checkSharedAlbumAccess(userId: string, albumIds: Set<string>, access: AlbumUserRole): Promise<Set<string>>; |  | ||||||
|     checkSharedLinkAccess(sharedLinkId: string, albumIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   timeline: { |  | ||||||
|     checkPartnerAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   memory: { |  | ||||||
|     checkOwnerAccess(userId: string, memoryIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   person: { |  | ||||||
|     checkFaceOwnerAccess(userId: string, assetFaceId: Set<string>): Promise<Set<string>>; |  | ||||||
|     checkOwnerAccess(userId: string, personIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   partner: { |  | ||||||
|     checkUpdateAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   stack: { |  | ||||||
|     checkOwnerAccess(userId: string, stackIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   tag: { |  | ||||||
|     checkOwnerAccess(userId: string, tagIds: Set<string>): Promise<Set<string>>; |  | ||||||
|   }; |  | ||||||
| } |  | ||||||
| @ -1,33 +1,18 @@ | |||||||
| import { Injectable } from '@nestjs/common'; |  | ||||||
| import { Kysely, sql } from 'kysely'; | import { Kysely, sql } from 'kysely'; | ||||||
| import { InjectKysely } from 'nestjs-kysely'; | import { InjectKysely } from 'nestjs-kysely'; | ||||||
| import { DB } from 'src/db'; | import { DB } from 'src/db'; | ||||||
| import { ChunkedSet, DummyValue, GenerateSql } from 'src/decorators'; | import { ChunkedSet, DummyValue, GenerateSql } from 'src/decorators'; | ||||||
| 
 |  | ||||||
| import { AlbumUserRole } from 'src/enum'; | import { AlbumUserRole } from 'src/enum'; | ||||||
| import { IAccessRepository } from 'src/interfaces/access.interface'; |  | ||||||
| import { asUuid } from 'src/utils/database'; | import { asUuid } from 'src/utils/database'; | ||||||
| 
 | 
 | ||||||
| type IActivityAccess = IAccessRepository['activity']; | class ActivityAccess { | ||||||
| type IAlbumAccess = IAccessRepository['album']; |  | ||||||
| type IAssetAccess = IAccessRepository['asset']; |  | ||||||
| type IAuthDeviceAccess = IAccessRepository['authDevice']; |  | ||||||
| type IMemoryAccess = IAccessRepository['memory']; |  | ||||||
| type IPersonAccess = IAccessRepository['person']; |  | ||||||
| type IPartnerAccess = IAccessRepository['partner']; |  | ||||||
| type IStackAccess = IAccessRepository['stack']; |  | ||||||
| type ITagAccess = IAccessRepository['tag']; |  | ||||||
| type ITimelineAccess = IAccessRepository['timeline']; |  | ||||||
| 
 |  | ||||||
| @Injectable() |  | ||||||
| class ActivityAccess implements IActivityAccess { |  | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, activityIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, activityIds: Set<string>) { | ||||||
|     if (activityIds.size === 0) { |     if (activityIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -41,9 +26,9 @@ class ActivityAccess implements IActivityAccess { | |||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkAlbumOwnerAccess(userId: string, activityIds: Set<string>): Promise<Set<string>> { |   async checkAlbumOwnerAccess(userId: string, activityIds: Set<string>) { | ||||||
|     if (activityIds.size === 0) { |     if (activityIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -58,9 +43,9 @@ class ActivityAccess implements IActivityAccess { | |||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkCreateAccess(userId: string, albumIds: Set<string>): Promise<Set<string>> { |   async checkCreateAccess(userId: string, albumIds: Set<string>) { | ||||||
|     if (albumIds.size === 0) { |     if (albumIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -77,14 +62,14 @@ class ActivityAccess implements IActivityAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class AlbumAccess implements IAlbumAccess { | class AlbumAccess { | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, albumIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, albumIds: Set<string>) { | ||||||
|     if (albumIds.size === 0) { |     if (albumIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -99,9 +84,9 @@ class AlbumAccess implements IAlbumAccess { | |||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkSharedAlbumAccess(userId: string, albumIds: Set<string>, access: AlbumUserRole): Promise<Set<string>> { |   async checkSharedAlbumAccess(userId: string, albumIds: Set<string>, access: AlbumUserRole) { | ||||||
|     if (albumIds.size === 0) { |     if (albumIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const accessRole = |     const accessRole = | ||||||
| @ -122,9 +107,9 @@ class AlbumAccess implements IAlbumAccess { | |||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkSharedLinkAccess(sharedLinkId: string, albumIds: Set<string>): Promise<Set<string>> { |   async checkSharedLinkAccess(sharedLinkId: string, albumIds: Set<string>) { | ||||||
|     if (albumIds.size === 0) { |     if (albumIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -139,14 +124,14 @@ class AlbumAccess implements IAlbumAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class AssetAccess implements IAssetAccess { | class AssetAccess { | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkAlbumAccess(userId: string, assetIds: Set<string>): Promise<Set<string>> { |   async checkAlbumAccess(userId: string, assetIds: Set<string>) { | ||||||
|     if (assetIds.size === 0) { |     if (assetIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -182,9 +167,9 @@ class AssetAccess implements IAssetAccess { | |||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, assetIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, assetIds: Set<string>) { | ||||||
|     if (assetIds.size === 0) { |     if (assetIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -198,9 +183,9 @@ class AssetAccess implements IAssetAccess { | |||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkPartnerAccess(userId: string, assetIds: Set<string>): Promise<Set<string>> { |   async checkPartnerAccess(userId: string, assetIds: Set<string>) { | ||||||
|     if (assetIds.size === 0) { |     if (assetIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -221,9 +206,9 @@ class AssetAccess implements IAssetAccess { | |||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkSharedLinkAccess(sharedLinkId: string, assetIds: Set<string>): Promise<Set<string>> { |   async checkSharedLinkAccess(sharedLinkId: string, assetIds: Set<string>) { | ||||||
|     if (assetIds.size === 0) { |     if (assetIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -273,14 +258,14 @@ class AssetAccess implements IAssetAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class AuthDeviceAccess implements IAuthDeviceAccess { | class AuthDeviceAccess { | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, deviceIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, deviceIds: Set<string>) { | ||||||
|     if (deviceIds.size === 0) { |     if (deviceIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -293,14 +278,14 @@ class AuthDeviceAccess implements IAuthDeviceAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class StackAccess implements IStackAccess { | class StackAccess { | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, stackIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, stackIds: Set<string>) { | ||||||
|     if (stackIds.size === 0) { |     if (stackIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -313,14 +298,14 @@ class StackAccess implements IStackAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class TimelineAccess implements ITimelineAccess { | class TimelineAccess { | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkPartnerAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>> { |   async checkPartnerAccess(userId: string, partnerIds: Set<string>) { | ||||||
|     if (partnerIds.size === 0) { |     if (partnerIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -333,14 +318,14 @@ class TimelineAccess implements ITimelineAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class MemoryAccess implements IMemoryAccess { | class MemoryAccess { | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, memoryIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, memoryIds: Set<string>) { | ||||||
|     if (memoryIds.size === 0) { |     if (memoryIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -354,14 +339,14 @@ class MemoryAccess implements IMemoryAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class PersonAccess implements IPersonAccess { | class PersonAccess { | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, personIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, personIds: Set<string>) { | ||||||
|     if (personIds.size === 0) { |     if (personIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -375,9 +360,9 @@ class PersonAccess implements IPersonAccess { | |||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkFaceOwnerAccess(userId: string, assetFaceIds: Set<string>): Promise<Set<string>> { |   async checkFaceOwnerAccess(userId: string, assetFaceIds: Set<string>) { | ||||||
|     if (assetFaceIds.size === 0) { |     if (assetFaceIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -393,14 +378,14 @@ class PersonAccess implements IPersonAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class PartnerAccess implements IPartnerAccess { | class PartnerAccess { | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkUpdateAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>> { |   async checkUpdateAccess(userId: string, partnerIds: Set<string>) { | ||||||
|     if (partnerIds.size === 0) { |     if (partnerIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -413,14 +398,14 @@ class PartnerAccess implements IPartnerAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class TagAccess implements ITagAccess { | class TagAccess { | ||||||
|   constructor(private db: Kysely<DB>) {} |   constructor(private db: Kysely<DB>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|   @ChunkedSet({ paramIndex: 1 }) |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, tagIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, tagIds: Set<string>) { | ||||||
|     if (tagIds.size === 0) { |     if (tagIds.size === 0) { | ||||||
|       return new Set(); |       return new Set<string>(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.db |     return this.db | ||||||
| @ -433,17 +418,17 @@ class TagAccess implements ITagAccess { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class AccessRepository implements IAccessRepository { | export class AccessRepository { | ||||||
|   activity: IActivityAccess; |   activity: ActivityAccess; | ||||||
|   album: IAlbumAccess; |   album: AlbumAccess; | ||||||
|   asset: IAssetAccess; |   asset: AssetAccess; | ||||||
|   authDevice: IAuthDeviceAccess; |   authDevice: AuthDeviceAccess; | ||||||
|   memory: IMemoryAccess; |   memory: MemoryAccess; | ||||||
|   person: IPersonAccess; |   person: PersonAccess; | ||||||
|   partner: IPartnerAccess; |   partner: PartnerAccess; | ||||||
|   stack: IStackAccess; |   stack: StackAccess; | ||||||
|   tag: ITagAccess; |   tag: TagAccess; | ||||||
|   timeline: ITimelineAccess; |   timeline: TimelineAccess; | ||||||
| 
 | 
 | ||||||
|   constructor(@InjectKysely() db: Kysely<DB>) { |   constructor(@InjectKysely() db: Kysely<DB>) { | ||||||
|     this.activity = new ActivityAccess(db); |     this.activity = new ActivityAccess(db); | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| import { IAccessRepository } from 'src/interfaces/access.interface'; |  | ||||||
| import { IAlbumUserRepository } from 'src/interfaces/album-user.interface'; | import { IAlbumUserRepository } from 'src/interfaces/album-user.interface'; | ||||||
| import { IAlbumRepository } from 'src/interfaces/album.interface'; | import { IAlbumRepository } from 'src/interfaces/album.interface'; | ||||||
| import { IKeyRepository } from 'src/interfaces/api-key.interface'; | import { IKeyRepository } from 'src/interfaces/api-key.interface'; | ||||||
| @ -78,11 +77,11 @@ import { ViewRepository } from 'src/repositories/view-repository'; | |||||||
| 
 | 
 | ||||||
| export const repositories = [ | export const repositories = [ | ||||||
|   //
 |   //
 | ||||||
|  |   AccessRepository, | ||||||
|   ActivityRepository, |   ActivityRepository, | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| export const providers = [ | export const providers = [ | ||||||
|   { provide: IAccessRepository, useClass: AccessRepository }, |  | ||||||
|   { provide: IAlbumRepository, useClass: AlbumRepository }, |   { provide: IAlbumRepository, useClass: AlbumRepository }, | ||||||
|   { provide: IAlbumUserRepository, useClass: AlbumUserRepository }, |   { provide: IAlbumUserRepository, useClass: AlbumUserRepository }, | ||||||
|   { provide: IAssetRepository, useClass: AssetRepository }, |   { provide: IAssetRepository, useClass: AssetRepository }, | ||||||
|  | |||||||
| @ -6,7 +6,6 @@ import { SALT_ROUNDS } from 'src/constants'; | |||||||
| import { StorageCore } from 'src/cores/storage.core'; | import { StorageCore } from 'src/cores/storage.core'; | ||||||
| import { Users } from 'src/db'; | import { Users } from 'src/db'; | ||||||
| import { UserEntity } from 'src/entities/user.entity'; | import { UserEntity } from 'src/entities/user.entity'; | ||||||
| import { IAccessRepository } from 'src/interfaces/access.interface'; |  | ||||||
| import { IAlbumUserRepository } from 'src/interfaces/album-user.interface'; | import { IAlbumUserRepository } from 'src/interfaces/album-user.interface'; | ||||||
| import { IAlbumRepository } from 'src/interfaces/album.interface'; | import { IAlbumRepository } from 'src/interfaces/album.interface'; | ||||||
| import { IKeyRepository } from 'src/interfaces/api-key.interface'; | import { IKeyRepository } from 'src/interfaces/api-key.interface'; | ||||||
| @ -44,6 +43,7 @@ import { ITrashRepository } from 'src/interfaces/trash.interface'; | |||||||
| import { IUserRepository } from 'src/interfaces/user.interface'; | import { IUserRepository } from 'src/interfaces/user.interface'; | ||||||
| import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface'; | import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface'; | ||||||
| import { IViewRepository } from 'src/interfaces/view.interface'; | import { IViewRepository } from 'src/interfaces/view.interface'; | ||||||
|  | import { AccessRepository } from 'src/repositories/access.repository'; | ||||||
| import { ActivityRepository } from 'src/repositories/activity.repository'; | import { ActivityRepository } from 'src/repositories/activity.repository'; | ||||||
| import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access'; | import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access'; | ||||||
| import { getConfig, updateConfig } from 'src/utils/config'; | import { getConfig, updateConfig } from 'src/utils/config'; | ||||||
| @ -53,7 +53,7 @@ export class BaseService { | |||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     @Inject(ILoggerRepository) protected logger: ILoggerRepository, |     @Inject(ILoggerRepository) protected logger: ILoggerRepository, | ||||||
|     @Inject(IAccessRepository) protected accessRepository: IAccessRepository, |     protected accessRepository: AccessRepository, | ||||||
|     protected activityRepository: ActivityRepository, |     protected activityRepository: ActivityRepository, | ||||||
|     @Inject(IAuditRepository) protected auditRepository: IAuditRepository, |     @Inject(IAuditRepository) protected auditRepository: IAuditRepository, | ||||||
|     @Inject(IAlbumRepository) protected albumRepository: IAlbumRepository, |     @Inject(IAlbumRepository) protected albumRepository: IAlbumRepository, | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| import { UserEntity } from 'src/entities/user.entity'; | import { UserEntity } from 'src/entities/user.entity'; | ||||||
| import { Permission } from 'src/enum'; | import { Permission } from 'src/enum'; | ||||||
|  | import { AccessRepository } from 'src/repositories/access.repository'; | ||||||
| import { ActivityRepository } from 'src/repositories/activity.repository'; | import { ActivityRepository } from 'src/repositories/activity.repository'; | ||||||
| 
 | 
 | ||||||
| export type AuthApiKey = { | export type AuthApiKey = { | ||||||
| @ -12,6 +13,7 @@ export type AuthApiKey = { | |||||||
| export type RepositoryInterface<T extends object> = Pick<T, keyof T>; | export type RepositoryInterface<T extends object> = Pick<T, keyof T>; | ||||||
| 
 | 
 | ||||||
| export type IActivityRepository = RepositoryInterface<ActivityRepository>; | export type IActivityRepository = RepositoryInterface<ActivityRepository>; | ||||||
|  | export type IAccessRepository = { [K in keyof AccessRepository]: RepositoryInterface<AccessRepository[K]> }; | ||||||
| 
 | 
 | ||||||
| export type ActivityItem = | export type ActivityItem = | ||||||
|   | Awaited<ReturnType<IActivityRepository['create']>> |   | Awaited<ReturnType<IActivityRepository['create']>> | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import { BadRequestException, UnauthorizedException } from '@nestjs/common'; | |||||||
| import { AuthDto } from 'src/dtos/auth.dto'; | import { AuthDto } from 'src/dtos/auth.dto'; | ||||||
| import { SharedLinkEntity } from 'src/entities/shared-link.entity'; | import { SharedLinkEntity } from 'src/entities/shared-link.entity'; | ||||||
| import { AlbumUserRole, Permission } from 'src/enum'; | import { AlbumUserRole, Permission } from 'src/enum'; | ||||||
| import { IAccessRepository } from 'src/interfaces/access.interface'; | import { AccessRepository } from 'src/repositories/access.repository'; | ||||||
| import { setDifference, setIsEqual, setIsSuperset, setUnion } from 'src/utils/set'; | import { setDifference, setIsEqual, setIsSuperset, setUnion } from 'src/utils/set'; | ||||||
| 
 | 
 | ||||||
| export type GrantedRequest = { | export type GrantedRequest = { | ||||||
| @ -34,7 +34,7 @@ export const requireUploadAccess = (auth: AuthDto | null): AuthDto => { | |||||||
|   return auth; |   return auth; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const requireAccess = async (access: IAccessRepository, request: AccessRequest) => { | export const requireAccess = async (access: AccessRepository, request: AccessRequest) => { | ||||||
|   const allowedIds = await checkAccess(access, request); |   const allowedIds = await checkAccess(access, request); | ||||||
|   if (!setIsEqual(new Set(request.ids), allowedIds)) { |   if (!setIsEqual(new Set(request.ids), allowedIds)) { | ||||||
|     throw new BadRequestException(`Not found or no ${request.permission} access`); |     throw new BadRequestException(`Not found or no ${request.permission} access`); | ||||||
| @ -42,7 +42,7 @@ export const requireAccess = async (access: IAccessRepository, request: AccessRe | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const checkAccess = async ( | export const checkAccess = async ( | ||||||
|   access: IAccessRepository, |   access: AccessRepository, | ||||||
|   { ids, auth, permission }: AccessRequest, |   { ids, auth, permission }: AccessRequest, | ||||||
| ): Promise<Set<string>> => { | ): Promise<Set<string>> => { | ||||||
|   const idSet = Array.isArray(ids) ? new Set(ids) : ids; |   const idSet = Array.isArray(ids) ? new Set(ids) : ids; | ||||||
| @ -56,7 +56,7 @@ export const checkAccess = async ( | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const checkSharedLinkAccess = async ( | const checkSharedLinkAccess = async ( | ||||||
|   access: IAccessRepository, |   access: AccessRepository, | ||||||
|   request: SharedLinkAccessRequest, |   request: SharedLinkAccessRequest, | ||||||
| ): Promise<Set<string>> => { | ): Promise<Set<string>> => { | ||||||
|   const { sharedLink, permission, ids } = request; |   const { sharedLink, permission, ids } = request; | ||||||
| @ -102,7 +102,7 @@ const checkSharedLinkAccess = async ( | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const checkOtherAccess = async (access: IAccessRepository, request: OtherAccessRequest): Promise<Set<string>> => { | const checkOtherAccess = async (access: AccessRepository, request: OtherAccessRequest): Promise<Set<string>> => { | ||||||
|   const { auth, permission, ids } = request; |   const { auth, permission, ids } = request; | ||||||
| 
 | 
 | ||||||
|   switch (permission) { |   switch (permission) { | ||||||
|  | |||||||
| @ -5,12 +5,12 @@ import { UploadFieldName } from 'src/dtos/asset-media.dto'; | |||||||
| import { AuthDto } from 'src/dtos/auth.dto'; | import { AuthDto } from 'src/dtos/auth.dto'; | ||||||
| import { AssetFileEntity } from 'src/entities/asset-files.entity'; | import { AssetFileEntity } from 'src/entities/asset-files.entity'; | ||||||
| import { AssetFileType, AssetType, Permission } from 'src/enum'; | import { AssetFileType, AssetType, Permission } from 'src/enum'; | ||||||
| import { IAccessRepository } from 'src/interfaces/access.interface'; |  | ||||||
| import { IAssetRepository } from 'src/interfaces/asset.interface'; | import { IAssetRepository } from 'src/interfaces/asset.interface'; | ||||||
| import { IEventRepository } from 'src/interfaces/event.interface'; | import { IEventRepository } from 'src/interfaces/event.interface'; | ||||||
| import { IPartnerRepository } from 'src/interfaces/partner.interface'; | import { IPartnerRepository } from 'src/interfaces/partner.interface'; | ||||||
| import { AuthRequest } from 'src/middleware/auth.guard'; | import { AuthRequest } from 'src/middleware/auth.guard'; | ||||||
| import { ImmichFile } from 'src/middleware/file-upload.interceptor'; | import { ImmichFile } from 'src/middleware/file-upload.interceptor'; | ||||||
|  | import { AccessRepository } from 'src/repositories/access.repository'; | ||||||
| import { UploadFile } from 'src/services/asset-media.service'; | import { UploadFile } from 'src/services/asset-media.service'; | ||||||
| import { checkAccess } from 'src/utils/access'; | import { checkAccess } from 'src/utils/access'; | ||||||
| 
 | 
 | ||||||
| @ -31,7 +31,7 @@ export const getAssetFiles = (files?: AssetFileEntity[]) => ({ | |||||||
| 
 | 
 | ||||||
| export const addAssets = async ( | export const addAssets = async ( | ||||||
|   auth: AuthDto, |   auth: AuthDto, | ||||||
|   repositories: { access: IAccessRepository; bulk: IBulkAsset }, |   repositories: { access: AccessRepository; bulk: IBulkAsset }, | ||||||
|   dto: { parentId: string; assetIds: string[] }, |   dto: { parentId: string; assetIds: string[] }, | ||||||
| ) => { | ) => { | ||||||
|   const { access, bulk } = repositories; |   const { access, bulk } = repositories; | ||||||
| @ -71,7 +71,7 @@ export const addAssets = async ( | |||||||
| 
 | 
 | ||||||
| export const removeAssets = async ( | export const removeAssets = async ( | ||||||
|   auth: AuthDto, |   auth: AuthDto, | ||||||
|   repositories: { access: IAccessRepository; bulk: IBulkAsset }, |   repositories: { access: AccessRepository; bulk: IBulkAsset }, | ||||||
|   dto: { parentId: string; assetIds: string[]; canAlwaysRemove: Permission }, |   dto: { parentId: string; assetIds: string[]; canAlwaysRemove: Permission }, | ||||||
| ) => { | ) => { | ||||||
|   const { access, bulk } = repositories; |   const { access, bulk } = repositories; | ||||||
|  | |||||||
| @ -1,18 +1,7 @@ | |||||||
| import { IAccessRepository } from 'src/interfaces/access.interface'; | import { IAccessRepository } from 'src/types'; | ||||||
| import { Mocked, vitest } from 'vitest'; | import { Mocked, vitest } from 'vitest'; | ||||||
| 
 | 
 | ||||||
| export interface IAccessRepositoryMock { | export type IAccessRepositoryMock = { [K in keyof IAccessRepository]: Mocked<IAccessRepository[K]> }; | ||||||
|   activity: Mocked<IAccessRepository['activity']>; |  | ||||||
|   asset: Mocked<IAccessRepository['asset']>; |  | ||||||
|   album: Mocked<IAccessRepository['album']>; |  | ||||||
|   authDevice: Mocked<IAccessRepository['authDevice']>; |  | ||||||
|   memory: Mocked<IAccessRepository['memory']>; |  | ||||||
|   person: Mocked<IAccessRepository['person']>; |  | ||||||
|   partner: Mocked<IAccessRepository['partner']>; |  | ||||||
|   stack: Mocked<IAccessRepository['stack']>; |  | ||||||
|   timeline: Mocked<IAccessRepository['timeline']>; |  | ||||||
|   tag: Mocked<IAccessRepository['tag']>; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| export const newAccessRepositoryMock = (): IAccessRepositoryMock => { | export const newAccessRepositoryMock = (): IAccessRepositoryMock => { | ||||||
|   return { |   return { | ||||||
|  | |||||||
| @ -3,9 +3,10 @@ import { Writable } from 'node:stream'; | |||||||
| import { PNG } from 'pngjs'; | import { PNG } from 'pngjs'; | ||||||
| import { ImmichWorker } from 'src/enum'; | import { ImmichWorker } from 'src/enum'; | ||||||
| import { IMetadataRepository } from 'src/interfaces/metadata.interface'; | import { IMetadataRepository } from 'src/interfaces/metadata.interface'; | ||||||
|  | import { AccessRepository } from 'src/repositories/access.repository'; | ||||||
| import { ActivityRepository } from 'src/repositories/activity.repository'; | import { ActivityRepository } from 'src/repositories/activity.repository'; | ||||||
| import { BaseService } from 'src/services/base.service'; | import { BaseService } from 'src/services/base.service'; | ||||||
| import { IActivityRepository } from 'src/types'; | import { IAccessRepository, IActivityRepository } from 'src/types'; | ||||||
| import { newAccessRepositoryMock } from 'test/repositories/access.repository.mock'; | import { newAccessRepositoryMock } from 'test/repositories/access.repository.mock'; | ||||||
| import { newActivityRepositoryMock } from 'test/repositories/activity.repository.mock'; | import { newActivityRepositoryMock } from 'test/repositories/activity.repository.mock'; | ||||||
| import { newAlbumUserRepositoryMock } from 'test/repositories/album-user.repository.mock'; | import { newAlbumUserRepositoryMock } from 'test/repositories/album-user.repository.mock'; | ||||||
| @ -105,7 +106,7 @@ export const newTestService = <T extends BaseService>( | |||||||
| 
 | 
 | ||||||
|   const sut = new Service( |   const sut = new Service( | ||||||
|     loggerMock, |     loggerMock, | ||||||
|     accessMock, |     accessMock as IAccessRepository as AccessRepository, | ||||||
|     activityMock as IActivityRepository as ActivityRepository, |     activityMock as IActivityRepository as ActivityRepository, | ||||||
|     auditMock, |     auditMock, | ||||||
|     albumMock, |     albumMock, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user