mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-15 02:15:21 +00:00
Merge pull request #254 from SyncrowIOT/SP-1180-be-create-tag-endpoint-fore-create-list-tags
Add Tag Module with CRUD operations
This commit is contained in:
@ -318,6 +318,19 @@ export class ControllerRoute {
|
|||||||
'Fetches a list of all products along with their associated device details';
|
'Fetches a list of all products along with their associated device details';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static TAG = class {
|
||||||
|
public static readonly ROUTE = 'tags';
|
||||||
|
static ACTIONS = class {
|
||||||
|
public static readonly CREATE_TAG_SUMMARY = 'Create a new tag';
|
||||||
|
public static readonly CREATE_TAG_DESCRIPTION =
|
||||||
|
'Creates a new tag and assigns it to a specific project and product.';
|
||||||
|
public static readonly GET_TAGS_BY_PROJECT_SUMMARY =
|
||||||
|
'Get tags by project';
|
||||||
|
public static readonly GET_TAGS_BY_PROJECT_DESCRIPTION =
|
||||||
|
'Retrieves a list of tags associated with a specific project.';
|
||||||
|
};
|
||||||
|
};
|
||||||
static USER = class {
|
static USER = class {
|
||||||
public static readonly ROUTE = '/user';
|
public static readonly ROUTE = '/user';
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { NewTagEntity } from '../entities';
|
|||||||
import { DataSource, Repository } from 'typeorm';
|
import { DataSource, Repository } from 'typeorm';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NewTagRepository extends Repository<NewTagRepository> {
|
export class NewTagRepository extends Repository<NewTagEntity> {
|
||||||
constructor(private dataSource: DataSource) {
|
constructor(private dataSource: DataSource) {
|
||||||
super(NewTagEntity, dataSource.createEntityManager());
|
super(NewTagEntity, dataSource.createEntityManager());
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import { PermissionModule } from './permission/permission.module';
|
|||||||
import { RoleModule } from './role/role.module';
|
import { RoleModule } from './role/role.module';
|
||||||
import { TermsConditionsModule } from './terms-conditions/terms-conditions.module';
|
import { TermsConditionsModule } from './terms-conditions/terms-conditions.module';
|
||||||
import { PrivacyPolicyModule } from './privacy-policy/privacy-policy.module';
|
import { PrivacyPolicyModule } from './privacy-policy/privacy-policy.module';
|
||||||
|
import { TagModule } from './tags/tags.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
@ -59,6 +60,7 @@ import { PrivacyPolicyModule } from './privacy-policy/privacy-policy.module';
|
|||||||
RoleModule,
|
RoleModule,
|
||||||
TermsConditionsModule,
|
TermsConditionsModule,
|
||||||
PrivacyPolicyModule,
|
PrivacyPolicyModule,
|
||||||
|
TagModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
|
1
src/tags/controllers/index.ts
Normal file
1
src/tags/controllers/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './tags.controller';
|
42
src/tags/controllers/tags.controller.ts
Normal file
42
src/tags/controllers/tags.controller.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common';
|
||||||
|
import { TagService } from '../services/tags.service';
|
||||||
|
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
|
||||||
|
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
import { ControllerRoute } from '@app/common/constants/controller-route';
|
||||||
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
import { CreateTagDto } from '../dtos/tags.dto';
|
||||||
|
import { GetTagsParam } from '../dtos/get-tags.param';
|
||||||
|
|
||||||
|
@ApiTags('Tag Module')
|
||||||
|
@Controller({
|
||||||
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
|
path: ControllerRoute.TAG.ROUTE,
|
||||||
|
})
|
||||||
|
export class TagController {
|
||||||
|
constructor(private readonly tagService: TagService) {}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Post()
|
||||||
|
@ApiOperation({
|
||||||
|
summary: ControllerRoute.TAG.ACTIONS.CREATE_TAG_SUMMARY,
|
||||||
|
description: ControllerRoute.TAG.ACTIONS.CREATE_TAG_DESCRIPTION,
|
||||||
|
})
|
||||||
|
async createTag(@Body() dto: CreateTagDto): Promise<BaseResponseDto> {
|
||||||
|
return this.tagService.createTag(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Get('project/:projectUuid')
|
||||||
|
@ApiOperation({
|
||||||
|
summary: ControllerRoute.TAG.ACTIONS.GET_TAGS_BY_PROJECT_SUMMARY,
|
||||||
|
description: ControllerRoute.TAG.ACTIONS.GET_TAGS_BY_PROJECT_DESCRIPTION,
|
||||||
|
})
|
||||||
|
async getTagsByProject(
|
||||||
|
@Param() params: GetTagsParam,
|
||||||
|
): Promise<BaseResponseDto> {
|
||||||
|
return this.tagService.getTagsByProjectUuid(params);
|
||||||
|
}
|
||||||
|
}
|
11
src/tags/dtos/get-tags.param.ts
Normal file
11
src/tags/dtos/get-tags.param.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsUUID } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetTagsParam {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'UUID of the Project',
|
||||||
|
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
|
||||||
|
})
|
||||||
|
@IsUUID()
|
||||||
|
projectUuid: string;
|
||||||
|
}
|
1
src/tags/dtos/index.ts
Normal file
1
src/tags/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './tags.dto';
|
28
src/tags/dtos/tags.dto.ts
Normal file
28
src/tags/dtos/tags.dto.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { IsNotEmpty, IsUUID, IsString } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class CreateTagDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The name of the tag',
|
||||||
|
example: 'New Tag',
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'UUID of the product associated with the tag',
|
||||||
|
example: '550e8400-e29b-41d4-a716-446655440000',
|
||||||
|
})
|
||||||
|
@IsUUID()
|
||||||
|
@IsNotEmpty()
|
||||||
|
productUuid: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'UUID of the project associated with the tag',
|
||||||
|
example: '123e4567-e89b-12d3-a456-426614174000',
|
||||||
|
})
|
||||||
|
@IsUUID()
|
||||||
|
@IsNotEmpty()
|
||||||
|
projectUuid: string;
|
||||||
|
}
|
1
src/tags/services/index.ts
Normal file
1
src/tags/services/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './tags.service';
|
91
src/tags/services/tags.service.ts
Normal file
91
src/tags/services/tags.service.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
||||||
|
import {
|
||||||
|
Injectable,
|
||||||
|
ConflictException,
|
||||||
|
NotFoundException,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { CreateTagDto } from '../dtos/tags.dto';
|
||||||
|
import { ProductEntity } from '@app/common/modules/product/entities';
|
||||||
|
import { ProjectEntity } from '@app/common/modules/project/entities';
|
||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
import { NewTagEntity } from '@app/common/modules/tag';
|
||||||
|
import { GetTagsParam } from '../dtos/get-tags.param';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TagService {
|
||||||
|
constructor(
|
||||||
|
private readonly tagRepository: NewTagRepository,
|
||||||
|
private readonly productRepository: ProductRepository,
|
||||||
|
private readonly projectRepository: ProjectRepository,
|
||||||
|
) {}
|
||||||
|
async getTagsByProjectUuid(params: GetTagsParam): Promise<BaseResponseDto> {
|
||||||
|
const { projectUuid } = params;
|
||||||
|
await this.getProjectByUuid(projectUuid);
|
||||||
|
|
||||||
|
const tags = await this.tagRepository.find({
|
||||||
|
where: { project: { uuid: projectUuid } },
|
||||||
|
relations: ['product', 'project'],
|
||||||
|
});
|
||||||
|
|
||||||
|
return new SuccessResponseDto({
|
||||||
|
message: `Tags retrieved successfully for project UUID: ${projectUuid}`,
|
||||||
|
data: tags,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async createTag(dto: CreateTagDto): Promise<BaseResponseDto> {
|
||||||
|
const { name, productUuid, projectUuid } = dto;
|
||||||
|
|
||||||
|
const product = await this.getProductByUuid(productUuid);
|
||||||
|
const project = await this.getProjectByUuid(projectUuid);
|
||||||
|
|
||||||
|
await this.validateTagUniqueness(name, projectUuid);
|
||||||
|
|
||||||
|
const tag = this.tagRepository.create({
|
||||||
|
name,
|
||||||
|
product,
|
||||||
|
project,
|
||||||
|
} as Partial<NewTagEntity>);
|
||||||
|
|
||||||
|
await this.tagRepository.save(tag);
|
||||||
|
|
||||||
|
return new SuccessResponseDto({
|
||||||
|
message: `Tag created successfully`,
|
||||||
|
data: tag,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getProductByUuid(uuid: string): Promise<ProductEntity> {
|
||||||
|
const product = await this.productRepository.findOne({ where: { uuid } });
|
||||||
|
if (!product) {
|
||||||
|
throw new NotFoundException(`Product with UUID ${uuid} not found.`);
|
||||||
|
}
|
||||||
|
return product;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getProjectByUuid(uuid: string): Promise<ProjectEntity> {
|
||||||
|
const project = await this.projectRepository.findOne({ where: { uuid } });
|
||||||
|
if (!project) {
|
||||||
|
throw new NotFoundException(`Project with UUID ${uuid} not found.`);
|
||||||
|
}
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async validateTagUniqueness(
|
||||||
|
name: string,
|
||||||
|
projectUuid: string,
|
||||||
|
): Promise<void> {
|
||||||
|
const existingTag = await this.tagRepository.findOne({
|
||||||
|
where: { name, project: { uuid: projectUuid } },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingTag) {
|
||||||
|
throw new ConflictException(
|
||||||
|
`Tag with name "${name}" already exists in this project.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/tags/tags.module.ts
Normal file
20
src/tags/tags.module.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { TagController } from './controllers';
|
||||||
|
import { TagService } from './services';
|
||||||
|
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
||||||
|
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
controllers: [TagController],
|
||||||
|
providers: [
|
||||||
|
TagService,
|
||||||
|
NewTagRepository,
|
||||||
|
ProductRepository,
|
||||||
|
ProjectRepository,
|
||||||
|
],
|
||||||
|
exports: [TagService],
|
||||||
|
})
|
||||||
|
export class TagModule {}
|
Reference in New Issue
Block a user