mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-26 08:04:53 +00:00
755 lines
22 KiB
TypeScript
755 lines
22 KiB
TypeScript
import {
|
|
InviteSpaceRepository,
|
|
SpaceRepository,
|
|
} from '@app/common/modules/space/repositories';
|
|
import {
|
|
BadRequestException,
|
|
HttpException,
|
|
HttpStatus,
|
|
Injectable,
|
|
} from '@nestjs/common';
|
|
import {
|
|
AddSpaceDto,
|
|
AddSubspaceDto,
|
|
CommunitySpaceParam,
|
|
GetSpaceParam,
|
|
UpdateSpaceDto,
|
|
} from '../dtos';
|
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
|
import { generateRandomString } from '@app/common/helper/randomString';
|
|
import { SpaceLinkService } from './space-link';
|
|
import { SubSpaceService } from './subspace';
|
|
import { DataSource, QueryRunner } from 'typeorm';
|
|
import { ValidationService } from './space-validation.service';
|
|
import {
|
|
ORPHAN_COMMUNITY_NAME,
|
|
ORPHAN_SPACE_NAME,
|
|
} from '@app/common/constants/orphan-constant';
|
|
import { CommandBus } from '@nestjs/cqrs';
|
|
import { TagService } from './tag';
|
|
import { TagService as NewTagService } from 'src/tags/services/tags.service';
|
|
import { SpaceModelService } from 'src/space-model/services';
|
|
import { DisableSpaceCommand } from '../commands';
|
|
import { GetSpaceDto } from '../dtos/get.space.dto';
|
|
import { removeCircularReferences } from '@app/common/helper/removeCircularReferences';
|
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
|
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';
|
|
@Injectable()
|
|
export class SpaceService {
|
|
constructor(
|
|
private readonly dataSource: DataSource,
|
|
private readonly spaceRepository: SpaceRepository,
|
|
private readonly inviteSpaceRepository: InviteSpaceRepository,
|
|
private readonly spaceLinkService: SpaceLinkService,
|
|
private readonly subSpaceService: SubSpaceService,
|
|
private readonly validationService: ValidationService,
|
|
private readonly tagService: TagService,
|
|
private readonly newTagService: NewTagService,
|
|
private readonly spaceModelService: SpaceModelService,
|
|
private commandBus: CommandBus,
|
|
private readonly spaceProductAllocationService: SpaceProductAllocationService,
|
|
private readonly subspaceProductAllocationService: SubspaceProductAllocationService,
|
|
) {}
|
|
|
|
async createSpace(
|
|
addSpaceDto: AddSpaceDto,
|
|
params: CommunitySpaceParam,
|
|
): Promise<BaseResponseDto> {
|
|
const { parentUuid, direction, spaceModelUuid, subspaces, tags } =
|
|
addSpaceDto;
|
|
const { communityUuid, projectUuid } = params;
|
|
|
|
if (addSpaceDto.spaceName === ORPHAN_SPACE_NAME) {
|
|
throw new HttpException(
|
|
`Name ${ORPHAN_SPACE_NAME} cannot be used`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
|
|
const queryRunner = this.dataSource.createQueryRunner();
|
|
|
|
await queryRunner.connect();
|
|
await queryRunner.startTransaction();
|
|
|
|
const { community } =
|
|
await this.validationService.validateCommunityAndProject(
|
|
communityUuid,
|
|
projectUuid,
|
|
);
|
|
|
|
this.validateSpaceCreation(addSpaceDto, spaceModelUuid);
|
|
|
|
const parent = parentUuid
|
|
? await this.validationService.validateSpace(parentUuid)
|
|
: null;
|
|
|
|
const spaceModel = spaceModelUuid
|
|
? await this.validationService.validateSpaceModel(spaceModelUuid)
|
|
: null;
|
|
|
|
try {
|
|
const space = queryRunner.manager.create(SpaceEntity, {
|
|
...addSpaceDto,
|
|
spaceModel,
|
|
parent: parentUuid ? parent : null,
|
|
community,
|
|
});
|
|
|
|
const newSpace = await queryRunner.manager.save(space);
|
|
const subspaceTags =
|
|
this.subSpaceService.extractTagsFromSubspace(subspaces);
|
|
const allTags = [...tags, ...subspaceTags];
|
|
this.validateUniqueTags(allTags);
|
|
if (spaceModelUuid) {
|
|
const hasDependencies = subspaces?.length > 0 || tags?.length > 0;
|
|
if (!hasDependencies && !newSpace.spaceModel) {
|
|
await this.spaceModelService.linkToSpace(
|
|
newSpace,
|
|
spaceModel,
|
|
queryRunner,
|
|
);
|
|
} else if (hasDependencies) {
|
|
throw new HttpException(
|
|
`Space cannot be linked to a model because it has existing dependencies (subspaces or tags).`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
}
|
|
|
|
await Promise.all([
|
|
direction && parent
|
|
? this.spaceLinkService.saveSpaceLink(
|
|
parent.uuid,
|
|
newSpace.uuid,
|
|
direction,
|
|
queryRunner,
|
|
)
|
|
: Promise.resolve(),
|
|
subspaces?.length
|
|
? this.createSubspaces(
|
|
subspaces,
|
|
newSpace,
|
|
queryRunner,
|
|
tags,
|
|
projectUuid,
|
|
)
|
|
: Promise.resolve(),
|
|
tags?.length
|
|
? this.createTags(tags, projectUuid, queryRunner, newSpace)
|
|
: Promise.resolve(),
|
|
]);
|
|
|
|
await queryRunner.commitTransaction();
|
|
|
|
return new SuccessResponseDto({
|
|
statusCode: HttpStatus.CREATED,
|
|
data: JSON.parse(JSON.stringify(newSpace, removeCircularReferences())),
|
|
message: 'Space created successfully',
|
|
});
|
|
} catch (error) {
|
|
await queryRunner.rollbackTransaction();
|
|
|
|
if (error instanceof HttpException) {
|
|
throw error;
|
|
}
|
|
throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
|
|
} finally {
|
|
await queryRunner.release();
|
|
}
|
|
}
|
|
private validateUniqueTags(allTags: ProcessTagDto[]) {
|
|
const tagUuidSet = new Set<string>();
|
|
const tagNameProductSet = new Set<string>();
|
|
|
|
for (const tag of allTags) {
|
|
if (tag.uuid) {
|
|
if (tagUuidSet.has(tag.uuid)) {
|
|
throw new HttpException(
|
|
`Duplicate tag UUID found: ${tag.uuid}`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
tagUuidSet.add(tag.uuid);
|
|
} else {
|
|
const tagKey = `${tag.name}-${tag.productUuid}`;
|
|
if (tagNameProductSet.has(tagKey)) {
|
|
throw new HttpException(
|
|
`Duplicate tag found with name "${tag.name}" and product "${tag.productUuid}".`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
tagNameProductSet.add(tagKey);
|
|
}
|
|
}
|
|
}
|
|
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,
|
|
getSpaceDto?: GetSpaceDto,
|
|
): Promise<BaseResponseDto> {
|
|
const { communityUuid, projectUuid } = params;
|
|
const { onlyWithDevices } = getSpaceDto;
|
|
await this.validationService.validateCommunityAndProject(
|
|
communityUuid,
|
|
projectUuid,
|
|
);
|
|
try {
|
|
const queryBuilder = this.spaceRepository
|
|
.createQueryBuilder('space')
|
|
.leftJoinAndSelect('space.parent', 'parent')
|
|
.leftJoinAndSelect(
|
|
'space.children',
|
|
'children',
|
|
'children.disabled = :disabled',
|
|
{ disabled: false },
|
|
)
|
|
.leftJoinAndSelect(
|
|
'space.incomingConnections',
|
|
'incomingConnections',
|
|
'incomingConnections.disabled = :incomingConnectionDisabled',
|
|
{ incomingConnectionDisabled: false },
|
|
)
|
|
.leftJoinAndSelect('space.productAllocations', 'productAllocations')
|
|
.leftJoinAndSelect('productAllocations.tags', 'tags')
|
|
.leftJoinAndSelect('tags.product', 'tagProduct')
|
|
.leftJoinAndSelect(
|
|
'space.subspaces',
|
|
'subspaces',
|
|
'subspaces.disabled = :subspaceDisabled',
|
|
{ subspaceDisabled: false },
|
|
)
|
|
.leftJoinAndSelect(
|
|
'subspaces.productAllocations',
|
|
'subspaceProductAllocations',
|
|
)
|
|
.leftJoinAndSelect('subspaceProductAllocations.tags', 'subspaceTags')
|
|
.leftJoinAndSelect('subspaceTags.product', 'subspaceTagProduct')
|
|
.leftJoinAndSelect('space.spaceModel', 'spaceModel')
|
|
.where('space.community_id = :communityUuid', { communityUuid })
|
|
.andWhere('space.spaceName != :orphanSpaceName', {
|
|
orphanSpaceName: ORPHAN_SPACE_NAME,
|
|
})
|
|
.andWhere('space.disabled = :disabled', { disabled: false });
|
|
|
|
if (onlyWithDevices) {
|
|
queryBuilder.innerJoin('space.devices', 'devices');
|
|
}
|
|
|
|
const spaces = await queryBuilder.getMany();
|
|
|
|
const spaceHierarchy = this.buildSpaceHierarchy(spaces);
|
|
|
|
return new SuccessResponseDto({
|
|
message: `Spaces in community ${communityUuid} successfully fetched in hierarchy`,
|
|
data: onlyWithDevices ? spaces : spaceHierarchy,
|
|
statusCode: HttpStatus.OK,
|
|
});
|
|
} catch (error) {
|
|
throw new HttpException(
|
|
`An error occurred while fetching the spaces ${error}`,
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
async findOne(params: GetSpaceParam): Promise<BaseResponseDto> {
|
|
const { communityUuid, spaceUuid, projectUuid } = params;
|
|
try {
|
|
await this.validationService.validateCommunityAndProject(
|
|
communityUuid,
|
|
projectUuid,
|
|
);
|
|
|
|
const queryBuilder = this.spaceRepository
|
|
.createQueryBuilder('space')
|
|
.leftJoinAndSelect('space.parent', 'parent')
|
|
.leftJoinAndSelect(
|
|
'space.children',
|
|
'children',
|
|
'children.disabled = :disabled',
|
|
{ disabled: false },
|
|
)
|
|
.leftJoinAndSelect(
|
|
'space.incomingConnections',
|
|
'incomingConnections',
|
|
'incomingConnections.disabled = :incomingConnectionDisabled',
|
|
{ incomingConnectionDisabled: false },
|
|
)
|
|
.leftJoinAndSelect(
|
|
'space.tags',
|
|
'tags',
|
|
'tags.disabled = :tagDisabled',
|
|
{ tagDisabled: false },
|
|
)
|
|
.leftJoinAndSelect('tags.product', 'tagProduct')
|
|
.leftJoinAndSelect(
|
|
'space.subspaces',
|
|
'subspaces',
|
|
'subspaces.disabled = :subspaceDisabled',
|
|
{ subspaceDisabled: false },
|
|
)
|
|
.leftJoinAndSelect(
|
|
'subspaces.tags',
|
|
'subspaceTags',
|
|
'subspaceTags.disabled = :subspaceTagsDisabled',
|
|
{ subspaceTagsDisabled: false },
|
|
)
|
|
.leftJoinAndSelect('subspaceTags.product', 'subspaceTagProduct')
|
|
.where('space.community_id = :communityUuid', { communityUuid })
|
|
.andWhere('space.spaceName != :orphanSpaceName', {
|
|
orphanSpaceName: ORPHAN_SPACE_NAME,
|
|
})
|
|
.andWhere('space.uuid = :spaceUuid', { spaceUuid })
|
|
.andWhere('space.disabled = :disabled', { disabled: false });
|
|
|
|
const space = await queryBuilder.getOne();
|
|
|
|
return new SuccessResponseDto({
|
|
message: `Space with ID ${spaceUuid} successfully fetched`,
|
|
data: space,
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof HttpException) {
|
|
throw error; // If it's an HttpException, rethrow it
|
|
} else {
|
|
throw new HttpException(
|
|
'An error occurred while deleting the community',
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
async delete(params: GetSpaceParam): Promise<BaseResponseDto> {
|
|
try {
|
|
const { communityUuid, spaceUuid, projectUuid } = params;
|
|
|
|
const { project } =
|
|
await this.validationService.validateCommunityAndProject(
|
|
communityUuid,
|
|
projectUuid,
|
|
);
|
|
|
|
const space = await this.validationService.validateSpace(spaceUuid);
|
|
|
|
if (space.spaceName === ORPHAN_SPACE_NAME) {
|
|
throw new HttpException(
|
|
`space ${ORPHAN_SPACE_NAME} cannot be deleted`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
|
|
const orphanSpace = await this.spaceRepository.findOne({
|
|
where: {
|
|
community: {
|
|
name: `${ORPHAN_COMMUNITY_NAME}-${project.name}`,
|
|
},
|
|
spaceName: ORPHAN_SPACE_NAME,
|
|
},
|
|
});
|
|
const queryRunner = this.dataSource.createQueryRunner();
|
|
await queryRunner.connect();
|
|
await queryRunner.startTransaction();
|
|
|
|
try {
|
|
await this.spaceProductAllocationService.clearAllAllocations(
|
|
spaceUuid,
|
|
queryRunner,
|
|
);
|
|
|
|
const subspaces = await queryRunner.manager.find(SubspaceEntity, {
|
|
where: { space: { uuid: spaceUuid } },
|
|
});
|
|
|
|
const subspaceUuids = subspaces.map((subspace) => subspace.uuid);
|
|
|
|
if (subspaceUuids.length > 0) {
|
|
await this.subSpaceService.clearSubspaces(subspaceUuids, queryRunner);
|
|
}
|
|
|
|
await this.disableSpace(space, orphanSpace);
|
|
|
|
await queryRunner.commitTransaction();
|
|
} catch (error) {
|
|
await queryRunner.rollbackTransaction();
|
|
throw error;
|
|
} finally {
|
|
await queryRunner.release();
|
|
}
|
|
|
|
return new SuccessResponseDto({
|
|
message: `Space with ID ${spaceUuid} successfully deleted`,
|
|
statusCode: HttpStatus.OK,
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof HttpException) {
|
|
throw error;
|
|
}
|
|
throw new HttpException(
|
|
`An error occurred while deleting the space ${error.message}`,
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
async disableSpace(space: SpaceEntity, orphanSpace: SpaceEntity) {
|
|
await this.commandBus.execute(
|
|
new DisableSpaceCommand({ spaceUuid: space.uuid, orphanSpace }),
|
|
);
|
|
}
|
|
|
|
async updateSpace(
|
|
params: GetSpaceParam,
|
|
updateSpaceDto: UpdateSpaceDto,
|
|
): Promise<BaseResponseDto> {
|
|
const { communityUuid, spaceUuid, projectUuid } = params;
|
|
|
|
const queryRunner = this.dataSource.createQueryRunner();
|
|
|
|
try {
|
|
await queryRunner.connect();
|
|
await queryRunner.startTransaction();
|
|
const project = await this.spaceModelService.validateProject(
|
|
params.projectUuid,
|
|
);
|
|
|
|
const space =
|
|
await this.validationService.validateSpaceWithinCommunityAndProject(
|
|
communityUuid,
|
|
projectUuid,
|
|
spaceUuid,
|
|
);
|
|
|
|
if (space.spaceName === ORPHAN_SPACE_NAME) {
|
|
throw new HttpException(
|
|
`Space "${ORPHAN_SPACE_NAME}" cannot be updated`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
|
|
this.updateSpaceProperties(space, updateSpaceDto);
|
|
|
|
if (updateSpaceDto.spaceModelUuid) {
|
|
const spaceModel = await this.validationService.validateSpaceModel(
|
|
updateSpaceDto.spaceModelUuid,
|
|
);
|
|
|
|
const hasDependencies =
|
|
space.devices?.length > 0 ||
|
|
space.subspaces?.length > 0 ||
|
|
space.productAllocations?.length > 0;
|
|
|
|
if (!hasDependencies && !space.spaceModel) {
|
|
await this.spaceModelService.linkToSpace(
|
|
space,
|
|
spaceModel,
|
|
queryRunner,
|
|
);
|
|
} else if (hasDependencies) {
|
|
await this.spaceModelService.overwriteSpace(
|
|
space,
|
|
project,
|
|
queryRunner,
|
|
);
|
|
await this.spaceModelService.linkToSpace(
|
|
space,
|
|
spaceModel,
|
|
queryRunner,
|
|
);
|
|
}
|
|
}
|
|
|
|
const hasSubspace = updateSpaceDto.subspace?.length > 0;
|
|
const hasTags = updateSpaceDto.tags?.length > 0;
|
|
|
|
if (hasSubspace || hasTags) {
|
|
space.spaceModel = null;
|
|
await this.tagService.unlinkModels(space.tags, queryRunner);
|
|
await this.subSpaceService.unlinkModels(space.subspaces, queryRunner);
|
|
}
|
|
await queryRunner.manager.save(space);
|
|
|
|
if (hasSubspace) {
|
|
const modifiedSubspaces = this.tagService.getModifiedSubspaces(
|
|
updateSpaceDto.tags,
|
|
updateSpaceDto.subspace,
|
|
);
|
|
|
|
await this.subSpaceService.modifySubSpace(
|
|
modifiedSubspaces,
|
|
queryRunner,
|
|
space,
|
|
projectUuid,
|
|
updateSpaceDto.tags,
|
|
);
|
|
}
|
|
|
|
if (hasTags) {
|
|
const spaceTagsAfterMove = this.tagService.getSubspaceTagsToBeAdded(
|
|
updateSpaceDto.tags,
|
|
updateSpaceDto.subspace,
|
|
);
|
|
|
|
await this.tagService.modifyTags(
|
|
spaceTagsAfterMove,
|
|
queryRunner,
|
|
space,
|
|
);
|
|
}
|
|
if (updateSpaceDto.tags) {
|
|
await this.spaceProductAllocationService.updateSpaceProductAllocations(
|
|
updateSpaceDto.tags,
|
|
projectUuid,
|
|
space,
|
|
queryRunner,
|
|
updateSpaceDto.subspace,
|
|
);
|
|
}
|
|
await queryRunner.commitTransaction();
|
|
|
|
return new SuccessResponseDto({
|
|
message: `Space with ID ${spaceUuid} successfully updated`,
|
|
statusCode: HttpStatus.OK,
|
|
});
|
|
} catch (error) {
|
|
await queryRunner.rollbackTransaction();
|
|
|
|
if (error instanceof HttpException) {
|
|
throw error;
|
|
}
|
|
|
|
throw new HttpException(
|
|
'An error occurred while updating the space',
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
} finally {
|
|
await queryRunner.release();
|
|
}
|
|
}
|
|
|
|
async unlinkSpaceFromModel(
|
|
space: SpaceEntity,
|
|
queryRunner: QueryRunner,
|
|
): Promise<void> {
|
|
try {
|
|
await queryRunner.manager.update(
|
|
this.spaceRepository.target,
|
|
{ uuid: space.uuid },
|
|
{
|
|
spaceModel: null,
|
|
},
|
|
);
|
|
|
|
// Unlink subspaces and tags if they exist
|
|
if (space.subspaces || space.tags) {
|
|
if (space.tags) {
|
|
await this.tagService.unlinkModels(space.tags, queryRunner);
|
|
}
|
|
|
|
if (space.subspaces) {
|
|
await this.subSpaceService.unlinkModels(space.subspaces, queryRunner);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
throw new HttpException(
|
|
`Failed to unlink space model: ${error.message}`,
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
private updateSpaceProperties(
|
|
space: SpaceEntity,
|
|
updateSpaceDto: UpdateSpaceDto,
|
|
): void {
|
|
const { spaceName, x, y, icon } = updateSpaceDto;
|
|
|
|
if (spaceName) space.spaceName = spaceName;
|
|
if (x) space.x = x;
|
|
if (y) space.y = y;
|
|
if (icon) space.icon = icon;
|
|
}
|
|
|
|
async getSpacesHierarchyForSpace(
|
|
params: GetSpaceParam,
|
|
): Promise<BaseResponseDto> {
|
|
const { spaceUuid, communityUuid, projectUuid } = params;
|
|
await this.validationService.checkCommunityAndProjectSpaceExistence(
|
|
communityUuid,
|
|
projectUuid,
|
|
spaceUuid,
|
|
);
|
|
|
|
try {
|
|
// Get all spaces that are children of the provided space, including the parent-child relations
|
|
const spaces = await this.spaceRepository.find({
|
|
where: { parent: { uuid: spaceUuid }, disabled: false },
|
|
relations: ['parent', 'children'], // Include parent and children relations
|
|
});
|
|
|
|
// Organize spaces into a hierarchical structure
|
|
const spaceHierarchy = this.buildSpaceHierarchy(spaces);
|
|
|
|
return new SuccessResponseDto({
|
|
message: `Spaces under space ${spaceUuid} successfully fetched in hierarchy`,
|
|
data: spaceHierarchy,
|
|
statusCode: HttpStatus.OK,
|
|
});
|
|
} catch (error) {
|
|
throw new HttpException(
|
|
`An error occurred while fetching the spaces under the space ${error}`,
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
async generateSpaceInvitationCode(params: GetSpaceParam): Promise<any> {
|
|
const { communityUuid, spaceUuid, projectUuid } = params;
|
|
try {
|
|
const invitationCode = generateRandomString(6);
|
|
|
|
const space =
|
|
await this.validationService.validateSpaceWithinCommunityAndProject(
|
|
communityUuid,
|
|
projectUuid,
|
|
spaceUuid,
|
|
);
|
|
await this.inviteSpaceRepository.save({
|
|
space: { uuid: spaceUuid },
|
|
invitationCode,
|
|
});
|
|
|
|
return new SuccessResponseDto({
|
|
message: `Invitation code has been successfuly added to the space`,
|
|
data: {
|
|
invitationCode,
|
|
spaceName: space.spaceName,
|
|
spaceUuid: space.uuid,
|
|
},
|
|
});
|
|
} catch (err) {
|
|
if (err instanceof BadRequestException) {
|
|
throw err;
|
|
} else {
|
|
throw new HttpException('Space not found', HttpStatus.NOT_FOUND);
|
|
}
|
|
}
|
|
}
|
|
|
|
private buildSpaceHierarchy(spaces: SpaceEntity[]): SpaceEntity[] {
|
|
const map = new Map<string, SpaceEntity>();
|
|
|
|
// Step 1: Create a map of spaces by UUID
|
|
spaces.forEach((space) => {
|
|
map.set(
|
|
space.uuid,
|
|
this.spaceRepository.create({
|
|
...space,
|
|
children: [], // Add children if needed
|
|
}),
|
|
);
|
|
});
|
|
|
|
// Step 2: Organize the hierarchy
|
|
const rootSpaces: SpaceEntity[] = [];
|
|
spaces.forEach((space) => {
|
|
if (space.parent && space.parent.uuid) {
|
|
const parent = map.get(space.parent.uuid);
|
|
parent?.children?.push(map.get(space.uuid));
|
|
} else {
|
|
rootSpaces.push(map.get(space.uuid));
|
|
}
|
|
});
|
|
|
|
return rootSpaces;
|
|
}
|
|
|
|
private validateSpaceCreation(
|
|
addSpaceDto: AddSpaceDto,
|
|
spaceModelUuid?: string,
|
|
) {
|
|
const hasTagsOrSubspaces =
|
|
(addSpaceDto.tags && addSpaceDto.tags.length > 0) ||
|
|
(addSpaceDto.subspaces && addSpaceDto.subspaces.length > 0);
|
|
|
|
if (spaceModelUuid && hasTagsOrSubspaces) {
|
|
throw new HttpException(
|
|
'For space creation choose either space model or products and subspace',
|
|
HttpStatus.CONFLICT,
|
|
);
|
|
}
|
|
}
|
|
|
|
private async createSubspaces(
|
|
subspaces: AddSubspaceDto[],
|
|
space: SpaceEntity,
|
|
queryRunner: QueryRunner,
|
|
tags: ProcessTagDto[],
|
|
projectUuid: string,
|
|
): Promise<void> {
|
|
space.subspaces = await this.subSpaceService.createSubspacesFromDto(
|
|
subspaces,
|
|
space,
|
|
queryRunner,
|
|
tags,
|
|
projectUuid,
|
|
);
|
|
}
|
|
|
|
private async createTags(
|
|
tags: ProcessTagDto[],
|
|
projectUuid: string,
|
|
queryRunner: QueryRunner,
|
|
space: SpaceEntity,
|
|
): Promise<void> {
|
|
const processedTags = await this.newTagService.processTags(
|
|
tags,
|
|
projectUuid,
|
|
queryRunner,
|
|
);
|
|
await this.spaceProductAllocationService.createSpaceProductAllocations(
|
|
space,
|
|
processedTags,
|
|
queryRunner,
|
|
);
|
|
}
|
|
}
|