diff --git a/.env.example b/.env.example index 642771bd..b612a9ea 100644 --- a/.env.example +++ b/.env.example @@ -88,4 +88,7 @@ KMS_ACCESS_KEY_ID= KMS_SECRET_ACCESS_KEY= KMS_REGION= KMS_API_VERSION= -KMS_ALIAS= \ No newline at end of file +KMS_ALIAS= + +# Private Name Tag +LIMITED_PRIVATE_NAME_TAG=10 diff --git a/src/components/private-name-tag/controllers/private-name-tag.controller.ts b/src/components/private-name-tag/controllers/private-name-tag.controller.ts index f7baa050..acebf9b9 100644 --- a/src/components/private-name-tag/controllers/private-name-tag.controller.ts +++ b/src/components/private-name-tag/controllers/private-name-tag.controller.ts @@ -40,7 +40,6 @@ import { Roles } from '../../../auth/role/roles.decorator'; import { JwtAuthGuard } from '../../../auth/jwt/jwt-auth.guard'; import { PrivateNameTag } from '../../../shared/entities/private-name-tag.entity'; import { GetPrivateNameTagAdminResult } from '../dtos/get-private-name-tag-admin.dto'; -import { GetPrivateNameTagResult } from '../dtos/get-private-name-tag-result.dto'; import { UpdatePrivateNameTagParamsDto } from '../dtos/update-private-name-tag-params.dto'; @Controller() @@ -138,47 +137,4 @@ export class PrivateNameTagController { this.logger.log(ctx, `${this.deleteNameTag.name} was called!`); return await this.nameTagService.deleteNameTag(ctx, id); } - - @Get('private-name-tag') - @UseGuards(JwtAuthGuard, RoleGuard) - @Roles(USER_ROLE.ADMIN, USER_ROLE.USER) - @ApiBearerAuth() - @ApiResponse({ status: HttpStatus.OK }) - @HttpCode(HttpStatus.OK) - @ApiOperation({ summary: 'Get all private name tag.' }) - @ApiOkResponse({ - description: 'Get all private name tag.', - type: GetPrivateNameTagResult, - }) - @ApiQuery({ - name: 'limit', - type: Number, - required: false, - description: 'Number of private name tag per page. Max is 500.', - }) - @ApiQuery({ - name: 'nextKey', - type: Number, - required: false, - description: 'Key for next page.', - }) - @ApiQuery({ - name: 'keyword', - type: String, - required: false, - description: 'Key for search: Address/Name Tag.', - }) - async getNameTag( - @ReqContext() ctx: RequestContext, - @Query('limit') limit?: number, - @Query('nextKey') nextKey?: number, - @Query('keyword') keyword?: string, - ): Promise { - return await this.nameTagService.getNameTagMainSite({ - user_id: ctx.user?.id || 0, - limit, - nextKey, - keyword, - }); - } } diff --git a/src/components/private-name-tag/dtos/get-private-name-tag-result.dto.ts b/src/components/private-name-tag/dtos/get-private-name-tag-result.dto.ts deleted file mode 100644 index 0c0a9690..00000000 --- a/src/components/private-name-tag/dtos/get-private-name-tag-result.dto.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; - -class PrivateNameTagResponseAttributes { - @ApiProperty({ example: 1 }) - id: number; - - @ApiProperty({ - example: 'aura1dylphmzd0gkdpuvyy3h7u5ffr8x0y2eajj0q5w2q8txnw33g0k0ss34cjy', - }) - address: string; - - @ApiProperty({ example: false }) - isFavorite: boolean; - - @ApiProperty({ example: 'private-name-tag' }) - nameTag: string; - - @ApiProperty({ example: 'note' }) - note: string; - - @ApiProperty({ example: '2023-07-31T02:55:47.994Z' }) - createdAt: Date; - - @ApiProperty({ example: '2023-07-31T02:55:47.994Z' }) - updatedAt: Date; -} - -class ListPrivateNameTag { - @ApiProperty({ isArray: true, type: PrivateNameTagResponseAttributes }) - nameTags: PrivateNameTagResponseAttributes[]; - - @ApiProperty() - count: number; - - @ApiProperty() - nextKey: number; -} - -export class GetPrivateNameTagResult { - @ApiProperty() - data: ListPrivateNameTag; -} diff --git a/src/components/private-name-tag/repositories/private-name-tag.repository.ts b/src/components/private-name-tag/repositories/private-name-tag.repository.ts index 9dbcf233..c7f64d54 100644 --- a/src/components/private-name-tag/repositories/private-name-tag.repository.ts +++ b/src/components/private-name-tag/repositories/private-name-tag.repository.ts @@ -18,6 +18,7 @@ export class PrivateNameTagRepository extends Repository { async getNameTags( user_id: number, keyword: string, + keywordEncrypt: string, limit: number, offset: number, ) { @@ -53,10 +54,10 @@ export class PrivateNameTagRepository extends Repository { if (keyword) { builder.andWhere( new Brackets((qb) => { - qb.where('LOWER(tag.address) LIKE LOWER(:keyword)', { - keyword: `%${keyword}%`, - }).orWhere('tag.name_tag LIKE :keyword', { - keyword: `%${keyword}%`, + qb.where('tag.address = :keyword', { + keyword: `${keyword}`, + }).orWhere('tag.name_tag = :keywordEncrypt', { + keywordEncrypt: `${keywordEncrypt}`, }); }), ); @@ -64,50 +65,4 @@ export class PrivateNameTagRepository extends Repository { return await _finalizeResult(); } - - async getNameTagMainSite( - user_id: number, - limit: number, - nextKey: number, - keyword: string, - keywordEncrypt: string, - ): Promise { - limit = Number(limit) || PAGE_REQUEST.MAX_500; - - if (limit > PAGE_REQUEST.MAX_500) { - limit = PAGE_REQUEST.MAX_500; - } - - let qb = this.createQueryBuilder() - .select([ - 'id', - 'is_favorite as isFavorite', - 'address', - 'name_tag as nameTag', - 'note', - 'created_at as createdAt', - 'updated_at as updatedAt', - ]) - .where('created_by = :user_id', { user_id }) - .orderBy('is_favorite', 'DESC') - .addOrderBy('updated_at', 'DESC') - .limit(Number(limit) || PAGE_REQUEST.MAX_500); - - if (nextKey) { - qb = qb.andWhere('id > :nextKey', { nextKey }); - } - - if (keyword) { - qb.andWhere( - new Brackets((qb) => { - qb.where('address = :keyword', { keyword }).orWhere( - 'name_tag = :keywordEncrypt', - { keywordEncrypt: keywordEncrypt }, - ); - }), - ); - } - - return qb.getRawMany(); - } } diff --git a/src/components/private-name-tag/services/private-name-tag.service.ts b/src/components/private-name-tag/services/private-name-tag.service.ts index 1855eb37..d6d60d5b 100644 --- a/src/components/private-name-tag/services/private-name-tag.service.ts +++ b/src/components/private-name-tag/services/private-name-tag.service.ts @@ -14,27 +14,32 @@ import { import { PrivateNameTagParamsDto } from '../dtos/private-name-tag-params.dto'; import { PrivateNameTagRepository } from '../repositories/private-name-tag.repository'; import { CreatePrivateNameTagParamsDto } from '../dtos/create-private-name-tag-params.dto'; -import { GetPrivateNameTagResult } from '../dtos/get-private-name-tag-result.dto'; import { PrivateNameTag } from '../../../shared/entities/private-name-tag.entity'; import { UpdatePrivateNameTagParamsDto } from '../dtos/update-private-name-tag-params.dto'; import { EncryptionService } from '../../encryption/encryption.service'; import { ServiceUtil } from '../../../shared/utils/service.util'; import { Not } from 'typeorm'; +import * as appConfig from '../../../shared/configs/configuration'; @Injectable() export class PrivateNameTagService { + private config; + constructor( private readonly logger: AkcLogger, private encryptionService: EncryptionService, private privateNameTagRepository: PrivateNameTagRepository, private serviceUtil: ServiceUtil, - ) {} + ) { + this.config = appConfig.default(); + } async getNameTags(ctx: RequestContext, req: PrivateNameTagParamsDto) { this.logger.log(ctx, `${this.getNameTags.name} was called!`); const { result, count } = await this.privateNameTagRepository.getNameTags( ctx.user.id, req.keyword, + await this.encryptionService.encrypt(req.keyword ?? ''), req.limit, req.offset, ); @@ -169,6 +174,18 @@ export class PrivateNameTagService { }; } + // check limited private name tag + const count = await this.privateNameTagRepository.count({ + where: { createdBy: user_id }, + }); + + if (count >= this.config.limitedPrivateNameTag) { + return { + code: ADMIN_ERROR_MAP.LIMIT_PRIVATE_NAME_TAG.Code, + message: ADMIN_ERROR_MAP.LIMIT_PRIVATE_NAME_TAG.Message, + }; + } + // check duplicate address const entity = await this.privateNameTagRepository.findOne({ where: { createdBy: user_id, address: req.address }, @@ -186,7 +203,7 @@ export class PrivateNameTagService { where: { id: Not(id), createdBy: user_id, - nameTag: await this.encryptionService.encrypt(req.nameTag ?? ""), + nameTag: await this.encryptionService.encrypt(req.nameTag ?? ''), }, }); if (entity) { @@ -198,38 +215,4 @@ export class PrivateNameTagService { return false; } - - async getNameTagMainSite(req: { - user_id: number; - limit: number; - nextKey: number; - keyword: string; - }): Promise { - const nameTags = await this.privateNameTagRepository.getNameTagMainSite( - Number(req.user_id), - Number(req.limit), - Number(req.nextKey), - req.keyword, - await this.encryptionService.encrypt(req.keyword), - ); - - const nextKey = nameTags.slice(-1)[0]?.id; - - const data = await Promise.all( - nameTags.map(async (item) => { - item.nameTag = await this.encryptionService.decrypt(item.nameTag); - return item; - }), - ); - - const result = { - data: { - nameTags: data, - count: Number(nameTags.length), - nextKey: nextKey || null, - }, - }; - - return result; - } } diff --git a/src/shared/configs/configuration.ts b/src/shared/configs/configuration.ts index 5a73e063..202a9073 100644 --- a/src/shared/configs/configuration.ts +++ b/src/shared/configs/configuration.ts @@ -83,4 +83,5 @@ export default () => ({ alias: process.env.KMS_ALIAS, }, addressPrefix: process.env.ADDRESS_PREFIX, + limitedPrivateNameTag: process.env.LIMITED_PRIVATE_NAME_TAG || 10, }); diff --git a/src/shared/constants/common.ts b/src/shared/constants/common.ts index d91ea133..8f52c692 100644 --- a/src/shared/constants/common.ts +++ b/src/shared/constants/common.ts @@ -176,6 +176,12 @@ export const ADMIN_ERROR_MAP = { Code: 'E005', Message: 'Invalid URL format', }, + LIMIT_PRIVATE_NAME_TAG: { + Code: 'E006', + Message: `You have reached out of ${ + process.env.LIMITED_PRIVATE_NAME_TAG || 10 + } max limitation of private name tag`, + }, }; export const PAGE_REQUEST = {