Merge pull request #169 from SyncrowIOT/feat/associate-community-project

Feat/associate-community-project
This commit is contained in:
faris Aljohari
2024-12-10 01:19:37 -06:00
committed by GitHub
24 changed files with 254 additions and 194 deletions

View File

@ -35,7 +35,7 @@ export class ControllerRoute {
}; };
static COMMUNITY = class { static COMMUNITY = class {
public static readonly ROUTE = 'communities'; public static readonly ROUTE = '/projects/:projectUuid/communities';
static ACTIONS = class { static ACTIONS = class {
public static readonly GET_COMMUNITY_BY_ID_SUMMARY = public static readonly GET_COMMUNITY_BY_ID_SUMMARY =
'Get community by community community uuid'; 'Get community by community community uuid';
@ -140,7 +140,8 @@ export class ControllerRoute {
}; };
static SPACE = class { static SPACE = class {
public static readonly ROUTE = '/communities/:communityUuid/spaces'; public static readonly ROUTE =
'/projects/:projectUuid/communities/:communityUuid/spaces';
static ACTIONS = class { static ACTIONS = class {
public static readonly CREATE_SPACE_SUMMARY = 'Create a new space'; public static readonly CREATE_SPACE_SUMMARY = 'Create a new space';
public static readonly CREATE_SPACE_DESCRIPTION = public static readonly CREATE_SPACE_DESCRIPTION =
@ -181,7 +182,7 @@ export class ControllerRoute {
static SPACE_SCENE = class { static SPACE_SCENE = class {
public static readonly ROUTE = public static readonly ROUTE =
'/communities/:communityUuid/spaces/:spaceUuid/scenes'; '/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/scenes';
static ACTIONS = class { static ACTIONS = class {
public static readonly GET_TAP_TO_RUN_SCENE_BY_SPACE_SUMMARY = public static readonly GET_TAP_TO_RUN_SCENE_BY_SPACE_SUMMARY =
'Retrieve Tap-to-Run Scenes by Space'; 'Retrieve Tap-to-Run Scenes by Space';
@ -192,7 +193,7 @@ export class ControllerRoute {
static SPACE_USER = class { static SPACE_USER = class {
public static readonly ROUTE = public static readonly ROUTE =
'/communities/:communityUuid/spaces/:spaceUuid/user'; '/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/user';
static ACTIONS = class { static ACTIONS = class {
public static readonly ASSOCIATE_SPACE_USER_SUMMARY = public static readonly ASSOCIATE_SPACE_USER_SUMMARY =
'Associate a user to a space'; 'Associate a user to a space';
@ -208,7 +209,7 @@ export class ControllerRoute {
static SPACE_DEVICES = class { static SPACE_DEVICES = class {
public static readonly ROUTE = public static readonly ROUTE =
'/communities/:communityUuid/spaces/:spaceUuid/devices'; '/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/devices';
static ACTIONS = class { static ACTIONS = class {
public static readonly LIST_SPACE_DEVICE_SUMMARY = public static readonly LIST_SPACE_DEVICE_SUMMARY =
'List devices in a space'; 'List devices in a space';
@ -219,7 +220,7 @@ export class ControllerRoute {
static SUBSPACE = class { static SUBSPACE = class {
public static readonly ROUTE = public static readonly ROUTE =
'/communities/:communityUuid/spaces/:spaceUuid/subspaces'; '/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/subspaces';
static ACTIONS = class { static ACTIONS = class {
public static readonly CREATE_SUBSPACE_SUMMARY = 'Create Subspace'; public static readonly CREATE_SUBSPACE_SUMMARY = 'Create Subspace';
public static readonly CREATE_SUBSPACE_DESCRIPTION = public static readonly CREATE_SUBSPACE_DESCRIPTION =
@ -245,7 +246,7 @@ export class ControllerRoute {
static SUBSPACE_DEVICE = class { static SUBSPACE_DEVICE = class {
public static readonly ROUTE = public static readonly ROUTE =
'/communities/:communityUuid/spaces/:spaceUuid/subspaces/:subSpaceUuid/devices'; '/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/subspaces/:subSpaceUuid/devices';
static ACTIONS = class { static ACTIONS = class {
public static readonly LIST_SUBSPACE_DEVICE_SUMMARY = public static readonly LIST_SUBSPACE_DEVICE_SUMMARY =

View File

@ -1,7 +1,8 @@
import { Column, Entity, OneToMany, Unique } from 'typeorm'; import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { CommunityDto } from '../dtos'; import { CommunityDto } from '../dtos';
import { SpaceEntity } from '../../space/entities'; import { SpaceEntity } from '../../space/entities';
import { ProjectEntity } from '../../project/entities';
@Entity({ name: 'community' }) @Entity({ name: 'community' })
@Unique(['name']) @Unique(['name'])
@ -31,4 +32,9 @@ export class CommunityEntity extends AbstractEntity<CommunityDto> {
nullable: true, nullable: true,
}) })
externalId: string; externalId: string;
@ManyToOne(() => ProjectEntity, (project) => project.communities, {
nullable: true,
})
project: ProjectEntity;
} }

View File

@ -1,6 +1,7 @@
import { Entity, Column, Unique } from 'typeorm'; import { Entity, Column, Unique, OneToMany } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { ProjectDto } from '../dtos'; import { ProjectDto } from '../dtos';
import { CommunityEntity } from '../../community/entities';
@Entity({ name: 'project' }) @Entity({ name: 'project' })
@Unique(['name']) @Unique(['name'])
@ -20,6 +21,9 @@ export class ProjectEntity extends AbstractEntity<ProjectDto> {
@Column({ length: 255, nullable: true }) @Column({ length: 255, nullable: true })
description: string; description: string;
@OneToMany(() => CommunityEntity, (community) => community.project)
communities: CommunityEntity[];
constructor(partial: Partial<ProjectEntity>) { constructor(partial: Partial<ProjectEntity>) {
super(); super();
Object.assign(this, partial); Object.assign(this, partial);

View File

@ -8,4 +8,4 @@ import { ProjectEntity } from './entities';
controllers: [], controllers: [],
imports: [TypeOrmModule.forFeature([ProjectEntity])], imports: [TypeOrmModule.forFeature([ProjectEntity])],
}) })
export class ProjectEntityModule {} export class ProjectRepositoryModule {}

View File

@ -9,6 +9,7 @@ import { UserRepositoryModule } from '@app/common/modules/user/user.repository.m
import { SpacePermissionService } from '@app/common/helper/services'; import { SpacePermissionService } from '@app/common/helper/services';
import { CommunityRepository } from '@app/common/modules/community/repositories'; import { CommunityRepository } from '@app/common/modules/community/repositories';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { ProjectRepository } from '@app/common/modules/project/repositiories';
@Module({ @Module({
imports: [ConfigModule, SpaceRepositoryModule, UserRepositoryModule], imports: [ConfigModule, SpaceRepositoryModule, UserRepositoryModule],
@ -20,6 +21,7 @@ import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service
TuyaService, TuyaService,
CommunityRepository, CommunityRepository,
SpacePermissionService, SpacePermissionService,
ProjectRepository,
], ],
exports: [CommunityService, SpacePermissionService], exports: [CommunityService, SpacePermissionService],
}) })

View File

@ -19,6 +19,7 @@ import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
import { ControllerRoute } from '@app/common/constants/controller-route'; import { ControllerRoute } from '@app/common/constants/controller-route';
import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { PaginationRequestGetListDto } from '@app/common/dto/pagination.request.dto'; import { PaginationRequestGetListDto } from '@app/common/dto/pagination.request.dto';
import { ProjectParam } from '../dtos';
@ApiTags('Community Module') @ApiTags('Community Module')
@Controller({ @Controller({
@ -36,9 +37,10 @@ export class CommunityController {
description: ControllerRoute.COMMUNITY.ACTIONS.CREATE_COMMUNITY_DESCRIPTION, description: ControllerRoute.COMMUNITY.ACTIONS.CREATE_COMMUNITY_DESCRIPTION,
}) })
async createCommunity( async createCommunity(
@Param() param: ProjectParam,
@Body() addCommunityDto: AddCommunityDto, @Body() addCommunityDto: AddCommunityDto,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return await this.communityService.createCommunity(addCommunityDto); return await this.communityService.createCommunity(param, addCommunityDto);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -52,7 +54,7 @@ export class CommunityController {
async getCommunityByUuid( async getCommunityByUuid(
@Param() params: GetCommunityParams, @Param() params: GetCommunityParams,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return await this.communityService.getCommunityById(params.communityUuid); return await this.communityService.getCommunityById(params);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -63,9 +65,10 @@ export class CommunityController {
}) })
@Get() @Get()
async getCommunities( async getCommunities(
@Param() param: ProjectParam,
@Query() query: PaginationRequestGetListDto, @Query() query: PaginationRequestGetListDto,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return this.communityService.getCommunities(query); return this.communityService.getCommunities(param, query);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -76,13 +79,10 @@ export class CommunityController {
}) })
@Put('/:communityUuid') @Put('/:communityUuid')
async updateCommunity( async updateCommunity(
@Param() param: GetCommunityParams, @Param() params: GetCommunityParams,
@Body() updateCommunityDto: UpdateCommunityNameDto, @Body() updateCommunityDto: UpdateCommunityNameDto,
) { ) {
return this.communityService.updateCommunity( return this.communityService.updateCommunity(params, updateCommunityDto);
param.communityUuid,
updateCommunityDto,
);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -93,8 +93,8 @@ export class CommunityController {
description: ControllerRoute.COMMUNITY.ACTIONS.DELETE_COMMUNITY_DESCRIPTION, description: ControllerRoute.COMMUNITY.ACTIONS.DELETE_COMMUNITY_DESCRIPTION,
}) })
async deleteCommunity( async deleteCommunity(
@Param() param: GetCommunityParams, @Param() params: GetCommunityParams,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return this.communityService.deleteCommunity(param.communityUuid); return this.communityService.deleteCommunity(params);
} }
} }

View File

@ -10,6 +10,7 @@ import {
IsUUID, IsUUID,
Min, Min,
} from 'class-validator'; } from 'class-validator';
import { ProjectParam } from './project.param.dto';
export class GetCommunityDto { export class GetCommunityDto {
@ApiProperty({ @ApiProperty({
@ -21,7 +22,7 @@ export class GetCommunityDto {
public communityUuid: string; public communityUuid: string;
} }
export class GetCommunityParams { export class GetCommunityParams extends ProjectParam {
@ApiProperty({ @ApiProperty({
description: 'Community id of the specific community', description: 'Community id of the specific community',
required: true, required: true,

View File

@ -1 +1,3 @@
export * from './add.community.dto'; export * from './add.community.dto';
export * from './project.param.dto';
export * from './get.community.dto';

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { AddCommunityDto } from '../dtos'; import { AddCommunityDto, GetCommunityParams, ProjectParam } from '../dtos';
import { UpdateCommunityNameDto } from '../dtos/update.community.dto'; import { UpdateCommunityNameDto } from '../dtos/update.community.dto';
import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { import {
@ -11,17 +11,24 @@ import { CommunityRepository } from '@app/common/modules/community/repositories'
import { CommunityDto } from '@app/common/modules/community/dtos'; import { CommunityDto } from '@app/common/modules/community/dtos';
import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { ProjectRepository } from '@app/common/modules/project/repositiories';
@Injectable() @Injectable()
export class CommunityService { export class CommunityService {
constructor( constructor(
private readonly communityRepository: CommunityRepository, private readonly communityRepository: CommunityRepository,
private readonly projectRepository: ProjectRepository,
private readonly tuyaService: TuyaService, private readonly tuyaService: TuyaService,
) {} ) {}
async createCommunity(dto: AddCommunityDto): Promise<BaseResponseDto> { async createCommunity(
param: ProjectParam,
dto: AddCommunityDto,
): Promise<BaseResponseDto> {
const { name, description } = dto; const { name, description } = dto;
const project = await this.validateProject(param.projectUuid);
const existingCommunity = await this.communityRepository.findOneBy({ const existingCommunity = await this.communityRepository.findOneBy({
name, name,
}); });
@ -36,6 +43,7 @@ export class CommunityService {
const community = this.communityRepository.create({ const community = this.communityRepository.create({
name: name, name: name,
description: description, description: description,
project: project,
}); });
// Save the community to the database // Save the community to the database
@ -54,7 +62,11 @@ export class CommunityService {
} }
} }
async getCommunityById(communityUuid: string): Promise<BaseResponseDto> { async getCommunityById(params: GetCommunityParams): Promise<BaseResponseDto> {
const { communityUuid, projectUuid } = params;
await this.validateProject(projectUuid);
const community = await this.communityRepository.findOneBy({ const community = await this.communityRepository.findOneBy({
uuid: communityUuid, uuid: communityUuid,
}); });
@ -75,9 +87,13 @@ export class CommunityService {
} }
async getCommunities( async getCommunities(
param: ProjectParam,
pageable: Partial<TypeORMCustomModelFindAllQuery>, pageable: Partial<TypeORMCustomModelFindAllQuery>,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
await this.validateProject(param.projectUuid);
pageable.modelName = 'community'; pageable.modelName = 'community';
pageable.where = { project: { uuid: param.projectUuid } };
const customModel = TypeORMCustomModel(this.communityRepository); const customModel = TypeORMCustomModel(this.communityRepository);
@ -91,9 +107,13 @@ export class CommunityService {
} }
async updateCommunity( async updateCommunity(
communityUuid: string, params: GetCommunityParams,
updateCommunityDto: UpdateCommunityNameDto, updateCommunityDto: UpdateCommunityNameDto,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { communityUuid, projectUuid } = params;
await this.validateProject(projectUuid);
const community = await this.communityRepository.findOne({ const community = await this.communityRepository.findOne({
where: { uuid: communityUuid }, where: { uuid: communityUuid },
}); });
@ -128,7 +148,11 @@ export class CommunityService {
} }
} }
async deleteCommunity(communityUuid: string): Promise<BaseResponseDto> { async deleteCommunity(params: GetCommunityParams): Promise<BaseResponseDto> {
const { communityUuid, projectUuid } = params;
await this.validateProject(projectUuid);
const community = await this.communityRepository.findOne({ const community = await this.communityRepository.findOne({
where: { uuid: communityUuid }, where: { uuid: communityUuid },
}); });
@ -169,4 +193,17 @@ export class CommunityService {
); );
} }
} }
private async validateProject(uuid: string) {
const project = await this.projectRepository.findOne({
where: { uuid },
});
if (!project) {
throw new HttpException(
`A project with the uuid '${uuid}' doesn't exists.`,
HttpStatus.BAD_REQUEST,
);
}
return project;
}
} }

View File

@ -26,10 +26,7 @@ export class SpaceUserController {
async associateUserToSpace( async associateUserToSpace(
@Param() params: UserSpaceParam, @Param() params: UserSpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return this.spaceUserService.associateUserToSpace( return this.spaceUserService.associateUserToSpace(params);
params.userUuid,
params.spaceUuid,
);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -43,9 +40,6 @@ export class SpaceUserController {
async disassociateUserFromSpace( async disassociateUserFromSpace(
@Param() params: UserSpaceParam, @Param() params: UserSpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return this.spaceUserService.disassociateUserFromSpace( return this.spaceUserService.disassociateUserFromSpace(params);
params.userUuid,
params.spaceUuid,
);
} }
} }

View File

@ -12,7 +12,7 @@ import {
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; 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 { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { GetSpaceParam } from '../dtos/get.space.param'; import { GetSpaceParam } from '../dtos/get.space.param';
@ -37,7 +37,7 @@ export class SpaceController {
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return await this.spaceService.createSpace( return await this.spaceService.createSpace(
addSpaceDto, addSpaceDto,
communitySpaceParam.communityUuid, communitySpaceParam,
); );
} }
@ -51,11 +51,9 @@ export class SpaceController {
}) })
@Get() @Get()
async getHierarchy( async getHierarchy(
@Param() param: CommunitySpaceParam, @Param() params: CommunitySpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return this.spaceService.getSpacesHierarchyForCommunity( return this.spaceService.getSpacesHierarchyForCommunity(params);
param.communityUuid,
);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -66,7 +64,7 @@ export class SpaceController {
}) })
@Delete('/:spaceUuid') @Delete('/:spaceUuid')
async deleteSpace(@Param() params: GetSpaceParam): Promise<BaseResponseDto> { async deleteSpace(@Param() params: GetSpaceParam): Promise<BaseResponseDto> {
return this.spaceService.delete(params.spaceUuid, params.communityUuid); return this.spaceService.delete(params);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -78,13 +76,9 @@ export class SpaceController {
}) })
async updateSpace( async updateSpace(
@Param() params: GetSpaceParam, @Param() params: GetSpaceParam,
@Body() updateSpaceDto: AddSpaceDto, @Body() updateSpaceDto: UpdateSpaceDto,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return this.spaceService.updateSpace( return this.spaceService.updateSpace(params, updateSpaceDto);
params.spaceUuid,
params.communityUuid,
updateSpaceDto,
);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -95,7 +89,7 @@ export class SpaceController {
}) })
@Get('/:spaceUuid') @Get('/:spaceUuid')
async get(@Param() params: GetSpaceParam): Promise<BaseResponseDto> { async get(@Param() params: GetSpaceParam): Promise<BaseResponseDto> {
return this.spaceService.findOne(params.spaceUuid); return this.spaceService.findOne(params);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -108,7 +102,7 @@ export class SpaceController {
async getHierarchyUnderSpace( async getHierarchyUnderSpace(
@Param() params: GetSpaceParam, @Param() params: GetSpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return this.spaceService.getSpacesHierarchyForSpace(params.spaceUuid); return this.spaceService.getSpacesHierarchyForSpace(params);
} }
//should it be post? //should it be post?
@ -123,6 +117,6 @@ export class SpaceController {
async generateSpaceInvitationCode( async generateSpaceInvitationCode(
@Param() params: GetSpaceParam, @Param() params: GetSpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return this.spaceService.getSpaceInvitationCode(params.spaceUuid); return this.spaceService.getSpaceInvitationCode(params);
} }
} }

View File

@ -30,7 +30,7 @@ export class AddSpaceDto {
parentUuid?: string; parentUuid?: string;
@IsString() @IsString()
@IsNotEmpty() @IsOptional()
public icon: string; public icon: string;
@ApiProperty({ @ApiProperty({
@ -56,6 +56,7 @@ export class AddSpaceDto {
@IsArray() @IsArray()
@ValidateNested({ each: true }) @ValidateNested({ each: true })
@IsOptional()
@Type(() => ProductAssignmentDto) @Type(() => ProductAssignmentDto)
products: ProductAssignmentDto[]; products: ProductAssignmentDto[];
} }

View File

@ -1,7 +1,8 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsUUID } from 'class-validator'; import { IsUUID } from 'class-validator';
import { ProjectParam } from './project.param.dto';
export class CommunitySpaceParam { export class CommunitySpaceParam extends ProjectParam {
@ApiProperty({ @ApiProperty({
description: 'UUID of the community this space belongs to', description: 'UUID of the community this space belongs to',
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851', example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',

View File

@ -3,3 +3,5 @@ export * from './community-space.param';
export * from './get.space.param'; export * from './get.space.param';
export * from './user-space.param'; export * from './user-space.param';
export * from './subspace'; export * from './subspace';
export * from './project.param.dto';
export * from './update.space.dto';

View File

@ -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;
}

View File

@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/swagger';
import { AddSpaceDto } from './add.space.dto';
export class UpdateSpaceDto extends PartialType(AddSpaceDto) {}

View File

@ -8,6 +8,7 @@ import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
import { ProductRepository } from '@app/common/modules/product/repositories'; import { ProductRepository } from '@app/common/modules/product/repositories';
import { SpaceService } from './space.service';
@Injectable() @Injectable()
export class SpaceDeviceService { export class SpaceDeviceService {
@ -16,14 +17,16 @@ export class SpaceDeviceService {
private readonly tuyaService: TuyaService, private readonly tuyaService: TuyaService,
private readonly productRepository: ProductRepository, private readonly productRepository: ProductRepository,
private readonly communityRepository: CommunityRepository, private readonly communityRepository: CommunityRepository,
private readonly spaceService: SpaceService,
) {} ) {}
async listDevicesInSpace(params: GetSpaceParam): Promise<BaseResponseDto> { async listDevicesInSpace(params: GetSpaceParam): Promise<BaseResponseDto> {
const { spaceUuid, communityUuid } = params; const { spaceUuid, communityUuid, projectUuid } = params;
try { try {
const space = await this.validateCommunityAndSpace( const space = await this.spaceService.validateCommunityAndSpace(
communityUuid, communityUuid,
spaceUuid, spaceUuid,
projectUuid,
); );
const safeFetch = async (device: any) => { const safeFetch = async (device: any) => {
@ -52,7 +55,7 @@ export class SpaceDeviceService {
const detailedDevices = await Promise.all(space.devices.map(safeFetch)); const detailedDevices = await Promise.all(space.devices.map(safeFetch));
return new SuccessResponseDto({ return new SuccessResponseDto({
data: detailedDevices.filter(Boolean), // Remove null or undefined values data: detailedDevices.filter(Boolean),
message: 'Successfully retrieved list of devices', message: 'Successfully retrieved list of devices',
}); });
} catch (error) { } catch (error) {
@ -64,31 +67,6 @@ export class SpaceDeviceService {
} }
} }
async validateCommunityAndSpace(communityUuid: string, spaceUuid: string) {
const community = await this.communityRepository.findOne({
where: { uuid: communityUuid },
});
if (!community) {
this.throwNotFound('Community', communityUuid);
}
const space = await this.spaceRepository.findOne({
where: { uuid: spaceUuid, community: { uuid: communityUuid } },
relations: ['devices', 'devices.productDevice'],
});
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,
);
}
private async getDeviceDetailsByDeviceIdTuya( private async getDeviceDetailsByDeviceIdTuya(
deviceId: string, deviceId: string,
): Promise<GetDeviceDetailsInterface> { ): Promise<GetDeviceDetailsInterface> {

View File

@ -18,11 +18,12 @@ export class SpaceSceneService {
getSceneDto: GetSceneDto, getSceneDto: GetSceneDto,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
try { try {
const { spaceUuid, communityUuid } = params; const { spaceUuid, communityUuid, projectUuid } = params;
await this.spaceSevice.validateCommunityAndSpace( await this.spaceSevice.validateCommunityAndSpace(
communityUuid, communityUuid,
spaceUuid, spaceUuid,
projectUuid,
); );
const scenes = await this.sceneSevice.findScenesBySpace( const scenes = await this.sceneSevice.findScenesBySpace(

View File

@ -6,6 +6,8 @@ import {
UserSpaceRepository, UserSpaceRepository,
} from '@app/common/modules/user/repositories'; } from '@app/common/modules/user/repositories';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { SpaceService } from './space.service';
import { UserSpaceParam } from '../dtos';
@Injectable() @Injectable()
export class SpaceUserService { export class SpaceUserService {
@ -13,11 +15,10 @@ export class SpaceUserService {
private readonly spaceRepository: SpaceRepository, private readonly spaceRepository: SpaceRepository,
private readonly userRepository: UserRepository, private readonly userRepository: UserRepository,
private readonly userSpaceRepository: UserSpaceRepository, private readonly userSpaceRepository: UserSpaceRepository,
private readonly spaceService: SpaceService,
) {} ) {}
async associateUserToSpace( async associateUserToSpace(params: UserSpaceParam): Promise<BaseResponseDto> {
userUuid: string, const { communityUuid, spaceUuid, userUuid, projectUuid } = params;
spaceUuid: string,
): Promise<BaseResponseDto> {
// Find the user by ID // Find the user by ID
const user = await this.userRepository.findOne({ const user = await this.userRepository.findOne({
where: { uuid: userUuid }, where: { uuid: userUuid },
@ -30,15 +31,11 @@ export class SpaceUserService {
} }
// Find the space by ID // Find the space by ID
const space = await this.spaceRepository.findOne({ const space = await this.spaceService.validateCommunityAndSpace(
where: { uuid: spaceUuid }, communityUuid,
}); spaceUuid,
if (!space) { projectUuid,
throw new HttpException(
`Space with ID ${spaceUuid} not found`,
HttpStatus.NOT_FOUND,
); );
}
// Check if the association already exists // Check if the association already exists
const existingAssociation = await this.userSpaceRepository.findOne({ const existingAssociation = await this.userSpaceRepository.findOne({
@ -61,9 +58,9 @@ export class SpaceUserService {
} }
async disassociateUserFromSpace( async disassociateUserFromSpace(
userUuid: string, params: UserSpaceParam,
spaceUuid: string,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { userUuid, spaceUuid, communityUuid, projectUuid } = params;
// Find the user by ID // Find the user by ID
const user = await this.userRepository.findOne({ const user = await this.userRepository.findOne({
where: { uuid: userUuid }, where: { uuid: userUuid },
@ -76,15 +73,11 @@ export class SpaceUserService {
} }
// Find the space by ID // Find the space by ID
const space = await this.spaceRepository.findOne({ await this.spaceService.validateCommunityAndSpace(
where: { uuid: spaceUuid }, communityUuid,
}); spaceUuid,
if (!space) { projectUuid,
throw new HttpException(
`Space with ID ${spaceUuid} not found`,
HttpStatus.NOT_FOUND,
); );
}
// Find the existing association // Find the existing association
const existingAssociation = await this.userSpaceRepository.findOne({ const existingAssociation = await this.userSpaceRepository.findOne({

View File

@ -5,7 +5,7 @@ import {
HttpStatus, HttpStatus,
Injectable, Injectable,
} from '@nestjs/common'; } from '@nestjs/common';
import { AddSpaceDto } from '../dtos'; import { AddSpaceDto, CommunitySpaceParam, GetSpaceParam, UpdateSpaceDto } from '../dtos';
import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { CommunityRepository } from '@app/common/modules/community/repositories'; 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 { generateRandomString } from '@app/common/helper/randomString';
import { SpaceLinkService } from './space-link'; import { SpaceLinkService } from './space-link';
import { SpaceProductService } from './space-products'; import { SpaceProductService } from './space-products';
import { ProjectRepository } from '@app/common/modules/project/repositiories';
@Injectable() @Injectable()
export class SpaceService { export class SpaceService {
@ -21,15 +22,19 @@ export class SpaceService {
private readonly communityRepository: CommunityRepository, private readonly communityRepository: CommunityRepository,
private readonly spaceLinkService: SpaceLinkService, private readonly spaceLinkService: SpaceLinkService,
private readonly spaceProductService: SpaceProductService, private readonly spaceProductService: SpaceProductService,
private readonly projectRepository: ProjectRepository,
) {} ) {}
async createSpace( async createSpace(
addSpaceDto: AddSpaceDto, addSpaceDto: AddSpaceDto,
communityId: string, params: CommunitySpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { parentUuid, direction, products } = addSpaceDto; 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; const parent = parentUuid ? await this.validateSpace(parentUuid) : null;
try { try {
@ -67,9 +72,11 @@ export class SpaceService {
} }
async getSpacesHierarchyForCommunity( async getSpacesHierarchyForCommunity(
communityUuid: string, params: CommunitySpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { communityUuid, projectUuid } = params;
await this.validateCommunity(communityUuid); await this.validateCommunity(communityUuid);
await this.validateProject(projectUuid);
try { try {
// Get all spaces related to the community, including the parent-child relations // Get all spaces related to the community, including the parent-child relations
const spaces = await this.spaceRepository.find({ const spaces = await this.spaceRepository.find({
@ -80,7 +87,7 @@ export class SpaceService {
'incomingConnections', 'incomingConnections',
'spaceProducts', 'spaceProducts',
'spaceProducts.product', 'spaceProducts.product',
], // Include parent and children relations ],
}); });
// Organize spaces into a hierarchical structure // Organize spaces into a hierarchical structure
@ -99,9 +106,14 @@ export class SpaceService {
} }
} }
async findOne(spaceUuid: string): Promise<BaseResponseDto> { async findOne(params: GetSpaceParam): Promise<BaseResponseDto> {
const { communityUuid, spaceUuid, projectUuid } = params;
try { try {
const space = await this.validateSpace(spaceUuid); const space = await this.validateCommunityAndSpace(
communityUuid,
spaceUuid,
projectUuid,
);
return new SuccessResponseDto({ return new SuccessResponseDto({
message: `Space with ID ${spaceUuid} successfully fetched`, message: `Space with ID ${spaceUuid} successfully fetched`,
@ -119,15 +131,14 @@ export class SpaceService {
} }
} }
async delete( async delete(params: GetSpaceParam): Promise<BaseResponseDto> {
spaceUuid: string,
communityUuid: string,
): Promise<BaseResponseDto> {
try { try {
const { communityUuid, spaceUuid, projectUuid } = params;
// First, check if the community exists // First, check if the community exists
const space = await this.validateCommunityAndSpace( const space = await this.validateCommunityAndSpace(
communityUuid, communityUuid,
spaceUuid, spaceUuid,
projectUuid,
); );
// Delete the space // Delete the space
@ -149,14 +160,15 @@ export class SpaceService {
} }
async updateSpace( async updateSpace(
spaceUuid: string, params: GetSpaceParam,
communityId: string, updateSpaceDto: UpdateSpaceDto,
updateSpaceDto: AddSpaceDto,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { communityUuid, spaceUuid, projectUuid } = params;
try { try {
const space = await this.validateCommunityAndSpace( const space = await this.validateCommunityAndSpace(
communityId, communityUuid,
spaceUuid, spaceUuid,
projectUuid,
); );
// If a parentId is provided, check if the parent exists // If a parentId is provided, check if the parent exists
@ -193,9 +205,10 @@ export class SpaceService {
} }
async getSpacesHierarchyForSpace( async getSpacesHierarchyForSpace(
spaceUuid: string, params: GetSpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
await this.validateSpace(spaceUuid); const { spaceUuid, communityUuid, projectUuid } = params;
await this.validateCommunityAndSpace(communityUuid, spaceUuid, projectUuid);
try { try {
// Get all spaces that are children of the provided space, including the parent-child relations // 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<any> { async getSpaceInvitationCode(params: GetSpaceParam): Promise<any> {
const { communityUuid, spaceUuid, projectUuid } = params;
try { try {
const invitationCode = generateRandomString(6); const invitationCode = generateRandomString(6);
const space = await this.validateSpace(spaceUuid); const space = await this.validateCommunityAndSpace(
communityUuid,
spaceUuid,
projectUuid,
);
space.invitationCode = invitationCode; space.invitationCode = invitationCode;
await this.spaceRepository.save(space); await this.spaceRepository.save(space);
@ -283,7 +301,13 @@ export class SpaceService {
return community; 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); const community = await this.validateCommunity(communityUuid);
if (!community) { if (!community) {
this.throwNotFound('Community', communityUuid); this.throwNotFound('Community', communityUuid);
@ -301,6 +325,14 @@ export class SpaceService {
return space; 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) { private throwNotFound(entity: string, uuid: string) {
throw new HttpException( throw new HttpException(
`${entity} with ID ${uuid} not found`, `${entity} with ID ${uuid} not found`,

View File

@ -12,6 +12,7 @@ import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { ProductRepository } from '@app/common/modules/product/repositories'; import { ProductRepository } from '@app/common/modules/product/repositories';
import { GetDeviceDetailsInterface } from '../../../device/interfaces/get.device.interface'; import { GetDeviceDetailsInterface } from '../../../device/interfaces/get.device.interface';
import { SpaceService } from '../space.service';
@Injectable() @Injectable()
export class SubspaceDeviceService { export class SubspaceDeviceService {
@ -22,14 +23,19 @@ export class SubspaceDeviceService {
private readonly deviceRepository: DeviceRepository, private readonly deviceRepository: DeviceRepository,
private readonly tuyaService: TuyaService, private readonly tuyaService: TuyaService,
private readonly productRepository: ProductRepository, private readonly productRepository: ProductRepository,
private readonly spaceService: SpaceService,
) {} ) {}
async listDevicesInSubspace( async listDevicesInSubspace(
params: GetSubSpaceParam, params: GetSubSpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { subSpaceUuid, spaceUuid, communityUuid } = params; const { subSpaceUuid, spaceUuid, communityUuid, projectUuid } = params;
await this.validateCommunityAndSpace(communityUuid, spaceUuid); await this.spaceService.validateCommunityAndSpace(
communityUuid,
spaceUuid,
projectUuid,
);
const subspace = await this.findSubspaceWithDevices(subSpaceUuid); const subspace = await this.findSubspaceWithDevices(subSpaceUuid);
@ -67,9 +73,14 @@ export class SubspaceDeviceService {
async associateDeviceToSubspace( async associateDeviceToSubspace(
params: DeviceSubSpaceParam, params: DeviceSubSpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { subSpaceUuid, deviceUuid, spaceUuid, communityUuid } = params; const { subSpaceUuid, deviceUuid, spaceUuid, communityUuid, projectUuid } =
params;
try { try {
await this.validateCommunityAndSpace(communityUuid, spaceUuid); await this.spaceService.validateCommunityAndSpace(
communityUuid,
spaceUuid,
projectUuid,
);
const subspace = await this.findSubspace(subSpaceUuid); const subspace = await this.findSubspace(subSpaceUuid);
const device = await this.findDevice(deviceUuid); const device = await this.findDevice(deviceUuid);
@ -97,9 +108,14 @@ export class SubspaceDeviceService {
async disassociateDeviceFromSubspace( async disassociateDeviceFromSubspace(
params: DeviceSubSpaceParam, params: DeviceSubSpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { subSpaceUuid, deviceUuid, spaceUuid, communityUuid } = params; const { subSpaceUuid, deviceUuid, spaceUuid, communityUuid, projectUuid } =
params;
try { try {
await this.validateCommunityAndSpace(communityUuid, spaceUuid); await this.spaceService.validateCommunityAndSpace(
communityUuid,
spaceUuid,
projectUuid,
);
const subspace = await this.findSubspace(subSpaceUuid); const subspace = await this.findSubspace(subSpaceUuid);
const device = await this.findDevice(deviceUuid); const device = await this.findDevice(deviceUuid);
@ -129,26 +145,6 @@ export class SubspaceDeviceService {
} }
} }
} }
// Helper method to validate community and space
private async validateCommunityAndSpace(
communityUuid: string,
spaceUuid: string,
) {
const community = await this.communityRepository.findOne({
where: { uuid: communityUuid },
});
if (!community) {
this.throwNotFound('Community', communityUuid);
}
const space = await this.spaceRepository.findOne({
where: { uuid: spaceUuid, community: { uuid: communityUuid } },
});
if (!space) {
this.throwNotFound('Space', spaceUuid);
}
return space;
}
// Helper method to find subspace with devices relation // Helper method to find subspace with devices relation
private async findSubspaceWithDevices(subSpaceUuid: string) { private async findSubspaceWithDevices(subSpaceUuid: string) {

View File

@ -1,9 +1,5 @@
import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { CommunityRepository } from '@app/common/modules/community/repositories'; import { SubspaceRepository } from '@app/common/modules/space/repositories';
import {
SpaceRepository,
SubspaceRepository,
} from '@app/common/modules/space/repositories';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { AddSubspaceDto, GetSpaceParam, GetSubSpaceParam } from '../../dtos'; import { AddSubspaceDto, GetSpaceParam, GetSubSpaceParam } from '../../dtos';
import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
@ -13,23 +9,24 @@ import {
} from '@app/common/models/typeOrmCustom.model'; } from '@app/common/models/typeOrmCustom.model';
import { PageResponse } from '@app/common/dto/pagination.response.dto'; import { PageResponse } from '@app/common/dto/pagination.response.dto';
import { SubspaceDto } from '@app/common/modules/space/dtos'; import { SubspaceDto } from '@app/common/modules/space/dtos';
import { SpaceService } from '../space.service';
@Injectable() @Injectable()
export class SubSpaceService { export class SubSpaceService {
constructor( constructor(
private readonly spaceRepository: SpaceRepository,
private readonly communityRepository: CommunityRepository,
private readonly subspaceRepository: SubspaceRepository, private readonly subspaceRepository: SubspaceRepository,
private readonly spaceService: SpaceService,
) {} ) {}
async createSubspace( async createSubspace(
addSubspaceDto: AddSubspaceDto, addSubspaceDto: AddSubspaceDto,
params: GetSpaceParam, params: GetSpaceParam,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { communityUuid, spaceUuid } = params; const { communityUuid, spaceUuid, projectUuid } = params;
const space = await this.validateCommunityAndSpace( const space = await this.spaceService.validateCommunityAndSpace(
communityUuid, communityUuid,
spaceUuid, spaceUuid,
projectUuid,
); );
try { try {
@ -54,8 +51,12 @@ export class SubSpaceService {
params: GetSpaceParam, params: GetSpaceParam,
pageable: Partial<TypeORMCustomModelFindAllQuery>, pageable: Partial<TypeORMCustomModelFindAllQuery>,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { communityUuid, spaceUuid } = params; const { communityUuid, spaceUuid, projectUuid } = params;
await this.validateCommunityAndSpace(communityUuid, spaceUuid); await this.spaceService.validateCommunityAndSpace(
communityUuid,
spaceUuid,
projectUuid,
);
try { try {
pageable.modelName = 'subspace'; pageable.modelName = 'subspace';
@ -74,8 +75,12 @@ export class SubSpaceService {
} }
async findOne(params: GetSubSpaceParam): Promise<BaseResponseDto> { async findOne(params: GetSubSpaceParam): Promise<BaseResponseDto> {
const { communityUuid, subSpaceUuid, spaceUuid } = params; const { communityUuid, subSpaceUuid, spaceUuid, projectUuid } = params;
await this.validateCommunityAndSpace(communityUuid, spaceUuid); await this.spaceService.validateCommunityAndSpace(
communityUuid,
spaceUuid,
projectUuid,
);
try { try {
const subSpace = await this.subspaceRepository.findOne({ const subSpace = await this.subspaceRepository.findOne({
where: { where: {
@ -110,8 +115,12 @@ export class SubSpaceService {
params: GetSubSpaceParam, params: GetSubSpaceParam,
updateSubSpaceDto: AddSubspaceDto, updateSubSpaceDto: AddSubspaceDto,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { spaceUuid, communityUuid, subSpaceUuid } = params; const { spaceUuid, communityUuid, subSpaceUuid, projectUuid } = params;
await this.validateCommunityAndSpace(communityUuid, spaceUuid); await this.spaceService.validateCommunityAndSpace(
communityUuid,
spaceUuid,
projectUuid,
);
const subSpace = await this.subspaceRepository.findOne({ const subSpace = await this.subspaceRepository.findOne({
where: { uuid: subSpaceUuid }, where: { uuid: subSpaceUuid },
@ -146,8 +155,12 @@ export class SubSpaceService {
} }
async delete(params: GetSubSpaceParam): Promise<BaseResponseDto> { async delete(params: GetSubSpaceParam): Promise<BaseResponseDto> {
const { spaceUuid, communityUuid, subSpaceUuid } = params; const { spaceUuid, communityUuid, subSpaceUuid, projectUuid } = params;
await this.validateCommunityAndSpace(communityUuid, spaceUuid); await this.spaceService.validateCommunityAndSpace(
communityUuid,
spaceUuid,
projectUuid,
);
const subspace = await this.subspaceRepository.findOne({ const subspace = await this.subspaceRepository.findOne({
where: { uuid: subSpaceUuid }, where: { uuid: subSpaceUuid },
@ -174,30 +187,4 @@ export class SubSpaceService {
); );
} }
} }
private async validateCommunityAndSpace(
communityUuid: string,
spaceUuid: string,
) {
const community = await this.communityRepository.findOne({
where: { uuid: communityUuid },
});
if (!community) {
throw new HttpException(
`Community with ID ${communityUuid} not found`,
HttpStatus.NOT_FOUND,
);
}
const space = await this.spaceRepository.findOne({
where: { uuid: spaceUuid, community: { uuid: communityUuid } },
});
if (!space) {
throw new HttpException(
`Space with ID ${spaceUuid} not found`,
HttpStatus.NOT_FOUND,
);
}
return space;
}
} }

View File

@ -42,6 +42,7 @@ import { DeviceService } from 'src/device/services';
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service'; import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories'; import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
import { ProjectRepository } from '@app/common/modules/project/repositiories';
@Module({ @Module({
imports: [ConfigModule, SpaceRepositoryModule], imports: [ConfigModule, SpaceRepositoryModule],
@ -79,6 +80,7 @@ import { SceneDeviceRepository } from '@app/common/modules/scene-device/reposito
SceneDeviceRepository, SceneDeviceRepository,
SpaceProductService, SpaceProductService,
SpaceProductRepository, SpaceProductRepository,
ProjectRepository,
], ],
exports: [SpaceService], exports: [SpaceService],
}) })