mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -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