diff --git a/libs/common/src/constants/controller-route.ts b/libs/common/src/constants/controller-route.ts index 94baf8e..7cb25ce 100644 --- a/libs/common/src/constants/controller-route.ts +++ b/libs/common/src/constants/controller-route.ts @@ -140,7 +140,8 @@ export class ControllerRoute { }; static SPACE = class { - public static readonly ROUTE = '/communities/:communityUuid/spaces'; + public static readonly ROUTE = + '/projects/:projectUuid/communities/:communityUuid/spaces'; static ACTIONS = class { public static readonly CREATE_SPACE_SUMMARY = 'Create a new space'; public static readonly CREATE_SPACE_DESCRIPTION = diff --git a/src/space/controllers/space.controller.ts b/src/space/controllers/space.controller.ts index e0615eb..d31bb23 100644 --- a/src/space/controllers/space.controller.ts +++ b/src/space/controllers/space.controller.ts @@ -12,7 +12,7 @@ import { UseGuards, } from '@nestjs/common'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; -import { AddSpaceDto, CommunitySpaceParam } from '../dtos'; +import { AddSpaceDto, CommunitySpaceParam, UpdateSpaceDto } from '../dtos'; import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { GetSpaceParam } from '../dtos/get.space.param'; @@ -37,7 +37,7 @@ export class SpaceController { ): Promise { return await this.spaceService.createSpace( addSpaceDto, - communitySpaceParam.communityUuid, + communitySpaceParam, ); } @@ -51,11 +51,9 @@ export class SpaceController { }) @Get() async getHierarchy( - @Param() param: CommunitySpaceParam, + @Param() params: CommunitySpaceParam, ): Promise { - return this.spaceService.getSpacesHierarchyForCommunity( - param.communityUuid, - ); + return this.spaceService.getSpacesHierarchyForCommunity(params); } @ApiBearerAuth() @@ -66,7 +64,7 @@ export class SpaceController { }) @Delete('/:spaceUuid') async deleteSpace(@Param() params: GetSpaceParam): Promise { - return this.spaceService.delete(params.spaceUuid, params.communityUuid); + return this.spaceService.delete(params); } @ApiBearerAuth() @@ -78,13 +76,9 @@ export class SpaceController { }) async updateSpace( @Param() params: GetSpaceParam, - @Body() updateSpaceDto: AddSpaceDto, + @Body() updateSpaceDto: UpdateSpaceDto, ): Promise { - return this.spaceService.updateSpace( - params.spaceUuid, - params.communityUuid, - updateSpaceDto, - ); + return this.spaceService.updateSpace(params, updateSpaceDto); } @ApiBearerAuth() @@ -95,7 +89,7 @@ export class SpaceController { }) @Get('/:spaceUuid') async get(@Param() params: GetSpaceParam): Promise { - return this.spaceService.findOne(params.spaceUuid); + return this.spaceService.findOne(params); } @ApiBearerAuth() @@ -108,7 +102,7 @@ export class SpaceController { async getHierarchyUnderSpace( @Param() params: GetSpaceParam, ): Promise { - return this.spaceService.getSpacesHierarchyForSpace(params.spaceUuid); + return this.spaceService.getSpacesHierarchyForSpace(params); } //should it be post? @@ -123,6 +117,6 @@ export class SpaceController { async generateSpaceInvitationCode( @Param() params: GetSpaceParam, ): Promise { - return this.spaceService.getSpaceInvitationCode(params.spaceUuid); + return this.spaceService.getSpaceInvitationCode(params); } } diff --git a/src/space/dtos/add.space.dto.ts b/src/space/dtos/add.space.dto.ts index 1f369b1..554f17b 100644 --- a/src/space/dtos/add.space.dto.ts +++ b/src/space/dtos/add.space.dto.ts @@ -30,7 +30,7 @@ export class AddSpaceDto { parentUuid?: string; @IsString() - @IsNotEmpty() + @IsOptional() public icon: string; @ApiProperty({ @@ -56,6 +56,7 @@ export class AddSpaceDto { @IsArray() @ValidateNested({ each: true }) + @IsOptional() @Type(() => ProductAssignmentDto) products: ProductAssignmentDto[]; } diff --git a/src/space/dtos/community-space.param.ts b/src/space/dtos/community-space.param.ts index ab35e4e..caf05b0 100644 --- a/src/space/dtos/community-space.param.ts +++ b/src/space/dtos/community-space.param.ts @@ -1,7 +1,8 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsUUID } from 'class-validator'; +import { ProjectParam } from './project.param.dto'; -export class CommunitySpaceParam { +export class CommunitySpaceParam extends ProjectParam { @ApiProperty({ description: 'UUID of the community this space belongs to', example: 'd290f1ee-6c54-4b01-90e6-d701748f0851', diff --git a/src/space/dtos/index.ts b/src/space/dtos/index.ts index 2cebe7b..3c85266 100644 --- a/src/space/dtos/index.ts +++ b/src/space/dtos/index.ts @@ -3,3 +3,5 @@ export * from './community-space.param'; export * from './get.space.param'; export * from './user-space.param'; export * from './subspace'; +export * from './project.param.dto'; +export * from './update.space.dto'; diff --git a/src/space/dtos/project.param.dto.ts b/src/space/dtos/project.param.dto.ts new file mode 100644 index 0000000..8bb2929 --- /dev/null +++ b/src/space/dtos/project.param.dto.ts @@ -0,0 +1,11 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsUUID } from 'class-validator'; + +export class ProjectParam { + @ApiProperty({ + description: 'UUID of the project this community belongs to', + example: 'd290f1ee-6c54-4b01-90e6-d701748f0851', + }) + @IsUUID() + projectUuid: string; +} diff --git a/src/space/dtos/update.space.dto.ts b/src/space/dtos/update.space.dto.ts new file mode 100644 index 0000000..d40476b --- /dev/null +++ b/src/space/dtos/update.space.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/swagger'; +import { AddSpaceDto } from './add.space.dto'; + +export class UpdateSpaceDto extends PartialType(AddSpaceDto) {} diff --git a/src/space/services/space.service.ts b/src/space/services/space.service.ts index 6e3e600..0055ddf 100644 --- a/src/space/services/space.service.ts +++ b/src/space/services/space.service.ts @@ -5,7 +5,7 @@ import { HttpStatus, Injectable, } from '@nestjs/common'; -import { AddSpaceDto } from '../dtos'; +import { AddSpaceDto, CommunitySpaceParam, GetSpaceParam, UpdateSpaceDto } 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'; @@ -13,6 +13,7 @@ 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'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; @Injectable() export class SpaceService { @@ -21,15 +22,19 @@ export class SpaceService { private readonly communityRepository: CommunityRepository, private readonly spaceLinkService: SpaceLinkService, private readonly spaceProductService: SpaceProductService, + private readonly projectRepository: ProjectRepository, ) {} async createSpace( addSpaceDto: AddSpaceDto, - communityId: string, + params: CommunitySpaceParam, ): Promise { const { parentUuid, direction, products } = addSpaceDto; + const { communityUuid, projectUuid } = params; - const community = await this.validateCommunity(communityId); + await this.validateProject(projectUuid); + + const community = await this.validateCommunity(communityUuid); const parent = parentUuid ? await this.validateSpace(parentUuid) : null; try { @@ -67,9 +72,11 @@ export class SpaceService { } async getSpacesHierarchyForCommunity( - communityUuid: string, + params: CommunitySpaceParam, ): Promise { + const { communityUuid, projectUuid } = params; await this.validateCommunity(communityUuid); + await this.validateProject(projectUuid); try { // Get all spaces related to the community, including the parent-child relations const spaces = await this.spaceRepository.find({ @@ -80,7 +87,7 @@ export class SpaceService { 'incomingConnections', 'spaceProducts', 'spaceProducts.product', - ], // Include parent and children relations + ], }); // Organize spaces into a hierarchical structure @@ -99,9 +106,14 @@ export class SpaceService { } } - async findOne(spaceUuid: string): Promise { + async findOne(params: GetSpaceParam): Promise { + const { communityUuid, spaceUuid, projectUuid } = params; try { - const space = await this.validateSpace(spaceUuid); + const space = await this.validateCommunityAndSpace( + communityUuid, + spaceUuid, + projectUuid, + ); return new SuccessResponseDto({ message: `Space with ID ${spaceUuid} successfully fetched`, @@ -119,15 +131,14 @@ export class SpaceService { } } - async delete( - spaceUuid: string, - communityUuid: string, - ): Promise { + async delete(params: GetSpaceParam): Promise { try { + const { communityUuid, spaceUuid, projectUuid } = params; // First, check if the community exists const space = await this.validateCommunityAndSpace( communityUuid, spaceUuid, + projectUuid, ); // Delete the space @@ -149,14 +160,15 @@ export class SpaceService { } async updateSpace( - spaceUuid: string, - communityId: string, - updateSpaceDto: AddSpaceDto, + params: GetSpaceParam, + updateSpaceDto: UpdateSpaceDto, ): Promise { + const { communityUuid, spaceUuid, projectUuid } = params; try { const space = await this.validateCommunityAndSpace( - communityId, + communityUuid, spaceUuid, + projectUuid, ); // If a parentId is provided, check if the parent exists @@ -193,9 +205,10 @@ export class SpaceService { } async getSpacesHierarchyForSpace( - spaceUuid: string, + params: GetSpaceParam, ): Promise { - await this.validateSpace(spaceUuid); + const { spaceUuid, communityUuid, projectUuid } = params; + await this.validateCommunityAndSpace(communityUuid, spaceUuid, projectUuid); try { // Get all spaces that are children of the provided space, including the parent-child relations @@ -220,11 +233,16 @@ export class SpaceService { } } - async getSpaceInvitationCode(spaceUuid: string): Promise { + async getSpaceInvitationCode(params: GetSpaceParam): Promise { + const { communityUuid, spaceUuid, projectUuid } = params; try { const invitationCode = generateRandomString(6); - const space = await this.validateSpace(spaceUuid); + const space = await this.validateCommunityAndSpace( + communityUuid, + spaceUuid, + projectUuid, + ); space.invitationCode = invitationCode; await this.spaceRepository.save(space); @@ -283,7 +301,13 @@ export class SpaceService { return community; } - async validateCommunityAndSpace(communityUuid: string, spaceUuid: string) { + async validateCommunityAndSpace( + communityUuid: string, + spaceUuid: string, + projectUuid: string, + ) { + await this.validateProject(projectUuid); + const community = await this.validateCommunity(communityUuid); if (!community) { this.throwNotFound('Community', communityUuid); @@ -301,6 +325,14 @@ export class SpaceService { return space; } + private async validateProject(uuid: string) { + const project = await this.projectRepository.findOne({ + where: { uuid }, + }); + + if (!project) this.throwNotFound('Project', uuid); + } + private throwNotFound(entity: string, uuid: string) { throw new HttpException( `${entity} with ID ${uuid} not found`, diff --git a/src/space/space.module.ts b/src/space/space.module.ts index 9c80fa1..002c2df 100644 --- a/src/space/space.module.ts +++ b/src/space/space.module.ts @@ -42,6 +42,7 @@ import { DeviceService } from 'src/device/services'; import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service'; import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories'; import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; @Module({ imports: [ConfigModule, SpaceRepositoryModule], @@ -79,6 +80,7 @@ import { SceneDeviceRepository } from '@app/common/modules/scene-device/reposito SceneDeviceRepository, SpaceProductService, SpaceProductRepository, + ProjectRepository, ], exports: [SpaceService], })