Files
backend/src/space/services/space.service.ts
T
2024-11-21 16:11:53 +04:00

311 lines
8.9 KiB
TypeScript

import { SpaceRepository } from '@app/common/modules/space/repositories';
import {
BadRequestException,
HttpException,
HttpStatus,
Injectable,
} from '@nestjs/common';
import { AddSpaceDto } from '../dtos';
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { CommunityRepository } from '@app/common/modules/community/repositories';
import { SpaceEntity } from '@app/common/modules/space/entities';
import { generateRandomString } from '@app/common/helper/randomString';
import { SpaceLinkService } from './space-link';
import { SpaceProductService } from './space-products';
@Injectable()
export class SpaceService {
constructor(
private readonly spaceRepository: SpaceRepository,
private readonly communityRepository: CommunityRepository,
private readonly spaceLinkService: SpaceLinkService,
private readonly spaceProductService: SpaceProductService,
) {}
async createSpace(
addSpaceDto: AddSpaceDto,
communityId: string,
): Promise<BaseResponseDto> {
const { parentUuid, direction, products } = addSpaceDto;
const community = await this.validateCommunity(communityId);
const parent = parentUuid ? await this.validateSpace(parentUuid) : null;
try {
const newSpace = this.spaceRepository.create({
...addSpaceDto,
community,
parent: parentUuid ? parent : null,
});
await this.spaceRepository.save(newSpace);
if (direction && parent) {
await this.spaceLinkService.saveSpaceLink(
parent.uuid,
newSpace.uuid,
direction,
);
}
if (products && products.length > 0) {
await this.spaceProductService.assignProductsToSpace(
newSpace,
products,
);
}
return new SuccessResponseDto({
statusCode: HttpStatus.CREATED,
data: newSpace,
message: 'Space created successfully',
});
} catch (error) {
throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
async getSpacesHierarchyForCommunity(
communityUuid: string,
): Promise<BaseResponseDto> {
await this.validateCommunity(communityUuid);
try {
// Get all spaces related to the community, including the parent-child relations
const spaces = await this.spaceRepository.find({
where: { community: { uuid: communityUuid } },
relations: [
'parent',
'children',
'incomingConnections',
'spaceProducts',
'spaceProducts.product',
], // Include parent and children relations
});
// Organize spaces into a hierarchical structure
const spaceHierarchy = this.buildSpaceHierarchy(spaces);
return new SuccessResponseDto({
message: `Spaces in community ${communityUuid} successfully fetched in hierarchy`,
data: spaceHierarchy,
statusCode: HttpStatus.OK,
});
} catch (error) {
throw new HttpException(
'An error occurred while fetching the spaces',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async findOne(spaceUuid: string): Promise<BaseResponseDto> {
try {
const space = await this.validateSpace(spaceUuid);
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(
spaceUuid: string,
communityUuid: string,
): Promise<BaseResponseDto> {
try {
// First, check if the community exists
const space = await this.validateCommunityAndSpace(
communityUuid,
spaceUuid,
);
// Delete the space
await this.spaceRepository.remove(space);
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',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async updateSpace(
spaceUuid: string,
communityId: string,
updateSpaceDto: AddSpaceDto,
): Promise<BaseResponseDto> {
try {
const space = await this.validateCommunityAndSpace(
communityId,
spaceUuid,
);
// If a parentId is provided, check if the parent exists
const { parentUuid, products } = updateSpaceDto;
const parent = parentUuid ? await this.validateSpace(parentUuid) : null;
// Update other space properties from updateSpaceDto
Object.assign(space, updateSpaceDto, { parent });
// Save the updated space
const updatedSpace = await this.spaceRepository.save(space);
if (products && products.length > 0) {
await this.spaceProductService.assignProductsToSpace(
updatedSpace,
products,
);
}
return new SuccessResponseDto({
message: `Space with ID ${spaceUuid} successfully updated`,
data: space,
statusCode: HttpStatus.OK,
});
} catch (error) {
if (error instanceof HttpException) {
throw error;
}
throw new HttpException(
'An error occurred while updating the space',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async getSpacesHierarchyForSpace(
spaceUuid: string,
): Promise<BaseResponseDto> {
await this.validateSpace(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 } },
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',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async getSpaceInvitationCode(spaceUuid: string): Promise<any> {
try {
const invitationCode = generateRandomString(6);
const space = await this.validateSpace(spaceUuid);
space.invitationCode = invitationCode;
await this.spaceRepository.save(space);
return new SuccessResponseDto({
message: `Invitation code has been successfuly added to the space`,
data: space,
});
} 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 async validateCommunity(communityId: string) {
const community = await this.communityRepository.findOne({
where: { uuid: communityId },
});
if (!community) {
throw new HttpException(
`Community with ID ${communityId} not found`,
HttpStatus.NOT_FOUND,
);
}
return community;
}
async validateCommunityAndSpace(communityUuid: string, spaceUuid: string) {
const community = await this.validateCommunity(communityUuid);
if (!community) {
this.throwNotFound('Community', communityUuid);
}
const space = await this.validateSpace(spaceUuid);
return space;
}
private async validateSpace(spaceUuid: string) {
const space = await this.spaceRepository.findOne({
where: { uuid: spaceUuid },
});
if (!space) this.throwNotFound('Space', spaceUuid);
return space;
}
private throwNotFound(entity: string, uuid: string) {
throw new HttpException(
`${entity} with ID ${uuid} not found`,
HttpStatus.NOT_FOUND,
);
}
}