2024-03-29 12:56:16 +01:00
|
|
|
import { AccessCore, Permission } from 'src/cores/access.core';
|
|
|
|
|
import { BulkIdErrorReason, BulkIdResponseDto } from 'src/dtos/asset-ids.response.dto';
|
|
|
|
|
import { AuthDto } from 'src/dtos/auth.dto';
|
|
|
|
|
import { IAccessRepository } from 'src/interfaces/access.interface';
|
2024-06-14 18:29:32 -04:00
|
|
|
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
2024-03-29 12:56:16 +01:00
|
|
|
|
|
|
|
|
export interface IBulkAsset {
|
|
|
|
|
getAssetIds: (id: string, assetIds: string[]) => Promise<Set<string>>;
|
|
|
|
|
addAssetIds: (id: string, assetIds: string[]) => Promise<void>;
|
|
|
|
|
removeAssetIds: (id: string, assetIds: string[]) => Promise<void>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const addAssets = async (
|
|
|
|
|
auth: AuthDto,
|
|
|
|
|
repositories: { accessRepository: IAccessRepository; repository: IBulkAsset },
|
2024-06-29 00:17:58 -04:00
|
|
|
dto: { parentId: string; assetIds: string[] },
|
2024-03-29 12:56:16 +01:00
|
|
|
) => {
|
|
|
|
|
const { accessRepository, repository } = repositories;
|
|
|
|
|
const access = AccessCore.create(accessRepository);
|
|
|
|
|
|
2024-06-29 00:17:58 -04:00
|
|
|
const existingAssetIds = await repository.getAssetIds(dto.parentId, dto.assetIds);
|
2024-03-29 12:56:16 +01:00
|
|
|
const notPresentAssetIds = dto.assetIds.filter((id) => !existingAssetIds.has(id));
|
|
|
|
|
const allowedAssetIds = await access.checkAccess(auth, Permission.ASSET_SHARE, notPresentAssetIds);
|
|
|
|
|
|
|
|
|
|
const results: BulkIdResponseDto[] = [];
|
|
|
|
|
for (const assetId of dto.assetIds) {
|
|
|
|
|
const hasAsset = existingAssetIds.has(assetId);
|
|
|
|
|
if (hasAsset) {
|
|
|
|
|
results.push({ id: assetId, success: false, error: BulkIdErrorReason.DUPLICATE });
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const hasAccess = allowedAssetIds.has(assetId);
|
|
|
|
|
if (!hasAccess) {
|
|
|
|
|
results.push({ id: assetId, success: false, error: BulkIdErrorReason.NO_PERMISSION });
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 23:29:32 -04:00
|
|
|
existingAssetIds.add(assetId);
|
2024-03-29 12:56:16 +01:00
|
|
|
results.push({ id: assetId, success: true });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const newAssetIds = results.filter(({ success }) => success).map(({ id }) => id);
|
|
|
|
|
if (newAssetIds.length > 0) {
|
2024-06-29 00:17:58 -04:00
|
|
|
await repository.addAssetIds(dto.parentId, newAssetIds);
|
2024-03-29 12:56:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return results;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const removeAssets = async (
|
|
|
|
|
auth: AuthDto,
|
|
|
|
|
repositories: { accessRepository: IAccessRepository; repository: IBulkAsset },
|
2024-06-29 00:17:58 -04:00
|
|
|
dto: { parentId: string; assetIds: string[]; canAlwaysRemove: Permission },
|
2024-03-29 12:56:16 +01:00
|
|
|
) => {
|
|
|
|
|
const { accessRepository, repository } = repositories;
|
|
|
|
|
const access = AccessCore.create(accessRepository);
|
|
|
|
|
|
2024-06-29 00:17:58 -04:00
|
|
|
// check if the user can always remove from the parent album, memory, etc.
|
|
|
|
|
const canAlwaysRemove = await access.checkAccess(auth, dto.canAlwaysRemove, [dto.parentId]);
|
|
|
|
|
const existingAssetIds = await repository.getAssetIds(dto.parentId, dto.assetIds);
|
|
|
|
|
const allowedAssetIds = canAlwaysRemove.has(dto.parentId)
|
|
|
|
|
? existingAssetIds
|
|
|
|
|
: await access.checkAccess(auth, Permission.ASSET_SHARE, existingAssetIds);
|
2024-03-29 12:56:16 +01:00
|
|
|
|
|
|
|
|
const results: BulkIdResponseDto[] = [];
|
|
|
|
|
for (const assetId of dto.assetIds) {
|
|
|
|
|
const hasAsset = existingAssetIds.has(assetId);
|
|
|
|
|
if (!hasAsset) {
|
|
|
|
|
results.push({ id: assetId, success: false, error: BulkIdErrorReason.NOT_FOUND });
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const hasAccess = allowedAssetIds.has(assetId);
|
|
|
|
|
if (!hasAccess) {
|
|
|
|
|
results.push({ id: assetId, success: false, error: BulkIdErrorReason.NO_PERMISSION });
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 23:29:32 -04:00
|
|
|
existingAssetIds.delete(assetId);
|
2024-03-29 12:56:16 +01:00
|
|
|
results.push({ id: assetId, success: true });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const removedIds = results.filter(({ success }) => success).map(({ id }) => id);
|
|
|
|
|
if (removedIds.length > 0) {
|
2024-06-29 00:17:58 -04:00
|
|
|
await repository.removeAssetIds(dto.parentId, removedIds);
|
2024-03-29 12:56:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return results;
|
|
|
|
|
};
|
2024-06-14 18:29:32 -04:00
|
|
|
|
|
|
|
|
export type PartnerIdOptions = {
|
|
|
|
|
userId: string;
|
|
|
|
|
repository: IPartnerRepository;
|
|
|
|
|
/** only include partners with `inTimeline: true` */
|
|
|
|
|
timelineEnabled?: boolean;
|
|
|
|
|
};
|
|
|
|
|
export const getMyPartnerIds = async ({ userId, repository, timelineEnabled }: PartnerIdOptions) => {
|
|
|
|
|
const partnerIds = new Set<string>();
|
|
|
|
|
const partners = await repository.getAll(userId);
|
|
|
|
|
for (const partner of partners) {
|
|
|
|
|
// ignore deleted users
|
|
|
|
|
if (!partner.sharedBy || !partner.sharedWith) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// wrong direction
|
|
|
|
|
if (partner.sharedWithId !== userId) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (timelineEnabled && !partner.inTimeline) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
partnerIds.add(partner.sharedById);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [...partnerIds];
|
|
|
|
|
};
|