mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-15 18:27:05 +00:00
Merge branch 'feat/project-tag' of https://github.com/SyncrowIOT/backend into feat/project-tag
This commit is contained in:
@ -70,9 +70,9 @@ export class SpaceModelController {
|
|||||||
@UseGuards(PermissionsGuard)
|
@UseGuards(PermissionsGuard)
|
||||||
@Permissions('SPACE_MODEL_VIEW')
|
@Permissions('SPACE_MODEL_VIEW')
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: ControllerRoute.SPACE_MODEL.ACTIONS.LIST_SPACE_MODEL_SUMMARY,
|
summary: ControllerRoute.SPACE_MODEL.ACTIONS.GET_SPACE_MODEL_SUMMARY,
|
||||||
description:
|
description:
|
||||||
ControllerRoute.SPACE_MODEL.ACTIONS.LIST_SPACE_MODEL_DESCRIPTION,
|
ControllerRoute.SPACE_MODEL.ACTIONS.GET_SPACE_MODEL_DESCRIPTION,
|
||||||
})
|
})
|
||||||
@Get(':spaceModelUuid')
|
@Get(':spaceModelUuid')
|
||||||
async get(@Param() param: SpaceModelParam): Promise<BaseResponseDto> {
|
async get(@Param() param: SpaceModelParam): Promise<BaseResponseDto> {
|
||||||
|
@ -3,7 +3,7 @@ import { IsUUID } from 'class-validator';
|
|||||||
import { ProjectParam } from './project-param.dto';
|
import { ProjectParam } from './project-param.dto';
|
||||||
export class SpaceModelParam extends ProjectParam {
|
export class SpaceModelParam extends ProjectParam {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'UUID of the Space',
|
description: 'UUID of the Space model',
|
||||||
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
|
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
|
||||||
})
|
})
|
||||||
@IsUUID()
|
@IsUUID()
|
||||||
|
@ -10,7 +10,6 @@ import {
|
|||||||
import { DataSource, QueryRunner } from 'typeorm';
|
import { DataSource, QueryRunner } from 'typeorm';
|
||||||
import { SubSpaceService } from 'src/space/services';
|
import { SubSpaceService } from 'src/space/services';
|
||||||
import { TagService } from 'src/space/services/tag';
|
import { TagService } from 'src/space/services/tag';
|
||||||
import { TagModelService } from '../services';
|
|
||||||
import { UpdatedSubspaceModelPayload } from '../interfaces';
|
import { UpdatedSubspaceModelPayload } from '../interfaces';
|
||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
||||||
import { ModifySubspaceDto } from 'src/space/dtos';
|
import { ModifySubspaceDto } from 'src/space/dtos';
|
||||||
@ -26,7 +25,6 @@ export class PropogateUpdateSpaceModelHandler
|
|||||||
private readonly dataSource: DataSource,
|
private readonly dataSource: DataSource,
|
||||||
private readonly subSpaceService: SubSpaceService,
|
private readonly subSpaceService: SubSpaceService,
|
||||||
private readonly tagService: TagService,
|
private readonly tagService: TagService,
|
||||||
private readonly tagModelService: TagModelService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(command: PropogateUpdateSpaceModelCommand): Promise<void> {
|
async execute(command: PropogateUpdateSpaceModelCommand): Promise<void> {
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
export * from './space-model.service';
|
export * from './space-model.service';
|
||||||
export * from './subspace';
|
export * from './subspace';
|
||||||
export * from './tag-model.service';
|
|
||||||
|
@ -311,16 +311,6 @@ export class SpaceModelProductAllocationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAllocationByTagUuid(
|
|
||||||
tagUuid: string,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
): Promise<SpaceModelProductAllocationEntity | null> {
|
|
||||||
return queryRunner.manager.findOne(SpaceModelProductAllocationEntity, {
|
|
||||||
where: { tags: { uuid: tagUuid } },
|
|
||||||
relations: ['tags'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async validateTagWithinSpaceModel(
|
private async validateTagWithinSpaceModel(
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
tag: NewTagEntity,
|
tag: NewTagEntity,
|
||||||
@ -351,4 +341,29 @@ export class SpaceModelProductAllocationService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clearAllAllocations(spaceModelUuid: string, queryRunner: QueryRunner) {
|
||||||
|
try {
|
||||||
|
await queryRunner.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.delete()
|
||||||
|
.from(SpaceModelProductAllocationEntity, 'allocation')
|
||||||
|
.relation(SpaceModelProductAllocationEntity, 'tags')
|
||||||
|
.of(
|
||||||
|
await queryRunner.manager.find(SpaceModelProductAllocationEntity, {
|
||||||
|
where: { spaceModel: { uuid: spaceModelUuid } },
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await queryRunner.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.delete()
|
||||||
|
.from(SpaceModelProductAllocationEntity)
|
||||||
|
.where('spaceModelUuid = :spaceModelUuid', { spaceModelUuid })
|
||||||
|
.execute();
|
||||||
|
} catch (error) {
|
||||||
|
throw this.handleError(error, `Failed to clear all allocations`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,24 @@
|
|||||||
import {
|
import {
|
||||||
SpaceModelEntity,
|
SpaceModelEntity,
|
||||||
|
SpaceModelProductAllocationEntity,
|
||||||
SpaceModelRepository,
|
SpaceModelRepository,
|
||||||
|
SubspaceModelProductAllocationEntity,
|
||||||
} from '@app/common/modules/space-model';
|
} from '@app/common/modules/space-model';
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import {
|
import { CreateSpaceModelDto, UpdateSpaceModelDto } from '../dtos';
|
||||||
CreateSpaceModelDto,
|
|
||||||
LinkSpacesToModelDto,
|
|
||||||
UpdateSpaceModelDto,
|
|
||||||
} from '../dtos';
|
|
||||||
import { ProjectParam } from 'src/community/dtos';
|
import { ProjectParam } from 'src/community/dtos';
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
import { SubSpaceModelService } from './subspace/subspace-model.service';
|
import { SubSpaceModelService } from './subspace/subspace-model.service';
|
||||||
import { DataSource, In, QueryRunner } from 'typeorm';
|
import { DataSource, QueryRunner, SelectQueryBuilder } from 'typeorm';
|
||||||
import {
|
import {
|
||||||
TypeORMCustomModel,
|
TypeORMCustomModel,
|
||||||
TypeORMCustomModelFindAllQuery,
|
TypeORMCustomModelFindAllQuery,
|
||||||
} from '@app/common/models/typeOrmCustom.model';
|
} from '@app/common/models/typeOrmCustom.model';
|
||||||
import { PageResponse } from '@app/common/dto/pagination.response.dto';
|
|
||||||
import { SpaceModelParam } from '../dtos/space-model-param';
|
import { SpaceModelParam } from '../dtos/space-model-param';
|
||||||
import { ProjectService } from 'src/project/services';
|
import { ProjectService } from 'src/project/services';
|
||||||
import { ProjectEntity } from '@app/common/modules/project/entities';
|
import { ProjectEntity } from '@app/common/modules/project/entities';
|
||||||
import { TagModelService } from './tag-model.service';
|
|
||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
import { CommandBus } from '@nestjs/cqrs';
|
import { CommandBus } from '@nestjs/cqrs';
|
||||||
import { SpaceModelDto } from '@app/common/modules/space-model/dtos';
|
|
||||||
import { TagService as NewTagService } from 'src/tags/services';
|
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
import { ProcessTagDto } from 'src/tags/dtos';
|
||||||
import { SpaceModelProductAllocationService } from './space-model-product-allocation.service';
|
import { SpaceModelProductAllocationService } from './space-model-product-allocation.service';
|
||||||
import { SpaceRepository } from '@app/common/modules/space';
|
import { SpaceRepository } from '@app/common/modules/space';
|
||||||
@ -36,9 +30,7 @@ export class SpaceModelService {
|
|||||||
private readonly spaceModelRepository: SpaceModelRepository,
|
private readonly spaceModelRepository: SpaceModelRepository,
|
||||||
private readonly projectService: ProjectService,
|
private readonly projectService: ProjectService,
|
||||||
private readonly subSpaceModelService: SubSpaceModelService,
|
private readonly subSpaceModelService: SubSpaceModelService,
|
||||||
private readonly tagModelService: TagModelService,
|
|
||||||
private commandBus: CommandBus,
|
private commandBus: CommandBus,
|
||||||
private readonly tagService: NewTagService,
|
|
||||||
private readonly spaceModelProductAllocationService: SpaceModelProductAllocationService,
|
private readonly spaceModelProductAllocationService: SpaceModelProductAllocationService,
|
||||||
private readonly spaceRepository: SpaceRepository,
|
private readonly spaceRepository: SpaceRepository,
|
||||||
) {}
|
) {}
|
||||||
@ -134,34 +126,9 @@ export class SpaceModelService {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
pageable.include =
|
pageable.include =
|
||||||
'subspaceModels,tags,subspaceModels.tags,tags.product,subspaceModels.tags.product';
|
'subspaceModels.productAllocations,subspaceModelProductAllocations.tags,subspaceModels, productAllocations, productAllocations.tags';
|
||||||
|
|
||||||
const queryBuilder = await this.spaceModelRepository
|
const queryBuilder = this.buildSpaceModelQuery(param.projectUuid);
|
||||||
.createQueryBuilder('spaceModel')
|
|
||||||
.leftJoinAndSelect(
|
|
||||||
'spaceModel.subspaceModels',
|
|
||||||
'subspaceModels',
|
|
||||||
'subspaceModels.disabled = :subspaceDisabled',
|
|
||||||
{ subspaceDisabled: false },
|
|
||||||
)
|
|
||||||
.leftJoinAndSelect(
|
|
||||||
'spaceModel.tags',
|
|
||||||
'tags',
|
|
||||||
'tags.disabled = :tagsDisabled',
|
|
||||||
{ tagsDisabled: false },
|
|
||||||
)
|
|
||||||
.leftJoinAndSelect('tags.product', 'spaceTagproduct')
|
|
||||||
.leftJoinAndSelect(
|
|
||||||
'subspaceModels.tags',
|
|
||||||
'subspaceModelTags',
|
|
||||||
'subspaceModelTags.disabled = :subspaceModelTagsDisabled',
|
|
||||||
{ subspaceModelTagsDisabled: false },
|
|
||||||
)
|
|
||||||
.leftJoinAndSelect('subspaceModelTags.product', 'subspaceTagproduct')
|
|
||||||
.where('spaceModel.disabled = :disabled', { disabled: false })
|
|
||||||
.andWhere('spaceModel.project = :projectUuid', {
|
|
||||||
projectUuid: param.projectUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
const customModel = TypeORMCustomModel(this.spaceModelRepository);
|
const customModel = TypeORMCustomModel(this.spaceModelRepository);
|
||||||
const { baseResponseDto, paginationResponseDto } =
|
const { baseResponseDto, paginationResponseDto } =
|
||||||
@ -174,10 +141,14 @@ export class SpaceModelService {
|
|||||||
queryBuilder,
|
queryBuilder,
|
||||||
);
|
);
|
||||||
|
|
||||||
return new PageResponse<SpaceModelDto>(
|
const formattedData = this.transformSpaceModelData(baseResponseDto.data);
|
||||||
baseResponseDto,
|
|
||||||
paginationResponseDto,
|
return {
|
||||||
);
|
code: 200,
|
||||||
|
data: formattedData,
|
||||||
|
message: 'Success get list spaceModel',
|
||||||
|
...paginationResponseDto,
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
`Error fetching paginated list: ${error.message}`,
|
`Error fetching paginated list: ${error.message}`,
|
||||||
@ -193,7 +164,10 @@ export class SpaceModelService {
|
|||||||
async update(dto: UpdateSpaceModelDto, param: SpaceModelParam) {
|
async update(dto: UpdateSpaceModelDto, param: SpaceModelParam) {
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
await this.validateProject(param.projectUuid);
|
await this.validateProject(param.projectUuid);
|
||||||
const spaceModel = await this.validateSpaceModel(param.spaceModelUuid);
|
const spaceModel = await this.validateSpaceModel(
|
||||||
|
param.spaceModelUuid,
|
||||||
|
param.projectUuid,
|
||||||
|
);
|
||||||
await queryRunner.connect();
|
await queryRunner.connect();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -259,7 +233,10 @@ export class SpaceModelService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await this.validateProject(param.projectUuid);
|
await this.validateProject(param.projectUuid);
|
||||||
const spaceModel = await this.validateSpaceModel(param.spaceModelUuid);
|
const spaceModel = await this.validateSpaceModel(
|
||||||
|
param.spaceModelUuid,
|
||||||
|
param.projectUuid,
|
||||||
|
);
|
||||||
|
|
||||||
if (spaceModel.subspaceModels?.length) {
|
if (spaceModel.subspaceModels?.length) {
|
||||||
const deleteSubspaceUuids = spaceModel.subspaceModels.map(
|
const deleteSubspaceUuids = spaceModel.subspaceModels.map(
|
||||||
@ -272,10 +249,11 @@ export class SpaceModelService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spaceModel.tags?.length) {
|
if (spaceModel.productAllocations?.length) {
|
||||||
const deleteSpaceTagsDtos = spaceModel.tags.map((tag) => tag.uuid);
|
await this.spaceModelProductAllocationService.clearAllAllocations(
|
||||||
|
spaceModel.uuid,
|
||||||
await this.tagModelService.deleteTags(deleteSpaceTagsDtos, queryRunner);
|
queryRunner,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await queryRunner.manager.update(
|
await queryRunner.manager.update(
|
||||||
@ -341,11 +319,15 @@ export class SpaceModelService {
|
|||||||
async findOne(params: SpaceModelParam): Promise<BaseResponseDto> {
|
async findOne(params: SpaceModelParam): Promise<BaseResponseDto> {
|
||||||
try {
|
try {
|
||||||
await this.validateProject(params.projectUuid);
|
await this.validateProject(params.projectUuid);
|
||||||
const spaceModel = await this.validateSpaceModel(params.spaceModelUuid);
|
const spaceModel = await this.validateSpaceModel(
|
||||||
|
params.spaceModelUuid,
|
||||||
|
params.projectUuid,
|
||||||
|
);
|
||||||
|
const response = this.formatSpaceModelResponse(spaceModel);
|
||||||
|
|
||||||
return new SuccessResponseDto({
|
return new SuccessResponseDto({
|
||||||
message: 'SpaceModel retrieved successfully',
|
message: 'SpaceModel retrieved successfully',
|
||||||
data: spaceModel,
|
data: response,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
@ -355,38 +337,19 @@ export class SpaceModelService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateSpaceModel(uuid: string): Promise<SpaceModelEntity> {
|
async validateSpaceModel(
|
||||||
const spaceModel = await this.spaceModelRepository
|
uuid: string,
|
||||||
.createQueryBuilder('spaceModel')
|
projectUuid?: string,
|
||||||
.leftJoinAndSelect(
|
): Promise<SpaceModelEntity> {
|
||||||
'spaceModel.subspaceModels',
|
const query = this.buildSpaceModelQuery(projectUuid);
|
||||||
'subspaceModels',
|
const result = await query
|
||||||
'subspaceModels.disabled = :subspaceDisabled',
|
|
||||||
{ subspaceDisabled: false },
|
|
||||||
)
|
|
||||||
.leftJoinAndSelect(
|
|
||||||
'spaceModel.tags',
|
|
||||||
'tags',
|
|
||||||
'tags.disabled = :tagsDisabled',
|
|
||||||
{ tagsDisabled: false },
|
|
||||||
)
|
|
||||||
.leftJoinAndSelect('tags.product', 'spaceTagproduct')
|
|
||||||
.leftJoinAndSelect(
|
|
||||||
'subspaceModels.tags',
|
|
||||||
'subspaceModelTags',
|
|
||||||
'subspaceModelTags.disabled = :subspaceModelTagsDisabled',
|
|
||||||
{ subspaceModelTagsDisabled: false },
|
|
||||||
)
|
|
||||||
.leftJoinAndSelect('subspaceModelTags.product', 'subspaceTagproduct')
|
|
||||||
.where('spaceModel.disabled = :disabled', { disabled: false })
|
|
||||||
.where('spaceModel.disabled = :disabled', { disabled: false })
|
|
||||||
.andWhere('spaceModel.uuid = :uuid', { uuid })
|
.andWhere('spaceModel.uuid = :uuid', { uuid })
|
||||||
.getOne();
|
.getOne();
|
||||||
|
|
||||||
if (!spaceModel) {
|
if (!result) {
|
||||||
throw new HttpException('space model not found', HttpStatus.NOT_FOUND);
|
throw new HttpException('space model not found', HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
return spaceModel;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateUniqueTags(allTags: ProcessTagDto[]) {
|
private validateUniqueTags(allTags: ProcessTagDto[]) {
|
||||||
@ -415,33 +378,102 @@ export class SpaceModelService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async linkSpacesToModel(params: SpaceModelParam, dto: LinkSpacesToModelDto) {
|
private buildSpaceModelQuery(
|
||||||
await this.validateProject(params.projectUuid);
|
projectUuid: string,
|
||||||
const spaceModel = await this.validateSpaceModel(params.spaceModelUuid);
|
): SelectQueryBuilder<SpaceModelEntity> {
|
||||||
|
return this.spaceModelRepository
|
||||||
|
.createQueryBuilder('spaceModel')
|
||||||
|
.leftJoinAndSelect(
|
||||||
|
'spaceModel.subspaceModels',
|
||||||
|
'subspaceModels',
|
||||||
|
'subspaceModels.disabled = :subspaceDisabled',
|
||||||
|
{ subspaceDisabled: false },
|
||||||
|
)
|
||||||
|
.leftJoinAndSelect(
|
||||||
|
'subspaceModels.productAllocations',
|
||||||
|
'subspaceModelProductAllocations',
|
||||||
|
)
|
||||||
|
.leftJoinAndSelect(
|
||||||
|
'subspaceModelProductAllocations.tags',
|
||||||
|
'subspaceModelTags',
|
||||||
|
)
|
||||||
|
.leftJoinAndSelect('subspaceModelTags.product', 'subspaceModelTagProduct')
|
||||||
|
.leftJoinAndSelect('spaceModel.productAllocations', 'productAllocations')
|
||||||
|
.leftJoinAndSelect('productAllocations.product', 'allocatedProduct')
|
||||||
|
.leftJoinAndSelect('productAllocations.tags', 'productTags')
|
||||||
|
.leftJoinAndSelect('productTags.product', 'productTagProduct')
|
||||||
|
.where('spaceModel.disabled = false')
|
||||||
|
.andWhere('spaceModel.project = :projectUuid', { projectUuid });
|
||||||
|
}
|
||||||
|
|
||||||
const spaces = await this.spaceRepository.find({
|
private transformSpaceModelData(spaceModelsArray: SpaceModelEntity[]): any[] {
|
||||||
where: { uuid: In(dto.spaceUuids) },
|
if (!Array.isArray(spaceModelsArray)) return [];
|
||||||
relations: [
|
|
||||||
'spaceModel',
|
|
||||||
'devices',
|
|
||||||
'subspaces',
|
|
||||||
'productAllocations',
|
|
||||||
'subspace.productAllocations',
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!spaces.length) {
|
return spaceModelsArray.map((spaceModel) => ({
|
||||||
throw new HttpException(
|
uuid: spaceModel.uuid,
|
||||||
`No spaces found for the given UUIDs`,
|
createdAt: spaceModel.createdAt,
|
||||||
HttpStatus.NOT_FOUND,
|
updatedAt: spaceModel.updatedAt,
|
||||||
);
|
modelName: spaceModel.modelName,
|
||||||
}
|
disabled: spaceModel.disabled,
|
||||||
|
subspaceModels: (spaceModel.subspaceModels ?? []).map((subspace) => ({
|
||||||
|
uuid: subspace.uuid,
|
||||||
|
createdAt: subspace.createdAt,
|
||||||
|
updatedAt: subspace.updatedAt,
|
||||||
|
subspaceName: subspace.subspaceName,
|
||||||
|
disabled: subspace.disabled,
|
||||||
|
tags: this.extractTags(subspace.productAllocations),
|
||||||
|
})),
|
||||||
|
tags: this.extractTags(spaceModel.productAllocations),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
for (const space of spaces) {
|
private extractTags(
|
||||||
const hasDependencies =
|
productAllocations:
|
||||||
space.devices.length > 0 ||
|
| SpaceModelProductAllocationEntity[]
|
||||||
space.subspaces.length > 0 ||
|
| SubspaceModelProductAllocationEntity[]
|
||||||
space.productAllocations.length > 0;
|
| undefined,
|
||||||
}
|
): any[] {
|
||||||
|
if (!productAllocations) return [];
|
||||||
|
|
||||||
|
return productAllocations
|
||||||
|
.flatMap((allocation) => allocation.tags ?? [])
|
||||||
|
.map((tag) => ({
|
||||||
|
uuid: tag.uuid,
|
||||||
|
createdAt: tag.createdAt,
|
||||||
|
updatedAt: tag.updatedAt,
|
||||||
|
tag: tag.tag,
|
||||||
|
disabled: tag.disabled,
|
||||||
|
product: tag.product
|
||||||
|
? {
|
||||||
|
uuid: tag.product.uuid,
|
||||||
|
createdAt: tag.product.createdAt,
|
||||||
|
updatedAt: tag.product.updatedAt,
|
||||||
|
catName: tag.product.catName,
|
||||||
|
prodId: tag.product.prodId,
|
||||||
|
name: tag.product.name,
|
||||||
|
prodType: tag.product.prodType,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatSpaceModelResponse(spaceModel: SpaceModelEntity): any {
|
||||||
|
return {
|
||||||
|
uuid: spaceModel.uuid,
|
||||||
|
createdAt: spaceModel.createdAt,
|
||||||
|
updatedAt: spaceModel.updatedAt,
|
||||||
|
modelName: spaceModel.modelName,
|
||||||
|
disabled: spaceModel.disabled,
|
||||||
|
subspaceModels:
|
||||||
|
spaceModel.subspaceModels?.map((subspace) => ({
|
||||||
|
uuid: subspace.uuid,
|
||||||
|
createdAt: subspace.createdAt,
|
||||||
|
updatedAt: subspace.updatedAt,
|
||||||
|
subspaceName: subspace.subspaceName,
|
||||||
|
disabled: subspace.disabled,
|
||||||
|
tags: this.extractTags(subspace.productAllocations),
|
||||||
|
})) ?? [],
|
||||||
|
tags: this.extractTags(spaceModel.productAllocations),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,579 +0,0 @@
|
|||||||
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
|
|
||||||
import { QueryRunner } from 'typeorm';
|
|
||||||
import {
|
|
||||||
SpaceModelEntity,
|
|
||||||
TagModel,
|
|
||||||
} from '@app/common/modules/space-model/entities';
|
|
||||||
import { SubspaceModelEntity } from '@app/common/modules/space-model/entities';
|
|
||||||
import { TagModelRepository } from '@app/common/modules/space-model';
|
|
||||||
import {
|
|
||||||
CreateTagModelDto,
|
|
||||||
ModifySubspaceModelDto,
|
|
||||||
ModifyTagModelDto,
|
|
||||||
} from '../dtos';
|
|
||||||
import { ProductService } from 'src/product/services';
|
|
||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { ModifiedTagsModelPayload } from '../interfaces';
|
|
||||||
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class TagModelService {
|
|
||||||
constructor(
|
|
||||||
private readonly tagModelRepository: TagModelRepository,
|
|
||||||
private readonly productService: ProductService,
|
|
||||||
private readonly tagRepository: NewTagRepository,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async createTags(
|
|
||||||
tags: CreateTagModelDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
spaceModel?: SpaceModelEntity,
|
|
||||||
subspaceModel?: SubspaceModelEntity,
|
|
||||||
additionalTags?: CreateTagModelDto[],
|
|
||||||
tagsToDelete?: ModifyTagModelDto[],
|
|
||||||
): Promise<TagModel[]> {
|
|
||||||
if (!tags.length) {
|
|
||||||
throw new HttpException('Tags cannot be empty.', HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
const combinedTags = additionalTags ? [...tags, ...additionalTags] : tags;
|
|
||||||
const duplicateTags = this.findDuplicateTags(combinedTags);
|
|
||||||
|
|
||||||
if (duplicateTags.length > 0) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Duplicate tags found for the same product: ${duplicateTags.join(', ')}`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagEntitiesToCreate = tags.filter((tagDto) => !tagDto.uuid);
|
|
||||||
const tagEntitiesToUpdate = tags.filter((tagDto) => !!tagDto.uuid);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const createdTags = await this.bulkSaveTags(
|
|
||||||
tagEntitiesToCreate,
|
|
||||||
queryRunner,
|
|
||||||
spaceModel,
|
|
||||||
subspaceModel,
|
|
||||||
tagsToDelete,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update existing tags
|
|
||||||
const updatedTags = await this.moveTags(
|
|
||||||
tagEntitiesToUpdate,
|
|
||||||
queryRunner,
|
|
||||||
spaceModel,
|
|
||||||
subspaceModel,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Combine created and updated tags
|
|
||||||
return [...createdTags, ...updatedTags];
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new HttpException(
|
|
||||||
`Failed to create tag models due to an unexpected error.: ${error}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async bulkSaveTags(
|
|
||||||
tags: CreateTagModelDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
spaceModel?: SpaceModelEntity,
|
|
||||||
subspaceModel?: SubspaceModelEntity,
|
|
||||||
tagsToDelete?: ModifyTagModelDto[],
|
|
||||||
): Promise<TagModel[]> {
|
|
||||||
if (!tags.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagEntities = await Promise.all(
|
|
||||||
tags.map((tagDto) =>
|
|
||||||
this.prepareTagEntity(
|
|
||||||
tagDto,
|
|
||||||
queryRunner,
|
|
||||||
spaceModel,
|
|
||||||
subspaceModel,
|
|
||||||
tagsToDelete,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await queryRunner.manager.save(tagEntities);
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new HttpException(
|
|
||||||
`Failed to save tag models due to an unexpected error: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async moveTags(
|
|
||||||
tags: CreateTagModelDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
spaceModel?: SpaceModelEntity,
|
|
||||||
subspaceModel?: SubspaceModelEntity,
|
|
||||||
): Promise<TagModel[]> {
|
|
||||||
if (!tags.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await Promise.all(
|
|
||||||
tags.map(async (tagDto) => {
|
|
||||||
try {
|
|
||||||
const tag = await this.getTagByUuid(tagDto.uuid);
|
|
||||||
if (!tag) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag with UUID ${tagDto.uuid} not found.`,
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subspaceModel && subspaceModel.spaceModel) {
|
|
||||||
await queryRunner.manager.update(
|
|
||||||
this.tagModelRepository.target,
|
|
||||||
{ uuid: tag.uuid },
|
|
||||||
{ subspaceModel, spaceModel: null },
|
|
||||||
);
|
|
||||||
tag.subspaceModel = subspaceModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!subspaceModel && spaceModel) {
|
|
||||||
await queryRunner.manager.update(
|
|
||||||
this.tagModelRepository.target,
|
|
||||||
{ uuid: tag.uuid },
|
|
||||||
{ subspaceModel: null, spaceModel: spaceModel },
|
|
||||||
);
|
|
||||||
tag.subspaceModel = null;
|
|
||||||
tag.spaceModel = spaceModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tag;
|
|
||||||
} catch (error) {
|
|
||||||
console.error(
|
|
||||||
`Error moving tag with UUID ${tagDto.uuid}: ${error.message}`,
|
|
||||||
);
|
|
||||||
throw error; // Re-throw the error to propagate it to the parent Promise.all
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error in moveTags: ${error.message}`);
|
|
||||||
throw new HttpException(
|
|
||||||
`Failed to move tags due to an unexpected error: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateTag(
|
|
||||||
tag: ModifyTagModelDto,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
spaceModel?: SpaceModelEntity,
|
|
||||||
subspaceModel?: SubspaceModelEntity,
|
|
||||||
): Promise<TagModel> {
|
|
||||||
try {
|
|
||||||
const existingTag = await this.getTagByUuid(tag.uuid);
|
|
||||||
|
|
||||||
if (tag.tag !== existingTag.tag) {
|
|
||||||
if (spaceModel) {
|
|
||||||
await this.checkTagReuse(
|
|
||||||
tag.tag,
|
|
||||||
existingTag.product.uuid,
|
|
||||||
spaceModel,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await this.checkTagReuse(
|
|
||||||
tag.tag,
|
|
||||||
existingTag.product.uuid,
|
|
||||||
subspaceModel.spaceModel,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag.tag) {
|
|
||||||
existingTag.tag = tag.tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return await queryRunner.manager.save(existingTag);
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Failed to update tags',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteTags(tagUuids: string[], queryRunner: QueryRunner) {
|
|
||||||
try {
|
|
||||||
const deletePromises = tagUuids.map((id) =>
|
|
||||||
queryRunner.manager.update(
|
|
||||||
this.tagModelRepository.target,
|
|
||||||
{ uuid: id },
|
|
||||||
{ disabled: true },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
await Promise.all(deletePromises);
|
|
||||||
return { message: 'Tags deleted successfully', tagUuids };
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Failed to delete tags',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private findDuplicateTags(tags: CreateTagModelDto[]): string[] {
|
|
||||||
const seen = new Map<string, boolean>();
|
|
||||||
const duplicates: string[] = [];
|
|
||||||
|
|
||||||
tags.forEach((tagDto) => {
|
|
||||||
const key = `${tagDto.productUuid}-${tagDto.tag}`;
|
|
||||||
if (seen.has(key)) {
|
|
||||||
duplicates.push(`${tagDto.tag} for Product: ${tagDto.productUuid}`);
|
|
||||||
} else {
|
|
||||||
seen.set(key, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return duplicates;
|
|
||||||
}
|
|
||||||
|
|
||||||
async modifyTags(
|
|
||||||
tags: ModifyTagModelDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
spaceModel?: SpaceModelEntity,
|
|
||||||
subspaceModel?: SubspaceModelEntity,
|
|
||||||
): Promise<ModifiedTagsModelPayload> {
|
|
||||||
const modifiedTagModels: ModifiedTagsModelPayload = {
|
|
||||||
added: [],
|
|
||||||
updated: [],
|
|
||||||
deleted: [],
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
const tagsToDelete = tags.filter(
|
|
||||||
(tag) => tag.action === ModifyAction.DELETE,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const tag of tags) {
|
|
||||||
if (tag.action === ModifyAction.ADD) {
|
|
||||||
const createTagDto: CreateTagModelDto = {
|
|
||||||
tag: tag.tag as string,
|
|
||||||
uuid: tag.uuid,
|
|
||||||
productUuid: tag.productUuid as string,
|
|
||||||
};
|
|
||||||
|
|
||||||
const newModel = await this.createTags(
|
|
||||||
[createTagDto],
|
|
||||||
queryRunner,
|
|
||||||
spaceModel,
|
|
||||||
subspaceModel,
|
|
||||||
null,
|
|
||||||
tagsToDelete,
|
|
||||||
);
|
|
||||||
modifiedTagModels.added.push(...newModel);
|
|
||||||
} else if (tag.action === ModifyAction.UPDATE) {
|
|
||||||
const updatedModel = await this.updateTag(
|
|
||||||
tag,
|
|
||||||
queryRunner,
|
|
||||||
spaceModel,
|
|
||||||
subspaceModel,
|
|
||||||
);
|
|
||||||
modifiedTagModels.updated.push(updatedModel);
|
|
||||||
} else if (tag.action === ModifyAction.DELETE) {
|
|
||||||
await queryRunner.manager.update(
|
|
||||||
this.tagModelRepository.target,
|
|
||||||
{ uuid: tag.uuid },
|
|
||||||
{ disabled: true },
|
|
||||||
);
|
|
||||||
modifiedTagModels.deleted.push(tag.uuid);
|
|
||||||
} else {
|
|
||||||
throw new HttpException(
|
|
||||||
`Invalid action "${tag.action}" provided.`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return modifiedTagModels;
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new HttpException(
|
|
||||||
`An error occurred while modifying tag models: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async checkTagReuse(
|
|
||||||
tag: string,
|
|
||||||
productUuid: string,
|
|
||||||
spaceModel: SpaceModelEntity,
|
|
||||||
tagsToDelete?: ModifyTagModelDto[],
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
|
||||||
// Query to find existing tags
|
|
||||||
const tagExists = await this.tagModelRepository.find({
|
|
||||||
where: [
|
|
||||||
{
|
|
||||||
tag,
|
|
||||||
spaceModel: { uuid: spaceModel.uuid },
|
|
||||||
product: { uuid: productUuid },
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tag,
|
|
||||||
subspaceModel: { spaceModel: { uuid: spaceModel.uuid } },
|
|
||||||
product: { uuid: productUuid },
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Remove tags that are marked for deletion
|
|
||||||
const filteredTagExists = tagExists.filter(
|
|
||||||
(existingTag) =>
|
|
||||||
!tagsToDelete?.some(
|
|
||||||
(deleteTag) => deleteTag.uuid === existingTag.uuid,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// If any tags remain, throw an exception
|
|
||||||
if (filteredTagExists.length > 0) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag ${tag} can't be reused`,
|
|
||||||
HttpStatus.CONFLICT,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
console.error(`Error while checking tag reuse: ${error.message}`);
|
|
||||||
throw new HttpException(
|
|
||||||
`An error occurred while checking tag reuse: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async prepareTagEntity(
|
|
||||||
tagDto: CreateTagModelDto,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
spaceModel?: SpaceModelEntity,
|
|
||||||
subspaceModel?: SubspaceModelEntity,
|
|
||||||
tagsToDelete?: ModifyTagModelDto[],
|
|
||||||
): Promise<TagModel> {
|
|
||||||
try {
|
|
||||||
const product = await this.productService.findOne(tagDto.productUuid);
|
|
||||||
|
|
||||||
if (!product) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Product with UUID ${tagDto.productUuid} not found.`,
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spaceModel) {
|
|
||||||
await this.checkTagReuse(
|
|
||||||
tagDto.tag,
|
|
||||||
tagDto.productUuid,
|
|
||||||
spaceModel,
|
|
||||||
tagsToDelete,
|
|
||||||
);
|
|
||||||
} else if (subspaceModel && subspaceModel.spaceModel) {
|
|
||||||
await this.checkTagReuse(
|
|
||||||
tagDto.tag,
|
|
||||||
tagDto.productUuid,
|
|
||||||
subspaceModel.spaceModel,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw new HttpException(
|
|
||||||
`Invalid subspaceModel or spaceModel provided.`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return queryRunner.manager.create(TagModel, {
|
|
||||||
tag: tagDto.tag,
|
|
||||||
product: product.data,
|
|
||||||
spaceModel: spaceModel,
|
|
||||||
subspaceModel: subspaceModel,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
throw new HttpException(
|
|
||||||
`An error occurred while preparing the tag entity: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTagByUuid(uuid: string): Promise<TagModel> {
|
|
||||||
const tag = await this.tagModelRepository.findOne({
|
|
||||||
where: { uuid, disabled: false },
|
|
||||||
relations: ['product'],
|
|
||||||
});
|
|
||||||
if (!tag) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag model with ID ${uuid} not found.`,
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTagByName(
|
|
||||||
tag: string,
|
|
||||||
subspaceUuid?: string,
|
|
||||||
spaceUuid?: string,
|
|
||||||
): Promise<TagModel> {
|
|
||||||
const queryConditions: any = { tag };
|
|
||||||
|
|
||||||
if (spaceUuid) {
|
|
||||||
queryConditions.spaceModel = { uuid: spaceUuid };
|
|
||||||
} else if (subspaceUuid) {
|
|
||||||
queryConditions.subspaceModel = { uuid: subspaceUuid };
|
|
||||||
} else {
|
|
||||||
throw new HttpException(
|
|
||||||
'Either spaceUuid or subspaceUuid must be provided.',
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
queryConditions.disabled = false;
|
|
||||||
|
|
||||||
const existingTag = await this.tagModelRepository.findOne({
|
|
||||||
where: queryConditions,
|
|
||||||
relations: ['product'],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!existingTag) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag model with tag "${tag}" not found.`,
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return existingTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSubspaceTagsToBeAdded(
|
|
||||||
spaceTags?: ModifyTagModelDto[],
|
|
||||||
subspaceModels?: ModifySubspaceModelDto[],
|
|
||||||
): ModifyTagModelDto[] {
|
|
||||||
if (!subspaceModels || subspaceModels.length === 0) {
|
|
||||||
return spaceTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spaceTagsToDelete = spaceTags?.filter(
|
|
||||||
(tag) => tag.action === 'delete',
|
|
||||||
);
|
|
||||||
|
|
||||||
const tagsToAdd = subspaceModels.flatMap(
|
|
||||||
(subspace) => subspace.tags?.filter((tag) => tag.action === 'add') || [],
|
|
||||||
);
|
|
||||||
|
|
||||||
const commonTagUuids = new Set(
|
|
||||||
tagsToAdd
|
|
||||||
.filter((tagToAdd) =>
|
|
||||||
spaceTagsToDelete.some(
|
|
||||||
(tagToDelete) => tagToAdd.uuid === tagToDelete.uuid,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map((tag) => tag.uuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
const remainingTags = spaceTags.filter(
|
|
||||||
(tag) => !commonTagUuids.has(tag.uuid), // Exclude tags in commonTagUuids
|
|
||||||
);
|
|
||||||
|
|
||||||
return remainingTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
getModifiedSubspaces(
|
|
||||||
spaceTags: ModifyTagModelDto[],
|
|
||||||
subspaceModels: ModifySubspaceModelDto[],
|
|
||||||
): ModifySubspaceModelDto[] {
|
|
||||||
if (!subspaceModels || subspaceModels.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract tags marked for addition in spaceTags
|
|
||||||
const spaceTagsToAdd = spaceTags.filter((tag) => tag.action === 'add');
|
|
||||||
|
|
||||||
const subspaceTagsToAdd = subspaceModels.flatMap(
|
|
||||||
(subspace) => subspace.tags?.filter((tag) => tag.action === 'add') || [],
|
|
||||||
);
|
|
||||||
|
|
||||||
const subspaceTagsToDelete = subspaceModels.flatMap(
|
|
||||||
(subspace) =>
|
|
||||||
subspace.tags?.filter((tag) => tag.action === 'delete') || [],
|
|
||||||
);
|
|
||||||
|
|
||||||
const subspaceTagsToDeleteUuids = new Set(
|
|
||||||
subspaceTagsToDelete.map((tag) => tag.uuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
const commonTagsInSubspaces = subspaceTagsToAdd.filter((tag) =>
|
|
||||||
subspaceTagsToDeleteUuids.has(tag.uuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Find UUIDs of tags that are common between spaceTagsToAdd and subspace tags marked for deletion
|
|
||||||
const commonTagUuids = new Set(
|
|
||||||
spaceTagsToAdd
|
|
||||||
.flatMap((tagToAdd) =>
|
|
||||||
subspaceModels.flatMap(
|
|
||||||
(subspace) =>
|
|
||||||
subspace.tags?.filter(
|
|
||||||
(tagToDelete) =>
|
|
||||||
tagToDelete.action === 'delete' &&
|
|
||||||
tagToAdd.uuid === tagToDelete.uuid,
|
|
||||||
) || [],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map((tag) => tag.uuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Modify subspaceModels by removing tags with UUIDs present in commonTagUuids
|
|
||||||
let modifiedSubspaces = subspaceModels.map((subspace) => ({
|
|
||||||
...subspace,
|
|
||||||
tags: subspace.tags?.filter((tag) => !commonTagUuids.has(tag.uuid)) || [],
|
|
||||||
}));
|
|
||||||
|
|
||||||
modifiedSubspaces = modifiedSubspaces.map((subspace) => ({
|
|
||||||
...subspace,
|
|
||||||
tags:
|
|
||||||
subspace.tags?.filter(
|
|
||||||
(tag) =>
|
|
||||||
!(
|
|
||||||
tag.action === 'delete' &&
|
|
||||||
commonTagsInSubspaces.some(
|
|
||||||
(commonTag) => commonTag.uuid === tag.uuid,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
) || [],
|
|
||||||
}));
|
|
||||||
|
|
||||||
return modifiedSubspaces;
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,11 +2,7 @@ import { SpaceRepositoryModule } from '@app/common/modules/space/space.repositor
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { SpaceModelController } from './controllers';
|
import { SpaceModelController } from './controllers';
|
||||||
import {
|
import { SpaceModelService, SubSpaceModelService } from './services';
|
||||||
SpaceModelService,
|
|
||||||
SubSpaceModelService,
|
|
||||||
TagModelService,
|
|
||||||
} from './services';
|
|
||||||
import {
|
import {
|
||||||
SpaceModelProductAllocationRepoitory,
|
SpaceModelProductAllocationRepoitory,
|
||||||
SpaceModelRepository,
|
SpaceModelRepository,
|
||||||
@ -64,7 +60,6 @@ const CommandHandlers = [
|
|||||||
SubspaceModelRepository,
|
SubspaceModelRepository,
|
||||||
ProductRepository,
|
ProductRepository,
|
||||||
SubspaceRepository,
|
SubspaceRepository,
|
||||||
TagModelService,
|
|
||||||
TagModelRepository,
|
TagModelRepository,
|
||||||
SubSpaceService,
|
SubSpaceService,
|
||||||
ValidationService,
|
ValidationService,
|
||||||
|
@ -59,7 +59,6 @@ import { TagService } from './services/tag';
|
|||||||
import {
|
import {
|
||||||
SpaceModelService,
|
SpaceModelService,
|
||||||
SubSpaceModelService,
|
SubSpaceModelService,
|
||||||
TagModelService,
|
|
||||||
} from 'src/space-model/services';
|
} from 'src/space-model/services';
|
||||||
import { UserService, UserSpaceService } from 'src/users/services';
|
import { UserService, UserSpaceService } from 'src/users/services';
|
||||||
import { UserDevicePermissionService } from 'src/user-device-permission/services';
|
import { UserDevicePermissionService } from 'src/user-device-permission/services';
|
||||||
@ -120,7 +119,6 @@ export const CommandHandlers = [DisableSpaceHandler];
|
|||||||
SceneDeviceRepository,
|
SceneDeviceRepository,
|
||||||
SpaceModelService,
|
SpaceModelService,
|
||||||
SubSpaceModelService,
|
SubSpaceModelService,
|
||||||
TagModelService,
|
|
||||||
ProjectRepository,
|
ProjectRepository,
|
||||||
SpaceModelRepository,
|
SpaceModelRepository,
|
||||||
SubspaceModelRepository,
|
SubspaceModelRepository,
|
||||||
|
Reference in New Issue
Block a user