From e17663169f17ec4f1b029257eedc7a0982a750b6 Mon Sep 17 00:00:00 2001 From: hou27 Date: Tue, 14 Mar 2023 20:19:04 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EC=83=88=EB=A1=9C=EC=9A=B4=20plan?= =?UTF-8?q?=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EA=B5=AC=ED=98=84=EA=B3=BC=20?= =?UTF-8?q?user=EC=99=80=EC=9D=98=20=EA=B4=80=EA=B3=84=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20-=20#176?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 플랜 관련 정책을 구체적으로 협의하기 전 구조 세팅 --- src/users/entities/paid-plan.entity.ts | 37 ++++++++++++++++++++++++++ src/users/entities/user.entity.ts | 20 +++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/users/entities/paid-plan.entity.ts diff --git a/src/users/entities/paid-plan.entity.ts b/src/users/entities/paid-plan.entity.ts new file mode 100644 index 0000000..edef111 --- /dev/null +++ b/src/users/entities/paid-plan.entity.ts @@ -0,0 +1,37 @@ +import { Column, Entity, OneToMany } from 'typeorm'; +import { IsNumber, IsString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { CoreEntity } from '../../common/entities/core.entity'; +import { User } from './user.entity'; + +@Entity() +export class PaidPlan extends CoreEntity { + @ApiProperty({ example: 'ultimate', description: 'plan name' }) + @Column({ unique: true }) + @IsString() + name!: string; + + @ApiProperty({ example: 3000, description: 'plan price' }) + @Column() + @IsNumber() + price!: number; + + @ApiProperty({ + example: 30, + description: 'The period (in days) of the paid plan.', + }) + @Column() + @IsString() + duration_days!: number; + + @ApiProperty({ example: 'ultimate plan', description: 'plan description' }) + @Column() + @IsString() + description!: string; + + @ApiProperty({ description: 'Users in use', type: [User] }) + @OneToMany((type) => User, (user) => user.paidPlan, { + nullable: true, + }) + users?: User[]; +} diff --git a/src/users/entities/user.entity.ts b/src/users/entities/user.entity.ts index 687e966..20d3847 100644 --- a/src/users/entities/user.entity.ts +++ b/src/users/entities/user.entity.ts @@ -1,5 +1,12 @@ import { InternalServerErrorException } from '@nestjs/common'; -import { BeforeInsert, BeforeUpdate, Column, Entity, OneToMany } from 'typeorm'; +import { + BeforeInsert, + BeforeUpdate, + Column, + Entity, + ManyToOne, + OneToMany, +} from 'typeorm'; import * as bcrypt from 'bcrypt'; import { IsBoolean, IsEmail, IsEnum, IsString, Matches } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; @@ -7,6 +14,7 @@ import { Content } from '../../contents/entities/content.entity'; import { Category } from '../../contents/entities/category.entity'; import { Collection } from '../../collections/entities/collection.entity'; import { CoreEntity } from '../../common/entities/core.entity'; +import { PaidPlan } from './paid-plan.entity'; export enum UserRole { Client = 'Client', @@ -77,6 +85,16 @@ export class User extends CoreEntity { }) collections?: Collection[]; + @ApiProperty({ + description: 'User Plan', + type: PaidPlan, + required: false, + }) + @ManyToOne((type) => PaidPlan, (paidPlan) => paidPlan.users, { + nullable: true, + }) + paidPlan?: PaidPlan; + @BeforeInsert() @BeforeUpdate() async hashPassword(): Promise { From 1ef2807bbba9973c673d4181c086228916665395 Mon Sep 17 00:00:00 2001 From: hou27 Date: Wed, 19 Jul 2023 19:16:43 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EB=8C=80=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EC=83=9D=EC=84=B1=20=EA=B0=9C=EC=88=98=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C=20-=20#176?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 현재는 유료 무료 플랜 구분 x --- src/contents/contents.service.ts | 13 +++++++++++++ src/contents/repository/category.repository.ts | 15 +++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/contents/contents.service.ts b/src/contents/contents.service.ts index 1178d2f..e135773 100644 --- a/src/contents/contents.service.ts +++ b/src/contents/contents.service.ts @@ -470,6 +470,19 @@ export class CategoryService { } currentParentId = parentCategory?.parentId; } + } else { + /** + * TODO: 유료 플랜 사용자이면 카테고리 개수 제한 없도록 추가 구성해야함. + */ + // if parentId is null, it means that category is root category + // root categories can't be more than 10 in one user + const isOverCategoryLimit = + await this.categoryRepository.isOverCategoryLimit(user); + if (isOverCategoryLimit) { + throw new ConflictException( + "Root categories can't be more than 10 in one user", + ); + } } // check if category exists in user's categories(check if category name is duplicated in same level too) diff --git a/src/contents/repository/category.repository.ts b/src/contents/repository/category.repository.ts index 5259c30..2f956a8 100644 --- a/src/contents/repository/category.repository.ts +++ b/src/contents/repository/category.repository.ts @@ -85,4 +85,19 @@ export class CategoryRepository extends Repository { return category; } + + /** + * 대 카테고리는 유저 당 10개까지만 생성 가능 + * 해당 유저의 대 카테고리 개수를 확인하고, 10개 이상이면 true 반환 + * @param user.id + * @returns boolean + */ + async isOverCategoryLimit(user: User): Promise { + const categoryCount = await this.createQueryBuilder('category') + .where('category.userId = :id', { id: user.id }) + .andWhere('category.parentId IS NULL') + .getCount(); + + return categoryCount >= 10; + } }