fixing propagation

This commit is contained in:
hannathkadher
2025-03-07 23:01:38 +04:00
parent 226781e53f
commit 1220ee395d
12 changed files with 236 additions and 68 deletions
@@ -13,12 +13,16 @@ import { ModifySubspaceDto } from '../dtos';
import { ProcessTagDto } from 'src/tags/dtos';
import { TagService as NewTagService } from 'src/tags/services';
import { SpaceModelProductAllocationEntity } from '@app/common/modules/space-model';
import { DeviceEntity } from '@app/common/modules/device/entities';
import { ProjectEntity } from '@app/common/modules/project/entities';
import { ValidationService } from './space-validation.service';
@Injectable()
export class SpaceProductAllocationService {
constructor(
private readonly tagService: NewTagService,
private readonly spaceProductAllocationRepository: SpaceProductAllocationRepository,
private readonly spaceService: ValidationService,
) {}
async createSpaceProductAllocations(
@@ -220,6 +224,114 @@ export class SpaceProductAllocationService {
}
}
async propagateDeleteToInheritedAllocations(
queryRunner: QueryRunner,
allocationsToUpdate: SpaceModelProductAllocationEntity[],
tagUuidsToDelete: string[],
project: ProjectEntity,
spaces?: SpaceEntity[],
): Promise<void> {
try {
const inheritedAllocationUpdates: SpaceProductAllocationEntity[] = [];
const inheritedAllocationsToDelete: SpaceProductAllocationEntity[] = [];
for (const allocation of allocationsToUpdate) {
for (const inheritedAllocation of allocation.inheritedSpaceAllocations) {
const updatedInheritedTags = inheritedAllocation.tags.filter(
(tag) => !tagUuidsToDelete.includes(tag.uuid),
);
if (updatedInheritedTags.length === inheritedAllocation.tags.length) {
continue;
}
if (updatedInheritedTags.length === 0) {
inheritedAllocationsToDelete.push(inheritedAllocation);
} else {
inheritedAllocation.tags = updatedInheritedTags;
inheritedAllocationUpdates.push(inheritedAllocation);
}
}
}
if (inheritedAllocationUpdates.length > 0) {
await queryRunner.manager.save(
SpaceProductAllocationEntity,
inheritedAllocationUpdates,
);
}
if (inheritedAllocationsToDelete.length > 0) {
await queryRunner.manager.remove(
SpaceProductAllocationEntity,
inheritedAllocationsToDelete,
);
}
if (spaces && spaces.length > 0) {
await this.moveDevicesToOrphanSpace(
queryRunner,
spaces,
tagUuidsToDelete,
project,
);
}
await queryRunner.manager
.createQueryBuilder()
.delete()
.from('space_product_tags')
.where(
'space_product_allocation_uuid NOT IN (' +
queryRunner.manager
.createQueryBuilder()
.select('allocation.uuid')
.from(SpaceProductAllocationEntity, 'allocation')
.getQuery() +
')',
)
.execute();
} catch (error) {
throw this.handleError(
error,
`Failed to propagate tag deletion to inherited allocations`,
);
}
}
async moveDevicesToOrphanSpace(
queryRunner: QueryRunner,
spaces: SpaceEntity[],
tagUuidsToDelete: string[],
project: ProjectEntity,
): Promise<void> {
try {
const orphanSpace = await this.spaceService.getOrphanSpace(project);
const devicesToMove = await queryRunner.manager
.createQueryBuilder(DeviceEntity, 'device')
.leftJoinAndSelect('device.tag', 'tag')
.where('device.spaceDevice IN (:...spaceUuids)', {
spaceUuids: spaces.map((space) => space.uuid),
})
.andWhere('tag.uuid IN (:...tagUuidsToDelete)', { tagUuidsToDelete })
.getMany();
if (devicesToMove.length === 0) return;
await queryRunner.manager
.createQueryBuilder()
.update(DeviceEntity)
.set({ spaceDevice: orphanSpace })
.where('uuid IN (:...deviceUuids)', {
deviceUuids: devicesToMove.map((device) => device.uuid),
})
.execute();
} catch (error) {
throw this.handleError(error, `Failed to move devices to orphan space`);
}
}
private async processDeleteActions(
dtos: ModifyTagDto[],
queryRunner: QueryRunner,
@@ -19,6 +19,11 @@ import { ValidateSpacesDto } from '../dtos/validation.space.dto';
import { ProjectParam } from '../dtos';
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
import { In } from 'typeorm';
import {
ORPHAN_COMMUNITY_NAME,
ORPHAN_SPACE_NAME,
} from '@app/common/constants/orphan-constant';
import { ProjectEntity } from '@app/common/modules/project/entities';
@Injectable()
export class ValidationService {
@@ -286,4 +291,24 @@ export class ValidationService {
);
}
}
async getOrphanSpace(project: ProjectEntity): Promise<SpaceEntity> {
const orphanSpace = await this.spaceRepository.findOne({
where: {
community: {
name: `${ORPHAN_COMMUNITY_NAME}-${project.name}`,
},
spaceName: ORPHAN_SPACE_NAME,
},
});
if (!orphanSpace) {
throw new HttpException(
`Orphan space not found in community ${project.name}`,
HttpStatus.NOT_FOUND,
);
}
return orphanSpace;
}
}
+5 -34
View File
@@ -38,6 +38,9 @@ import { ProcessTagDto } from 'src/tags/dtos';
import { SpaceProductAllocationService } from './space-product-allocation.service';
import { SubspaceProductAllocationService } from './subspace/subspace-product-allocation.service';
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
import { ProjectEntity } from '@app/common/modules/project/entities';
import { DeviceRepository } from '@app/common/modules/device/repositories';
import { DeviceService } from 'src/device/services';
@Injectable()
export class SpaceService {
constructor(
@@ -53,6 +56,8 @@ export class SpaceService {
private commandBus: CommandBus,
private readonly spaceProductAllocationService: SpaceProductAllocationService,
private readonly subspaceProductAllocationService: SubspaceProductAllocationService,
private readonly deviceRepository: DeviceRepository,
private readonly deviceSevice: DeviceService,
) {}
async createSpace(
@@ -186,40 +191,6 @@ export class SpaceService {
}
}
}
async createFromModel(
spaceModelUuid: string,
queryRunner: QueryRunner,
space: SpaceEntity,
) {
try {
const spaceModel =
await this.spaceModelService.validateSpaceModel(spaceModelUuid);
space.spaceModel = spaceModel;
await queryRunner.manager.save(SpaceEntity, space);
await this.subSpaceService.createSubSpaceFromModel(
spaceModel.subspaceModels,
space,
queryRunner,
);
await this.tagService.createTagsFromModel(
queryRunner,
spaceModel.tags,
space,
null,
);
} catch (error) {
if (error instanceof HttpException) {
throw error;
}
throw new HttpException(
'An error occurred while creating the space from space model',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async getSpacesHierarchyForCommunity(
params: CommunitySpaceParam,
+13 -19
View File
@@ -70,29 +70,23 @@ export class SubSpaceService {
async createSubSpaceFromModel(
subspaceModels: SubspaceModelEntity[],
space: SpaceEntity,
spaces: SpaceEntity[],
queryRunner: QueryRunner,
): Promise<void> {
if (!subspaceModels?.length) return;
if (!subspaceModels?.length || !spaces?.length) return;
const subspaceData = subspaceModels.map((subSpaceModel) => ({
subspaceName: subSpaceModel.subspaceName,
space,
subSpaceModel,
}));
const subspaceData = [];
const subspaces = await this.createSubspaces(subspaceData, queryRunner);
await Promise.all(
subspaceModels.map((model, index) =>
this.tagService.createTagsFromModel(
queryRunner,
model.tags || [],
null,
subspaces[index],
),
),
);
for (const space of spaces) {
for (const subSpaceModel of subspaceModels) {
subspaceData.push({
subspaceName: subSpaceModel.subspaceName,
space,
subSpaceModel,
});
}
}
await this.createSubspaces(subspaceData, queryRunner);
}
async createSubspacesFromDto(
+1
View File
@@ -118,6 +118,7 @@ export const CommandHandlers = [DisableSpaceHandler];
UserRepository,
SpaceUserService,
SpaceSceneService,
DeviceService,
SceneService,
SceneIconRepository,
SceneRepository,