Skip to content

Commit

Permalink
feat: 에픽 생성, 수정 API에 우선순위 데이터(rankValue)추가
Browse files Browse the repository at this point in the history
- lexorank 패키지 설치
- epic 엔티티
  - rankValue 프로퍼티 추가
  - 에픽의 rankValue가 project에서 고유하도록 유니크 제약조건 추가
- project 레포지토리, project 서비스, epic컨트롤러에 rankValue 정보 추가
- Epic DTO에 rankValue 정보 추가
- LexoRank형식인지 검증할 수 있는 IsLexoRankValue 데코레이터 추가
- E2E 테스트
  - 에픽, 스토리, 태스크, 백로그 테스트에 rankValue정보 추가
  - 에픽 테스트에 rankValue update테스트 추가
  • Loading branch information
choyoungwoo9 committed Jul 30, 2024
1 parent d9d44e9 commit c13ae07
Show file tree
Hide file tree
Showing 15 changed files with 212 additions and 60 deletions.
67 changes: 41 additions & 26 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cookie-parser": "^1.4.6",
"lexorank": "^1.0.5",
"mysql2": "^3.9.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
Expand Down
18 changes: 18 additions & 0 deletions backend/src/common/decorator/IsLexoRankValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { registerDecorator } from 'class-validator';

export function IsLexoRankValue() {
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'IsLexoRankValue',
target: object.constructor,
propertyName: propertyName,
options: { message: 'invalid LexoRank format' },
validator: {
validate(value: any) {
const lexorankPattern = new RegExp(`^[012]\\|.*`, 'i');
return lexorankPattern.test(value);
},
},
});
};
}
9 changes: 6 additions & 3 deletions backend/src/project/dto/epic/EpicCreateNotify.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ class Epic {
id: number;
name: string;
color: EpicColor;
static of(id: number, name: string, color: EpicColor) {
rankValue: string;

static of(id: number, name: string, color: EpicColor, rankValue: string) {
const dto = new Epic();
dto.id = id;
dto.name = name;
dto.color = color;
dto.rankValue = rankValue;
return dto;
}
}
Expand All @@ -18,11 +21,11 @@ export class EpicCreateNotifyDto {
action: string;
content: Epic;

static of(id: number, name: string, color: EpicColor) {
static of(id: number, name: string, color: EpicColor, rankValue: string) {
const dto = new EpicCreateNotifyDto();
dto.domain = 'epic';
dto.action = 'create';
dto.content = Epic.of(id, name, color);
dto.content = Epic.of(id, name, color, rankValue);
return dto;
}
}
6 changes: 6 additions & 0 deletions backend/src/project/dto/epic/EpicCreateRequest.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Matches,
ValidateNested,
} from 'class-validator';
import { IsLexoRankValue } from 'src/common/decorator/IsLexoRankValue';
import { EpicColor } from 'src/project/entity/epic.entity';

class Epic {
Expand All @@ -16,6 +17,11 @@ class Epic {

@IsEnum(EpicColor)
color: EpicColor;

@IsString()
@IsLexoRankValue()
@Length(2, 255)
rankValue: string;
}

export class EpicCreateRequestDto {
Expand Down
8 changes: 5 additions & 3 deletions backend/src/project/dto/epic/EpicUpdateNotify.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ class Epic {
id: number;
name?: string;
color?: EpicColor;
static of(id: number, name: string, color: EpicColor) {
rankValue?: string;
static of(id: number, name: string, color: EpicColor, rankValue: string) {
const dto = new Epic();
dto.id = id;
if (name !== undefined) dto.name = name;
if (color !== undefined) dto.color = color;
if (rankValue !== undefined) dto.rankValue = rankValue;
return dto;
}
}
Expand All @@ -18,11 +20,11 @@ export class EpicUpdateNotifyDto {
action: string;
content: Epic;

static of(id: number, name: string, color: EpicColor) {
static of(id: number, name: string, color: EpicColor, rankValue: string) {
const dto = new EpicUpdateNotifyDto();
dto.domain = 'epic';
dto.action = 'update';
dto.content = Epic.of(id, name, color);
dto.content = Epic.of(id, name, color, rankValue);
return dto;
}
}
8 changes: 7 additions & 1 deletion backend/src/project/dto/epic/EpicUpdateRequest.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import {
ValidateNested,
Length,
} from 'class-validator';
import { IsLexoRankValue } from 'src/common/decorator/IsLexoRankValue';
import { EpicColor } from 'src/project/entity/epic.entity';
import { AtLeastOneProperty } from 'src/project/util/validation.util';

class Epic {
@IsNotEmpty()
@IsInt()
@AtLeastOneProperty(['name', 'color'])
@AtLeastOneProperty(['name', 'color', 'rankValue'])
id: number;

@IsOptional()
Expand All @@ -26,6 +27,11 @@ class Epic {
@IsOptional()
@IsEnum(EpicColor)
color?: EpicColor;

@IsOptional()
@IsLexoRankValue()
@Length(2, 255)
rankValue?: string;
}

export class EpicUpdateRequestDto {
Expand Down
13 changes: 12 additions & 1 deletion backend/src/project/entity/epic.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
Unique,
UpdateDateColumn,
} from 'typeorm';
import { Project } from './project.entity';
Expand All @@ -22,6 +23,7 @@ export enum EpicColor {
}

@Entity()
@Unique(['rankValue', 'projectId'])
export class Epic {
@PrimaryGeneratedColumn('increment', { type: 'int' })
id: number;
Expand Down Expand Up @@ -51,11 +53,20 @@ export class Epic {
@OneToMany(() => Story, (story) => story.epic)
storyList: Story[];

static of(project: Project, name: string, color: EpicColor) {
@Column({ type: 'varchar', length: 255, nullable: false, name: 'rank_value' })
rankValue: string;

static of(
project: Project,
name: string,
color: EpicColor,
rankValue: string,
) {
const newEpic = new Epic();
newEpic.project = project;
newEpic.name = name;
newEpic.color = color;
newEpic.rankValue = rankValue;
return newEpic;
}
}
5 changes: 5 additions & 0 deletions backend/src/project/project.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export class ProjectRepository {
id: number,
name?: string,
color?: EpicColor,
rankValue?: string,
): Promise<boolean> {
const updateData: any = {};

Expand All @@ -144,6 +145,10 @@ export class ProjectRepository {
updateData.color = color;
}

if (rankValue !== undefined) {
updateData.rankValue = rankValue;
}

const result = await this.epicRepository.update(
{ id, project: { id: project.id } },
updateData,
Expand Down
24 changes: 18 additions & 6 deletions backend/src/project/service/project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,13 @@ export class ProjectService {
return result ? true : false;
}

createEpic(project: Project, name: string, color: EpicColor) {
const newEpic = Epic.of(project, name, color);
createEpic(
project: Project,
name: string,
color: EpicColor,
rankValue: string,
) {
const newEpic = Epic.of(project, name, color, rankValue);
return this.projectRepository.createEpic(newEpic);
}

Expand All @@ -110,8 +115,15 @@ export class ProjectService {
id: number,
name?: string,
color?: EpicColor,
rankValue?: string,
): Promise<boolean> {
return this.projectRepository.updateEpic(project, id, name, color);
return this.projectRepository.updateEpic(
project,
id,
name,
color,
rankValue,
);
}

async createStory(
Expand Down Expand Up @@ -211,8 +223,8 @@ export class ProjectService {
assignedMemberId,
);
}
getProjectBacklog(project: Project){
return this.projectRepository.getProjectBacklog(project);

getProjectBacklog(project: Project) {
return this.projectRepository.getProjectBacklog(project);
}
}
Loading

0 comments on commit c13ae07

Please sign in to comment.