diff --git a/server/src/services/activity.service.ts b/server/src/services/activity.service.ts index 4e17baebc3..fce104ecbd 100644 --- a/server/src/services/activity.service.ts +++ b/server/src/services/activity.service.ts @@ -14,12 +14,11 @@ import { AuthDto } from 'src/dtos/auth.dto'; import { ActivityEntity } from 'src/entities/activity.entity'; import { Permission } from 'src/enum'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; @Injectable() export class ActivityService extends BaseService { async getAll(auth: AuthDto, dto: ActivitySearchDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_READ, ids: [dto.albumId] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_READ, ids: [dto.albumId] }); const activities = await this.activityRepository.search({ userId: dto.userId, albumId: dto.albumId, @@ -31,12 +30,12 @@ export class ActivityService extends BaseService { } async getStatistics(auth: AuthDto, dto: ActivityDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_READ, ids: [dto.albumId] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_READ, ids: [dto.albumId] }); return { comments: await this.activityRepository.getStatistics(dto.assetId, dto.albumId) }; } async create(auth: AuthDto, dto: ActivityCreateDto): Promise> { - await requireAccess(this.accessRepository, { auth, permission: Permission.ACTIVITY_CREATE, ids: [dto.albumId] }); + await this.requireAccess({ auth, permission: Permission.ACTIVITY_CREATE, ids: [dto.albumId] }); const common = { userId: auth.user.id, @@ -70,7 +69,7 @@ export class ActivityService extends BaseService { } async delete(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ACTIVITY_DELETE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ACTIVITY_DELETE, ids: [id] }); await this.activityRepository.delete(id); } } diff --git a/server/src/services/album.service.ts b/server/src/services/album.service.ts index a9a678d605..e8acce9b6c 100644 --- a/server/src/services/album.service.ts +++ b/server/src/services/album.service.ts @@ -19,7 +19,6 @@ import { AssetEntity } from 'src/entities/asset.entity'; import { Permission } from 'src/enum'; import { AlbumAssetCount, AlbumInfoOptions } from 'src/interfaces/album.interface'; import { BaseService } from 'src/services/base.service'; -import { checkAccess, requireAccess } from 'src/utils/access'; import { addAssets, removeAssets } from 'src/utils/asset.util'; @Injectable() @@ -82,7 +81,7 @@ export class AlbumService extends BaseService { } async get(auth: AuthDto, id: string, dto: AlbumInfoDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_READ, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_READ, ids: [id] }); await this.albumRepository.updateThumbnails(); const withAssets = dto.withoutAssets === undefined ? true : !dto.withoutAssets; const album = await this.findOrFail(id, { withAssets }); @@ -106,7 +105,7 @@ export class AlbumService extends BaseService { } } - const allowedAssetIdsSet = await checkAccess(this.accessRepository, { + const allowedAssetIdsSet = await this.checkAccess({ auth, permission: Permission.ASSET_SHARE, ids: dto.assetIds || [], @@ -130,7 +129,7 @@ export class AlbumService extends BaseService { } async update(auth: AuthDto, id: string, dto: UpdateAlbumDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_UPDATE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_UPDATE, ids: [id] }); const album = await this.findOrFail(id, { withAssets: true }); @@ -153,13 +152,13 @@ export class AlbumService extends BaseService { } async delete(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_DELETE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_DELETE, ids: [id] }); await this.albumRepository.delete(id); } async addAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise { const album = await this.findOrFail(id, { withAssets: false }); - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_ADD_ASSET, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_ADD_ASSET, ids: [id] }); const results = await addAssets( auth, @@ -182,7 +181,7 @@ export class AlbumService extends BaseService { } async removeAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_REMOVE_ASSET, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_REMOVE_ASSET, ids: [id] }); const album = await this.findOrFail(id, { withAssets: false }); const results = await removeAssets( @@ -203,7 +202,7 @@ export class AlbumService extends BaseService { } async addUsers(auth: AuthDto, id: string, { albumUsers }: AddUsersDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_SHARE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_SHARE, ids: [id] }); const album = await this.findOrFail(id, { withAssets: false }); @@ -247,14 +246,14 @@ export class AlbumService extends BaseService { // non-admin can remove themselves if (auth.user.id !== userId) { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_SHARE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_SHARE, ids: [id] }); } await this.albumUserRepository.delete({ albumId: id, userId }); } async updateUser(auth: AuthDto, id: string, userId: string, dto: Partial): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_SHARE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_SHARE, ids: [id] }); await this.albumUserRepository.update({ albumId: id, userId }, { role: dto.role }); } diff --git a/server/src/services/asset-media.service.ts b/server/src/services/asset-media.service.ts index b320c32a21..70f4905de3 100644 --- a/server/src/services/asset-media.service.ts +++ b/server/src/services/asset-media.service.ts @@ -24,7 +24,7 @@ import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity } from 'src/entities/asset.entit import { AssetStatus, AssetType, CacheControl, Permission, StorageFolder } from 'src/enum'; import { JobName } from 'src/interfaces/job.interface'; import { BaseService } from 'src/services/base.service'; -import { requireAccess, requireUploadAccess } from 'src/utils/access'; +import { requireUploadAccess } from 'src/utils/access'; import { getAssetFiles, onBeforeLink } from 'src/utils/asset.util'; import { ImmichFileResponse } from 'src/utils/file'; import { mimeTypes } from 'src/utils/mime-types'; @@ -125,7 +125,7 @@ export class AssetMediaService extends BaseService { sidecarFile?: UploadFile, ): Promise { try { - await requireAccess(this.accessRepository, { + await this.requireAccess({ auth, permission: Permission.ASSET_UPLOAD, // do not need an id here, but the interface requires it @@ -159,7 +159,7 @@ export class AssetMediaService extends BaseService { sidecarFile?: UploadFile, ): Promise { try { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_UPDATE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ASSET_UPDATE, ids: [id] }); const asset = (await this.assetRepository.getById(id)) as AssetEntity; this.requireQuota(auth, file.size); @@ -182,7 +182,7 @@ export class AssetMediaService extends BaseService { } async downloadOriginal(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_DOWNLOAD, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ASSET_DOWNLOAD, ids: [id] }); const asset = await this.findOrFail(id); @@ -194,7 +194,7 @@ export class AssetMediaService extends BaseService { } async viewThumbnail(auth: AuthDto, id: string, dto: AssetMediaOptionsDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_VIEW, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ASSET_VIEW, ids: [id] }); const asset = await this.findOrFail(id); const size = dto.size ?? AssetMediaSize.THUMBNAIL; @@ -217,7 +217,7 @@ export class AssetMediaService extends BaseService { } async playbackVideo(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_VIEW, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ASSET_VIEW, ids: [id] }); const asset = await this.findOrFail(id); diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts index 5fef742f5a..2f31806e81 100644 --- a/server/src/services/asset.service.ts +++ b/server/src/services/asset.service.ts @@ -29,7 +29,6 @@ import { JobStatus, } from 'src/interfaces/job.interface'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; import { getAssetFiles, getMyPartnerIds, onAfterUnlink, onBeforeLink, onBeforeUnlink } from 'src/utils/asset.util'; import { usePagination } from 'src/utils/pagination'; @@ -86,7 +85,7 @@ export class AssetService extends BaseService { } async get(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_READ, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ASSET_READ, ids: [id] }); const asset = await this.assetRepository.getById( id, @@ -135,7 +134,7 @@ export class AssetService extends BaseService { } async update(auth: AuthDto, id: string, dto: UpdateAssetDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_UPDATE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.ASSET_UPDATE, ids: [id] }); const { description, dateTimeOriginal, latitude, longitude, rating, ...rest } = dto; const repos = { asset: this.assetRepository, event: this.eventRepository }; @@ -178,7 +177,7 @@ export class AssetService extends BaseService { async updateAll(auth: AuthDto, dto: AssetBulkUpdateDto): Promise { const { ids, dateTimeOriginal, latitude, longitude, ...options } = dto; - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_UPDATE, ids }); + await this.requireAccess({ auth, permission: Permission.ASSET_UPDATE, ids }); for (const id of ids) { await this.updateMetadata({ id, dateTimeOriginal, latitude, longitude }); @@ -275,7 +274,7 @@ export class AssetService extends BaseService { async deleteAll(auth: AuthDto, dto: AssetBulkDeleteDto): Promise { const { ids, force } = dto; - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_DELETE, ids }); + await this.requireAccess({ auth, permission: Permission.ASSET_DELETE, ids }); await this.assetRepository.updateAll(ids, { deletedAt: new Date(), status: force ? AssetStatus.DELETED : AssetStatus.TRASHED, @@ -284,7 +283,7 @@ export class AssetService extends BaseService { } async run(auth: AuthDto, dto: AssetJobsDto) { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_UPDATE, ids: dto.assetIds }); + await this.requireAccess({ auth, permission: Permission.ASSET_UPDATE, ids: dto.assetIds }); const jobs: JobItem[] = []; diff --git a/server/src/services/audit.service.ts b/server/src/services/audit.service.ts index 60f8d6fa81..d891c88b39 100644 --- a/server/src/services/audit.service.ts +++ b/server/src/services/audit.service.ts @@ -23,7 +23,6 @@ import { } from 'src/enum'; import { JOBS_ASSET_PAGINATION_SIZE, JobStatus } from 'src/interfaces/job.interface'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; import { getAssetFiles } from 'src/utils/asset.util'; import { usePagination } from 'src/utils/pagination'; @@ -36,7 +35,7 @@ export class AuditService extends BaseService { async getDeletes(auth: AuthDto, dto: AuditDeletesDto): Promise { const userId = dto.userId || auth.user.id; - await requireAccess(this.accessRepository, { auth, permission: Permission.TIMELINE_READ, ids: [userId] }); + await this.requireAccess({ auth, permission: Permission.TIMELINE_READ, ids: [userId] }); const audits = await this.auditRepository.getAfter(dto.after, { userIds: [userId], diff --git a/server/src/services/base.service.ts b/server/src/services/base.service.ts index e98f88ade1..2bb717b45b 100644 --- a/server/src/services/base.service.ts +++ b/server/src/services/base.service.ts @@ -38,6 +38,7 @@ import { ITrashRepository } from 'src/interfaces/trash.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface'; import { IViewRepository } from 'src/interfaces/view.interface'; +import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access'; import { getConfig, updateConfig } from 'src/utils/config'; export class BaseService { @@ -95,7 +96,7 @@ export class BaseService { ); } - private get repos() { + private get configRepos() { return { configRepo: this.configRepository, metadataRepo: this.systemMetadataRepository, @@ -104,10 +105,18 @@ export class BaseService { } getConfig(options: { withCache: boolean }) { - return getConfig(this.repos, options); + return getConfig(this.configRepos, options); } updateConfig(newConfig: SystemConfig) { - return updateConfig(this.repos, newConfig); + return updateConfig(this.configRepos, newConfig); + } + + requireAccess(request: AccessRequest) { + return requireAccess(this.accessRepository, request); + } + + checkAccess(request: AccessRequest) { + return checkAccess(this.accessRepository, request); } } diff --git a/server/src/services/download.service.ts b/server/src/services/download.service.ts index d8ad67044e..3d66f009cf 100644 --- a/server/src/services/download.service.ts +++ b/server/src/services/download.service.ts @@ -8,7 +8,6 @@ import { AssetEntity } from 'src/entities/asset.entity'; import { Permission } from 'src/enum'; import { ImmichReadStream } from 'src/interfaces/storage.interface'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; import { HumanReadableSize } from 'src/utils/bytes'; import { usePagination } from 'src/utils/pagination'; import { getPreferences } from 'src/utils/preferences'; @@ -62,7 +61,7 @@ export class DownloadService extends BaseService { } async downloadArchive(auth: AuthDto, dto: AssetIdsDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_DOWNLOAD, ids: dto.assetIds }); + await this.requireAccess({ auth, permission: Permission.ASSET_DOWNLOAD, ids: dto.assetIds }); const zip = this.storageRepository.createZipStream(); const assets = await this.assetRepository.getByIds(dto.assetIds); @@ -105,20 +104,20 @@ export class DownloadService extends BaseService { if (dto.assetIds) { const assetIds = dto.assetIds; - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_DOWNLOAD, ids: assetIds }); + await this.requireAccess({ auth, permission: Permission.ASSET_DOWNLOAD, ids: assetIds }); const assets = await this.assetRepository.getByIds(assetIds, { exifInfo: true }); return usePagination(PAGINATION_SIZE, () => ({ hasNextPage: false, items: assets })); } if (dto.albumId) { const albumId = dto.albumId; - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_DOWNLOAD, ids: [albumId] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_DOWNLOAD, ids: [albumId] }); return usePagination(PAGINATION_SIZE, (pagination) => this.assetRepository.getByAlbumId(pagination, albumId)); } if (dto.userId) { const userId = dto.userId; - await requireAccess(this.accessRepository, { auth, permission: Permission.TIMELINE_DOWNLOAD, ids: [userId] }); + await this.requireAccess({ auth, permission: Permission.TIMELINE_DOWNLOAD, ids: [userId] }); return usePagination(PAGINATION_SIZE, (pagination) => this.assetRepository.getByUserId(pagination, userId, { isVisible: true }), ); diff --git a/server/src/services/memory.service.ts b/server/src/services/memory.service.ts index f7d1ead6aa..816b0fddeb 100644 --- a/server/src/services/memory.service.ts +++ b/server/src/services/memory.service.ts @@ -5,7 +5,6 @@ import { MemoryCreateDto, MemoryResponseDto, MemoryUpdateDto, mapMemory } from ' import { AssetEntity } from 'src/entities/asset.entity'; import { Permission } from 'src/enum'; import { BaseService } from 'src/services/base.service'; -import { checkAccess, requireAccess } from 'src/utils/access'; import { addAssets, removeAssets } from 'src/utils/asset.util'; @Injectable() @@ -16,7 +15,7 @@ export class MemoryService extends BaseService { } async get(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.MEMORY_READ, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.MEMORY_READ, ids: [id] }); const memory = await this.findOrFail(id); return mapMemory(memory); } @@ -25,7 +24,7 @@ export class MemoryService extends BaseService { // TODO validate type/data combination const assetIds = dto.assetIds || []; - const allowedAssetIds = await checkAccess(this.accessRepository, { + const allowedAssetIds = await this.checkAccess({ auth, permission: Permission.ASSET_SHARE, ids: assetIds, @@ -44,7 +43,7 @@ export class MemoryService extends BaseService { } async update(auth: AuthDto, id: string, dto: MemoryUpdateDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.MEMORY_UPDATE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.MEMORY_UPDATE, ids: [id] }); const memory = await this.memoryRepository.update({ id, @@ -57,12 +56,12 @@ export class MemoryService extends BaseService { } async remove(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.MEMORY_DELETE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.MEMORY_DELETE, ids: [id] }); await this.memoryRepository.delete(id); } async addAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.MEMORY_READ, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.MEMORY_READ, ids: [id] }); const repos = { access: this.accessRepository, bulk: this.memoryRepository }; const results = await addAssets(auth, repos, { parentId: id, assetIds: dto.ids }); @@ -76,7 +75,7 @@ export class MemoryService extends BaseService { } async removeAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.MEMORY_UPDATE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.MEMORY_UPDATE, ids: [id] }); const repos = { access: this.accessRepository, bulk: this.memoryRepository }; const results = await removeAssets(auth, repos, { diff --git a/server/src/services/partner.service.ts b/server/src/services/partner.service.ts index 39907ec5fe..ee36f1ce45 100644 --- a/server/src/services/partner.service.ts +++ b/server/src/services/partner.service.ts @@ -6,7 +6,6 @@ import { PartnerEntity } from 'src/entities/partner.entity'; import { Permission } from 'src/enum'; import { PartnerDirection, PartnerIds } from 'src/interfaces/partner.interface'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; @Injectable() export class PartnerService extends BaseService { @@ -41,7 +40,7 @@ export class PartnerService extends BaseService { } async update(auth: AuthDto, sharedById: string, dto: UpdatePartnerDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.PARTNER_UPDATE, ids: [sharedById] }); + await this.requireAccess({ auth, permission: Permission.PARTNER_UPDATE, ids: [sharedById] }); const partnerId: PartnerIds = { sharedById, sharedWithId: auth.user.id }; const entity = await this.partnerRepository.update({ ...partnerId, inTimeline: dto.inTimeline }); diff --git a/server/src/services/person.service.ts b/server/src/services/person.service.ts index 624fb46b6d..e5f016d8ef 100644 --- a/server/src/services/person.service.ts +++ b/server/src/services/person.service.ts @@ -47,7 +47,6 @@ import { BoundingBox } from 'src/interfaces/machine-learning.interface'; import { CropOptions, ImageDimensions, InputDimensions } from 'src/interfaces/media.interface'; import { UpdateFacesData } from 'src/interfaces/person.interface'; import { BaseService } from 'src/services/base.service'; -import { checkAccess, requireAccess } from 'src/utils/access'; import { getAssetFiles } from 'src/utils/asset.util'; import { ImmichFileResponse } from 'src/utils/file'; import { mimeTypes } from 'src/utils/mime-types'; @@ -80,7 +79,7 @@ export class PersonService extends BaseService { } async reassignFaces(auth: AuthDto, personId: string, dto: AssetFaceUpdateDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.PERSON_UPDATE, ids: [personId] }); + await this.requireAccess({ auth, permission: Permission.PERSON_UPDATE, ids: [personId] }); const person = await this.findOrFail(personId); const result: PersonResponseDto[] = []; const changeFeaturePhoto: string[] = []; @@ -88,7 +87,7 @@ export class PersonService extends BaseService { const faces = await this.personRepository.getFacesByIds([{ personId: data.personId, assetId: data.assetId }]); for (const face of faces) { - await requireAccess(this.accessRepository, { auth, permission: Permission.PERSON_CREATE, ids: [face.id] }); + await this.requireAccess({ auth, permission: Permission.PERSON_CREATE, ids: [face.id] }); if (person.faceAssetId === null) { changeFeaturePhoto.push(person.id); } @@ -109,8 +108,8 @@ export class PersonService extends BaseService { } async reassignFacesById(auth: AuthDto, personId: string, dto: FaceDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.PERSON_UPDATE, ids: [personId] }); - await requireAccess(this.accessRepository, { auth, permission: Permission.PERSON_CREATE, ids: [dto.id] }); + await this.requireAccess({ auth, permission: Permission.PERSON_UPDATE, ids: [personId] }); + await this.requireAccess({ auth, permission: Permission.PERSON_CREATE, ids: [dto.id] }); const face = await this.personRepository.getFaceById(dto.id); const person = await this.findOrFail(personId); @@ -126,7 +125,7 @@ export class PersonService extends BaseService { } async getFacesById(auth: AuthDto, dto: FaceDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_READ, ids: [dto.id] }); + await this.requireAccess({ auth, permission: Permission.ASSET_READ, ids: [dto.id] }); const faces = await this.personRepository.getFaces(dto.id); return faces.map((asset) => mapFaces(asset, auth)); } @@ -150,17 +149,17 @@ export class PersonService extends BaseService { } async getById(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.PERSON_READ, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.PERSON_READ, ids: [id] }); return this.findOrFail(id).then(mapPerson); } async getStatistics(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.PERSON_READ, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.PERSON_READ, ids: [id] }); return this.personRepository.getStatistics(id); } async getThumbnail(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.PERSON_READ, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.PERSON_READ, ids: [id] }); const person = await this.personRepository.getById(id); if (!person || !person.thumbnailPath) { throw new NotFoundException(); @@ -183,13 +182,13 @@ export class PersonService extends BaseService { } async update(auth: AuthDto, id: string, dto: PersonUpdateDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.PERSON_UPDATE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.PERSON_UPDATE, ids: [id] }); const { name, birthDate, isHidden, featureFaceAssetId: assetId } = dto; // TODO: set by faceId directly let faceId: string | undefined = undefined; if (assetId) { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_READ, ids: [assetId] }); + await this.requireAccess({ auth, permission: Permission.ASSET_READ, ids: [assetId] }); const [face] = await this.personRepository.getFacesByIds([{ personId: id, assetId }]); if (!face) { throw new BadRequestException('Invalid assetId for feature face'); @@ -584,13 +583,13 @@ export class PersonService extends BaseService { throw new BadRequestException('Cannot merge a person into themselves'); } - await requireAccess(this.accessRepository, { auth, permission: Permission.PERSON_UPDATE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.PERSON_UPDATE, ids: [id] }); let primaryPerson = await this.findOrFail(id); const primaryName = primaryPerson.name || primaryPerson.id; const results: BulkIdResponseDto[] = []; - const allowedIds = await checkAccess(this.accessRepository, { + const allowedIds = await this.checkAccess({ auth, permission: Permission.PERSON_MERGE, ids: mergeIds, diff --git a/server/src/services/session.service.ts b/server/src/services/session.service.ts index c68fb3088c..2e27942c66 100644 --- a/server/src/services/session.service.ts +++ b/server/src/services/session.service.ts @@ -5,7 +5,6 @@ import { SessionResponseDto, mapSession } from 'src/dtos/session.dto'; import { Permission } from 'src/enum'; import { JobStatus } from 'src/interfaces/job.interface'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; @Injectable() export class SessionService extends BaseService { @@ -34,7 +33,7 @@ export class SessionService extends BaseService { } async delete(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.AUTH_DEVICE_DELETE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.AUTH_DEVICE_DELETE, ids: [id] }); await this.sessionRepository.delete(id); } diff --git a/server/src/services/shared-link.service.ts b/server/src/services/shared-link.service.ts index 5676531e57..a01a2f45a3 100644 --- a/server/src/services/shared-link.service.ts +++ b/server/src/services/shared-link.service.ts @@ -15,7 +15,6 @@ import { AssetEntity } from 'src/entities/asset.entity'; import { SharedLinkEntity } from 'src/entities/shared-link.entity'; import { Permission, SharedLinkType } from 'src/enum'; import { BaseService } from 'src/services/base.service'; -import { checkAccess, requireAccess } from 'src/utils/access'; import { OpenGraphTags } from 'src/utils/misc'; @Injectable() @@ -49,7 +48,7 @@ export class SharedLinkService extends BaseService { if (!dto.albumId) { throw new BadRequestException('Invalid albumId'); } - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_SHARE, ids: [dto.albumId] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_SHARE, ids: [dto.albumId] }); break; } @@ -58,7 +57,7 @@ export class SharedLinkService extends BaseService { throw new BadRequestException('Invalid assetIds'); } - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_SHARE, ids: dto.assetIds }); + await this.requireAccess({ auth, permission: Permission.ASSET_SHARE, ids: dto.assetIds }); break; } @@ -119,7 +118,7 @@ export class SharedLinkService extends BaseService { const existingAssetIds = new Set(sharedLink.assets.map((asset) => asset.id)); const notPresentAssetIds = dto.assetIds.filter((assetId) => !existingAssetIds.has(assetId)); - const allowedAssetIds = await checkAccess(this.accessRepository, { + const allowedAssetIds = await this.checkAccess({ auth, permission: Permission.ASSET_SHARE, ids: notPresentAssetIds, diff --git a/server/src/services/stack.service.ts b/server/src/services/stack.service.ts index c965d3e73e..58fccc8be2 100644 --- a/server/src/services/stack.service.ts +++ b/server/src/services/stack.service.ts @@ -4,7 +4,6 @@ import { AuthDto } from 'src/dtos/auth.dto'; import { StackCreateDto, StackResponseDto, StackSearchDto, StackUpdateDto, mapStack } from 'src/dtos/stack.dto'; import { Permission } from 'src/enum'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; @Injectable() export class StackService extends BaseService { @@ -18,7 +17,7 @@ export class StackService extends BaseService { } async create(auth: AuthDto, dto: StackCreateDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_UPDATE, ids: dto.assetIds }); + await this.requireAccess({ auth, permission: Permission.ASSET_UPDATE, ids: dto.assetIds }); const stack = await this.stackRepository.create({ ownerId: auth.user.id, assetIds: dto.assetIds }); @@ -28,13 +27,13 @@ export class StackService extends BaseService { } async get(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.STACK_READ, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.STACK_READ, ids: [id] }); const stack = await this.findOrFail(id); return mapStack(stack, { auth }); } async update(auth: AuthDto, id: string, dto: StackUpdateDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.STACK_UPDATE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.STACK_UPDATE, ids: [id] }); const stack = await this.findOrFail(id); if (dto.primaryAssetId && !stack.assets.some(({ id }) => id === dto.primaryAssetId)) { throw new BadRequestException('Primary asset must be in the stack'); @@ -48,13 +47,13 @@ export class StackService extends BaseService { } async delete(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.STACK_DELETE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.STACK_DELETE, ids: [id] }); await this.stackRepository.delete(id); await this.eventRepository.emit('stack.delete', { stackId: id, userId: auth.user.id }); } async deleteAll(auth: AuthDto, dto: BulkIdsDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.STACK_DELETE, ids: dto.ids }); + await this.requireAccess({ auth, permission: Permission.STACK_DELETE, ids: dto.ids }); await this.stackRepository.deleteAll(dto.ids); await this.eventRepository.emit('stacks.delete', { stackIds: dto.ids, userId: auth.user.id }); } diff --git a/server/src/services/sync.service.ts b/server/src/services/sync.service.ts index e09c06c778..f85200db48 100644 --- a/server/src/services/sync.service.ts +++ b/server/src/services/sync.service.ts @@ -5,7 +5,6 @@ import { AuthDto } from 'src/dtos/auth.dto'; import { AssetDeltaSyncDto, AssetDeltaSyncResponseDto, AssetFullSyncDto } from 'src/dtos/sync.dto'; import { DatabaseAction, EntityType, Permission } from 'src/enum'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; import { getMyPartnerIds } from 'src/utils/asset.util'; import { setIsEqual } from 'src/utils/set'; @@ -15,7 +14,7 @@ export class SyncService extends BaseService { async getFullSync(auth: AuthDto, dto: AssetFullSyncDto): Promise { // mobile implementation is faster if this is a single id const userId = dto.userId || auth.user.id; - await requireAccess(this.accessRepository, { auth, permission: Permission.TIMELINE_READ, ids: [userId] }); + await this.requireAccess({ auth, permission: Permission.TIMELINE_READ, ids: [userId] }); const assets = await this.assetRepository.getAllForUserFullSync({ ownerId: userId, updatedUntil: dto.updatedUntil, @@ -39,7 +38,7 @@ export class SyncService extends BaseService { return FULL_SYNC; } - await requireAccess(this.accessRepository, { auth, permission: Permission.TIMELINE_READ, ids: dto.userIds }); + await this.requireAccess({ auth, permission: Permission.TIMELINE_READ, ids: dto.userIds }); const limit = 10_000; const upserted = await this.assetRepository.getChangedDeltaSync({ limit, updatedAfter: dto.updatedAfter, userIds }); diff --git a/server/src/services/tag.service.ts b/server/src/services/tag.service.ts index 2824a9832d..5534d74efa 100644 --- a/server/src/services/tag.service.ts +++ b/server/src/services/tag.service.ts @@ -15,7 +15,6 @@ import { Permission } from 'src/enum'; import { JobStatus } from 'src/interfaces/job.interface'; import { AssetTagItem } from 'src/interfaces/tag.interface'; import { BaseService } from 'src/services/base.service'; -import { checkAccess, requireAccess } from 'src/utils/access'; import { addAssets, removeAssets } from 'src/utils/asset.util'; import { upsertTags } from 'src/utils/tag'; @@ -27,7 +26,7 @@ export class TagService extends BaseService { } async get(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.TAG_READ, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.TAG_READ, ids: [id] }); const tag = await this.findOrFail(id); return mapTag(tag); } @@ -35,7 +34,7 @@ export class TagService extends BaseService { async create(auth: AuthDto, dto: TagCreateDto) { let parent: TagEntity | undefined; if (dto.parentId) { - await requireAccess(this.accessRepository, { auth, permission: Permission.TAG_READ, ids: [dto.parentId] }); + await this.requireAccess({ auth, permission: Permission.TAG_READ, ids: [dto.parentId] }); parent = (await this.tagRepository.get(dto.parentId)) || undefined; if (!parent) { throw new BadRequestException('Tag not found'); @@ -55,7 +54,7 @@ export class TagService extends BaseService { } async update(auth: AuthDto, id: string, dto: TagUpdateDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.TAG_UPDATE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.TAG_UPDATE, ids: [id] }); const { color } = dto; const tag = await this.tagRepository.update({ id, color }); @@ -68,7 +67,7 @@ export class TagService extends BaseService { } async remove(auth: AuthDto, id: string): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.TAG_DELETE, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.TAG_DELETE, ids: [id] }); // TODO sync tag changes for affected assets @@ -77,8 +76,8 @@ export class TagService extends BaseService { async bulkTagAssets(auth: AuthDto, dto: TagBulkAssetsDto): Promise { const [tagIds, assetIds] = await Promise.all([ - checkAccess(this.accessRepository, { auth, permission: Permission.TAG_ASSET, ids: dto.tagIds }), - checkAccess(this.accessRepository, { auth, permission: Permission.ASSET_UPDATE, ids: dto.assetIds }), + this.checkAccess({ auth, permission: Permission.TAG_ASSET, ids: dto.tagIds }), + this.checkAccess({ auth, permission: Permission.ASSET_UPDATE, ids: dto.assetIds }), ]); const items: AssetTagItem[] = []; @@ -97,7 +96,7 @@ export class TagService extends BaseService { } async addAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.TAG_ASSET, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.TAG_ASSET, ids: [id] }); const results = await addAssets( auth, @@ -115,7 +114,7 @@ export class TagService extends BaseService { } async removeAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise { - await requireAccess(this.accessRepository, { auth, permission: Permission.TAG_ASSET, ids: [id] }); + await this.requireAccess({ auth, permission: Permission.TAG_ASSET, ids: [id] }); const results = await removeAssets( auth, diff --git a/server/src/services/timeline.service.ts b/server/src/services/timeline.service.ts index 48e4daafd1..04fd206fe7 100644 --- a/server/src/services/timeline.service.ts +++ b/server/src/services/timeline.service.ts @@ -5,7 +5,6 @@ import { TimeBucketAssetDto, TimeBucketDto, TimeBucketResponseDto } from 'src/dt import { Permission } from 'src/enum'; import { TimeBucketOptions } from 'src/interfaces/asset.interface'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; import { getMyPartnerIds } from 'src/utils/asset.util'; export class TimelineService extends BaseService { @@ -48,20 +47,20 @@ export class TimelineService extends BaseService { private async timeBucketChecks(auth: AuthDto, dto: TimeBucketDto) { if (dto.albumId) { - await requireAccess(this.accessRepository, { auth, permission: Permission.ALBUM_READ, ids: [dto.albumId] }); + await this.requireAccess({ auth, permission: Permission.ALBUM_READ, ids: [dto.albumId] }); } else { dto.userId = dto.userId || auth.user.id; } if (dto.userId) { - await requireAccess(this.accessRepository, { auth, permission: Permission.TIMELINE_READ, ids: [dto.userId] }); + await this.requireAccess({ auth, permission: Permission.TIMELINE_READ, ids: [dto.userId] }); if (dto.isArchived !== false) { - await requireAccess(this.accessRepository, { auth, permission: Permission.ARCHIVE_READ, ids: [dto.userId] }); + await this.requireAccess({ auth, permission: Permission.ARCHIVE_READ, ids: [dto.userId] }); } } if (dto.tagId) { - await requireAccess(this.accessRepository, { auth, permission: Permission.TAG_READ, ids: [dto.tagId] }); + await this.requireAccess({ auth, permission: Permission.TAG_READ, ids: [dto.tagId] }); } if (dto.withPartners) { diff --git a/server/src/services/trash.service.ts b/server/src/services/trash.service.ts index add6e29f6b..91c359392e 100644 --- a/server/src/services/trash.service.ts +++ b/server/src/services/trash.service.ts @@ -5,7 +5,6 @@ import { TrashResponseDto } from 'src/dtos/trash.dto'; import { Permission } from 'src/enum'; import { JOBS_ASSET_PAGINATION_SIZE, JobName, JobStatus } from 'src/interfaces/job.interface'; import { BaseService } from 'src/services/base.service'; -import { requireAccess } from 'src/utils/access'; import { usePagination } from 'src/utils/pagination'; export class TrashService extends BaseService { @@ -15,7 +14,7 @@ export class TrashService extends BaseService { return { count: 0 }; } - await requireAccess(this.accessRepository, { auth, permission: Permission.ASSET_DELETE, ids }); + await this.requireAccess({ auth, permission: Permission.ASSET_DELETE, ids }); await this.trashRepository.restoreAll(ids); await this.eventRepository.emit('assets.restore', { assetIds: ids, userId: auth.user.id });