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.';
};
};
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-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,
UseGuards,
} from '@nestjs/common';
import { SubSpaceService } from '../services';
import { SubSpaceService } from '../../services';
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 { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
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 './get.subspace.param';
export * from './add.subspace-device.param';

View File

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

View File

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