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:
hannathkadher
2025-02-12 11:13:37 +04:00
committed by GitHub
11 changed files with 211 additions and 1 deletions

View File

@ -318,6 +318,19 @@ export class ControllerRoute {
'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 {
public static readonly ROUTE = '/user';

View File

@ -3,7 +3,7 @@ import { NewTagEntity } from '../entities';
import { DataSource, Repository } from 'typeorm';
@Injectable()
export class NewTagRepository extends Repository<NewTagRepository> {
export class NewTagRepository extends Repository<NewTagEntity> {
constructor(private dataSource: DataSource) {
super(NewTagEntity, dataSource.createEntityManager());
}

View File

@ -28,6 +28,7 @@ import { PermissionModule } from './permission/permission.module';
import { RoleModule } from './role/role.module';
import { TermsConditionsModule } from './terms-conditions/terms-conditions.module';
import { PrivacyPolicyModule } from './privacy-policy/privacy-policy.module';
import { TagModule } from './tags/tags.module';
@Module({
imports: [
ConfigModule.forRoot({
@ -59,6 +60,7 @@ import { PrivacyPolicyModule } from './privacy-policy/privacy-policy.module';
RoleModule,
TermsConditionsModule,
PrivacyPolicyModule,
TagModule,
],
providers: [
{

View File

@ -0,0 +1 @@
export * from './tags.controller';

View 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);
}
}

View 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
View File

@ -0,0 +1 @@
export * from './tags.dto';

28
src/tags/dtos/tags.dto.ts Normal file
View 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;
}

View File

@ -0,0 +1 @@
export * from './tags.service';

View 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
View 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 {}