subspace endpoints

This commit is contained in:
hannathkadher
2024-10-29 13:13:44 +04:00
parent 74428b408e
commit eb77f8ab99
13 changed files with 275 additions and 26 deletions

View File

@ -155,4 +155,26 @@ export class ControllerRoute {
'Deletes a specific subspace within a given space and community.'; 'Deletes a specific subspace within a given space and community.';
}; };
}; };
static SUBSPACE_DEVICE = class {
public static readonly ROUTE =
'/communities/:communityUuid/spaces/:spaceUuid/subspaces/:subSpaceUuid/devices';
static ACTIONS = class {
public static readonly LIST_SUBSPACE_DEVICE_SUMMARY =
'List devices in a subspace';
public static readonly LIST_SUBSPACE_DEVICE_DESCRIPTION =
'Retrieves a list of all devices associated with a specified subspace.';
public static readonly ASSOCIATE_SUBSPACE_DEVICE_SUMMARY =
'Associate a device to a subspace';
public static readonly ASSOCIATE_SUBSPACE_DEVICE_DESCRIPTION =
'Associates a device with a specific subspace, enabling it to be managed within that subspace context.';
public static readonly DISASSOCIATE_SUBSPACE_DEVICE_SUMMARY =
'Disassociate a device from a subspace';
public static readonly DISASSOCIATE_SUBSPACE_DEVICE_DESCRIPTION =
'Removes the association of a device from a specific subspace, making it no longer managed within that subspace.';
};
};
} }

View File

@ -1,3 +1,3 @@
export * from './space.controller'; export * from './space.controller';
export * from './space-user.controller'; export * from './space-user.controller';
export * from './subspace.controller'; export * from './subspace';

View File

@ -0,0 +1,2 @@
export * from './subspace.controller';
export * from './subspace-device.controller';

View File

@ -0,0 +1,64 @@
import { ControllerRoute } from '@app/common/constants/controller-route';
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
import { Controller, Get, Param, Post, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { DeviceSubSpaceParam, GetSubSpaceParam } from '../../dtos';
import { SubspaceDeviceService } from 'src/space/services';
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
@ApiTags('Space Module')
@Controller({
version: '1',
path: ControllerRoute.SUBSPACE_DEVICE.ROUTE,
})
export class SubSpaceDeviceController {
constructor(private readonly subspaceDeviceService: SubspaceDeviceService) {}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ApiOperation({
summary:
ControllerRoute.SUBSPACE_DEVICE.ACTIONS.LIST_SUBSPACE_DEVICE_SUMMARY,
description:
ControllerRoute.SUBSPACE_DEVICE.ACTIONS.LIST_SUBSPACE_DEVICE_DESCRIPTION,
})
@Get()
async listDevicesInSubspace(
@Param() params: GetSubSpaceParam,
): Promise<BaseResponseDto> {
return await this.subspaceDeviceService.listDevicesInSubspace(params);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ApiOperation({
summary:
ControllerRoute.SUBSPACE_DEVICE.ACTIONS.ASSOCIATE_SUBSPACE_DEVICE_SUMMARY,
description:
ControllerRoute.SUBSPACE_DEVICE.ACTIONS
.ASSOCIATE_SUBSPACE_DEVICE_DESCRIPTION,
})
@Post('/:deviceUuid')
async associateDeviceToSubspace(
@Param() params: DeviceSubSpaceParam,
): Promise<BaseResponseDto> {
return await this.subspaceDeviceService.associateDeviceToSubspace(params);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ApiOperation({
summary:
ControllerRoute.SUBSPACE_DEVICE.ACTIONS
.DISASSOCIATE_SUBSPACE_DEVICE_SUMMARY,
description:
ControllerRoute.SUBSPACE_DEVICE.ACTIONS
.DISASSOCIATE_SUBSPACE_DEVICE_DESCRIPTION,
})
@Post('/:deviceUuid')
async disassociateDeviceFromSubspace(
@Param() params: DeviceSubSpaceParam,
): Promise<BaseResponseDto> {
return await this.subspaceDeviceService.associateDeviceToSubspace(params);
}
}

View File

@ -10,9 +10,9 @@ import {
Query, Query,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { SubSpaceService } from '../services'; import { SubSpaceService } from '../../services';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { AddSubspaceDto, GetSpaceParam, GetSubSpaceParam } from '../dtos'; import { AddSubspaceDto, GetSpaceParam, GetSubSpaceParam } from '../../dtos';
import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
import { PaginationRequestGetListDto } from '@app/common/dto/pagination.request.dto'; import { PaginationRequestGetListDto } from '@app/common/dto/pagination.request.dto';

View File

@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsUUID } from 'class-validator';
import { GetSubSpaceParam } from './get.subspace.param';
export class DeviceSubSpaceParam extends GetSubSpaceParam {
@ApiProperty({
description: 'UUID of the device',
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
})
@IsUUID()
deviceUuid: string;
}

View File

@ -1,2 +1,3 @@
export * from './add.subspace.dto'; export * from './add.subspace.dto';
export * from './get.subspace.param'; export * from './get.subspace.param';
export * from './add.subspace-device.param';

View File

@ -1,3 +1,3 @@
export * from './space.service'; export * from './space.service';
export * from './space-user.service'; export * from './space-user.service';
export * from './subspace.service'; export * from './subspace';

View File

@ -107,23 +107,23 @@ export class SpaceService {
} }
} }
async findOne(spaceId: string): Promise<BaseResponseDto> { async findOne(spaceUuid: string): Promise<BaseResponseDto> {
try { try {
const space = await this.spaceRepository.findOne({ const space = await this.spaceRepository.findOne({
where: { where: {
uuid: spaceId, uuid: spaceUuid,
}, },
}); });
// If space is not found, throw a NotFoundException // If space is not found, throw a NotFoundException
if (!space) { if (!space) {
throw new HttpException( throw new HttpException(
`Space with UUID ${spaceId} not found`, `Space with UUID ${spaceUuid} not found`,
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
); );
} }
return new SuccessResponseDto({ return new SuccessResponseDto({
message: `Space with ID ${spaceId} successfully fetched`, message: `Space with ID ${spaceUuid} successfully fetched`,
data: space, data: space,
}); });
} catch (error) { } catch (error) {
@ -138,28 +138,31 @@ export class SpaceService {
} }
} }
async delete(spaceId: string, communityId: string): Promise<BaseResponseDto> { async delete(
spaceUuid: string,
communityUuid: string,
): Promise<BaseResponseDto> {
try { try {
// First, check if the community exists // First, check if the community exists
const community = await this.communityRepository.findOne({ const community = await this.communityRepository.findOne({
where: { uuid: communityId }, where: { uuid: communityUuid },
}); });
if (!community) { if (!community) {
throw new HttpException( throw new HttpException(
`Community with ID ${communityId} not found`, `Community with ID ${communityUuid} not found`,
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
); );
} }
// Check if the space exists // Check if the space exists
const space = await this.spaceRepository.findOne({ const space = await this.spaceRepository.findOne({
where: { uuid: spaceId, community: { uuid: communityId } }, where: { uuid: spaceUuid, community: { uuid: communityUuid } },
}); });
if (!space) { if (!space) {
throw new HttpException( throw new HttpException(
`Space with ID ${spaceId} not found`, `Space with ID ${spaceUuid} not found`,
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
); );
} }
@ -168,7 +171,7 @@ export class SpaceService {
await this.spaceRepository.remove(space); await this.spaceRepository.remove(space);
return new SuccessResponseDto({ return new SuccessResponseDto({
message: `Space with ID ${spaceId} successfully deleted`, message: `Space with ID ${spaceUuid} successfully deleted`,
statusCode: HttpStatus.OK, statusCode: HttpStatus.OK,
}); });
} catch (error) { } catch (error) {
@ -183,7 +186,7 @@ export class SpaceService {
} }
async updateSpace( async updateSpace(
spaceId: string, spaceUuid: string,
communityId: string, communityId: string,
updateSpaceDto: AddSpaceDto, updateSpaceDto: AddSpaceDto,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
@ -202,12 +205,12 @@ export class SpaceService {
// Check if the space exists // Check if the space exists
const space = await this.spaceRepository.findOne({ const space = await this.spaceRepository.findOne({
where: { uuid: spaceId, community: { uuid: communityId } }, where: { uuid: spaceUuid, community: { uuid: communityId } },
}); });
if (!space) { if (!space) {
throw new HttpException( throw new HttpException(
`Space with ID ${spaceId} not found`, `Space with ID ${spaceUuid} not found`,
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
); );
} }
@ -241,7 +244,7 @@ export class SpaceService {
await this.spaceRepository.save(space); await this.spaceRepository.save(space);
return new SuccessResponseDto({ return new SuccessResponseDto({
message: `Space with ID ${spaceId} successfully updated`, message: `Space with ID ${spaceUuid} successfully updated`,
data: space, data: space,
statusCode: HttpStatus.OK, statusCode: HttpStatus.OK,
}); });
@ -256,15 +259,17 @@ export class SpaceService {
} }
} }
async getSpacesHierarchyForSpace(spaceId: string): Promise<BaseResponseDto> { async getSpacesHierarchyForSpace(
spaceUuid: string,
): Promise<BaseResponseDto> {
const space = await this.spaceRepository.findOne({ const space = await this.spaceRepository.findOne({
where: { uuid: spaceId }, where: { uuid: spaceUuid },
}); });
// If the space doesn't exist, throw a 404 error // If the space doesn't exist, throw a 404 error
if (!space) { if (!space) {
throw new HttpException( throw new HttpException(
`Space with ID ${spaceId} not found`, `Space with ID ${spaceUuid} not found`,
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
); );
} }
@ -272,7 +277,7 @@ export class SpaceService {
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
const spaces = await this.spaceRepository.find({ const spaces = await this.spaceRepository.find({
where: { parent: { uuid: spaceId } }, where: { parent: { uuid: spaceUuid } },
relations: ['parent', 'children'], // Include parent and children relations relations: ['parent', 'children'], // Include parent and children relations
}); });
@ -280,7 +285,7 @@ export class SpaceService {
const spaceHierarchy = this.buildSpaceHierarchy(spaces); const spaceHierarchy = this.buildSpaceHierarchy(spaces);
return new SuccessResponseDto({ return new SuccessResponseDto({
message: `Spaces under space ${spaceId} successfully fetched in hierarchy`, message: `Spaces under space ${spaceUuid} successfully fetched in hierarchy`,
data: spaceHierarchy, data: spaceHierarchy,
statusCode: HttpStatus.OK, statusCode: HttpStatus.OK,
}); });

View File

@ -0,0 +1,2 @@
export * from './subspace.service';
export * from './subspace-device.service';

View File

@ -0,0 +1,128 @@
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
import { DeviceRepository } from '@app/common/modules/device/repositories';
import {
SpaceRepository,
SubspaceRepository,
} from '@app/common/modules/space/repositories';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { DeviceSubSpaceParam, GetSubSpaceParam } from '../../dtos';
import { CommunityRepository } from '@app/common/modules/community/repositories';
@Injectable()
export class SubspaceDeviceService {
constructor(
private readonly spaceRepository: SpaceRepository,
private readonly communityRepository: CommunityRepository,
private readonly subspaceRepository: SubspaceRepository,
private readonly deviceRepository: DeviceRepository,
) {}
async listDevicesInSubspace(
params: GetSubSpaceParam,
): Promise<BaseResponseDto> {
const { subSpaceUuid, spaceUuid, communityUuid } = params;
await this.validateCommunityAndSpace(communityUuid, spaceUuid);
const subspace = await this.findSubspaceWithDevices(subSpaceUuid);
return new SuccessResponseDto({
data: subspace.devices,
message: 'Successfully retrieved list of devices',
});
}
async associateDeviceToSubspace(params: DeviceSubSpaceParam) {
const { subSpaceUuid, deviceUuid, spaceUuid, communityUuid } = params;
await this.validateCommunityAndSpace(communityUuid, spaceUuid);
const subspace = await this.findSubspace(subSpaceUuid);
const device = await this.findDevice(deviceUuid);
device.subspace = subspace;
await this.deviceRepository.save(device);
return new SuccessResponseDto({
data: device,
message: 'Successfully associated device to subspace',
});
}
async disassociateDeviceFromSubspace(params: DeviceSubSpaceParam) {
const { subSpaceUuid, deviceUuid, spaceUuid, communityUuid } = params;
await this.validateCommunityAndSpace(communityUuid, spaceUuid);
await this.findSubspace(subSpaceUuid);
const device = await this.findDevice(deviceUuid);
device.subspace = null;
await this.deviceRepository.save(device);
return new SuccessResponseDto({
data: device,
message: 'Successfully dissociated device from subspace',
});
}
// 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
private async findSubspaceWithDevices(subSpaceUuid: string) {
const subspace = await this.subspaceRepository.findOne({
where: { uuid: subSpaceUuid },
relations: ['devices'],
});
if (!subspace) {
this.throwNotFound('Subspace', subSpaceUuid);
}
return subspace;
}
private async findSubspace(subSpaceUuid: string) {
const subspace = await this.subspaceRepository.findOne({
where: { uuid: subSpaceUuid },
});
if (!subspace) {
this.throwNotFound('Subspace', subSpaceUuid);
}
return subspace;
}
private async findDevice(deviceUuid: string) {
const device = await this.deviceRepository.findOne({
where: { uuid: deviceUuid },
});
if (!device) {
this.throwNotFound('Device', deviceUuid);
}
return device;
}
private throwNotFound(entity: string, uuid: string) {
throw new HttpException(
`${entity} with ID ${uuid} not found`,
HttpStatus.NOT_FOUND,
);
}
}

View File

@ -5,7 +5,7 @@ import {
SubspaceRepository, SubspaceRepository,
} from '@app/common/modules/space/repositories'; } 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';
import { import {
TypeORMCustomModel, TypeORMCustomModel,

View File

@ -6,7 +6,12 @@ import {
SpaceUserController, SpaceUserController,
SubSpaceController, SubSpaceController,
} from './controllers'; } from './controllers';
import { SpaceService, SpaceUserService, SubSpaceService } from './services'; import {
SpaceService,
SpaceUserService,
SubspaceDeviceService,
SubSpaceService,
} from './services';
import { import {
SpaceRepository, SpaceRepository,
SubspaceRepository, SubspaceRepository,
@ -16,14 +21,22 @@ import {
UserRepository, UserRepository,
UserSpaceRepository, UserSpaceRepository,
} from '@app/common/modules/user/repositories'; } from '@app/common/modules/user/repositories';
import { DeviceRepository } from '@app/common/modules/device/repositories';
@Module({ @Module({
imports: [ConfigModule, SpaceRepositoryModule], imports: [ConfigModule, SpaceRepositoryModule],
controllers: [SpaceController, SpaceUserController, SubSpaceController], controllers: [
SpaceController,
SpaceUserController,
SubSpaceController,
SubSpaceController,
],
providers: [ providers: [
SpaceService, SpaceService,
SubSpaceService, SubSpaceService,
SubspaceDeviceService,
SpaceRepository, SpaceRepository,
DeviceRepository,
CommunityRepository, CommunityRepository,
SubspaceRepository, SubspaceRepository,
UserSpaceRepository, UserSpaceRepository,