From af14c0024d62f9887bea19364096a02c863002b2 Mon Sep 17 00:00:00 2001 From: Min Sang Date: Sun, 5 May 2024 18:02:26 +0900 Subject: [PATCH] =?UTF-8?q?[#59]=20=EC=9D=B4=EC=8A=88=20=EB=9D=BC=EB=B2=A8?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20(#91)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 이슈 라벨 Enum 추가 및 컨버터 등록 * refactor: assigneeDto from 메서드 사용 및 카카오 이미지 url 추가 * refactor: assigneeDto member 패키지 밑으로 이동하면서 리펙터링 * feat(EpicFactory): 라벨 추가 * feat: 라벨 추가 및 생성자 관련 SuperBuilder로 리펙터링 * refactor: superBuilder 지우고 생성자로 다시 변경 story와 task 같은 경우 생성할때 추가적인 로직이 존재하기 때문에 단순화를 위해 생성자로 다시 사용합니다 * feat: 라벨 추가 및 assigneeDto관련 리펙터링 * style: assigneeDto 패키지 임포트 경로 수정 * refactor(SimpleIssueResponse): label 추가 * feat: storyFactory, taskFactory label 추가 * refactor: 스프린트들 조회시 스프린트 상태도 반환하도록 수정 * refactor: 스키마에 라벨 추가 --- .../agilehub/global/config/WebConfig.java | 2 + .../util/StringToIssueLabelConverter.java | 12 ++++ .../util/StringToIssueTypeConverter.java | 3 - .../controller/request/IssueRequest.java | 7 ++ .../controller/response/EpicResponse.java | 6 +- .../controller/response/IssueResponse.java | 27 +------- .../response/SimpleIssueResponse.java | 4 +- .../controller/response/StoryResponse.java | 15 ++--- .../controller/response/TaskResponse.java | 17 ++--- .../agilehub/issue/domain/Issue.java | 10 ++- .../agilehub/issue/domain/IssueLabel.java | 17 +++++ .../agilehub/issue/domain/epic/Epic.java | 9 +-- .../agilehub/issue/domain/story/Story.java | 6 +- .../agilehub/issue/domain/task/Task.java | 6 +- .../issue/service/IssueQueryService.java | 41 ++++++------ .../issue/service/factory/EpicFactory.java | 46 +++++++------ .../issue/service/factory/IssueFactory.java | 2 +- .../issue/service/factory/StoryFactory.java | 67 ++++++++++--------- .../issue/service/factory/TaskFactory.java | 48 +++++++------ .../agilehub/member/dto/AssigneeDto.java | 30 +++++++++ .../controller/response/SprintResponse.java | 6 +- .../sprint/service/SprintQueryService.java | 3 +- src/main/resources/application-local.yml | 2 +- src/main/resources/shema.sql | 1 + 24 files changed, 225 insertions(+), 162 deletions(-) create mode 100644 src/main/java/dynamicquad/agilehub/global/util/StringToIssueLabelConverter.java create mode 100644 src/main/java/dynamicquad/agilehub/issue/domain/IssueLabel.java create mode 100644 src/main/java/dynamicquad/agilehub/member/dto/AssigneeDto.java diff --git a/src/main/java/dynamicquad/agilehub/global/config/WebConfig.java b/src/main/java/dynamicquad/agilehub/global/config/WebConfig.java index 4765794..d04e476 100644 --- a/src/main/java/dynamicquad/agilehub/global/config/WebConfig.java +++ b/src/main/java/dynamicquad/agilehub/global/config/WebConfig.java @@ -1,6 +1,7 @@ package dynamicquad.agilehub.global.config; import dynamicquad.agilehub.global.auth.util.MemberArgumentResolver; +import dynamicquad.agilehub.global.util.StringToIssueLabelConverter; import dynamicquad.agilehub.global.util.StringToIssueStatusConverter; import dynamicquad.agilehub.global.util.StringToIssueTypeConverter; import java.util.List; @@ -18,6 +19,7 @@ public class WebConfig implements WebMvcConfigurer { public void addFormatters(FormatterRegistry registry) { registry.addConverter(new StringToIssueTypeConverter()); registry.addConverter(new StringToIssueStatusConverter()); + registry.addConverter(new StringToIssueLabelConverter()); } @Override diff --git a/src/main/java/dynamicquad/agilehub/global/util/StringToIssueLabelConverter.java b/src/main/java/dynamicquad/agilehub/global/util/StringToIssueLabelConverter.java new file mode 100644 index 0000000..311f394 --- /dev/null +++ b/src/main/java/dynamicquad/agilehub/global/util/StringToIssueLabelConverter.java @@ -0,0 +1,12 @@ +package dynamicquad.agilehub.global.util; + +import dynamicquad.agilehub.issue.domain.IssueLabel; +import org.springframework.core.convert.converter.Converter; + +public class StringToIssueLabelConverter implements Converter { + + @Override + public IssueLabel convert(String source) { + return IssueLabel.parsing(source); + } +} diff --git a/src/main/java/dynamicquad/agilehub/global/util/StringToIssueTypeConverter.java b/src/main/java/dynamicquad/agilehub/global/util/StringToIssueTypeConverter.java index a381f96..591aea5 100644 --- a/src/main/java/dynamicquad/agilehub/global/util/StringToIssueTypeConverter.java +++ b/src/main/java/dynamicquad/agilehub/global/util/StringToIssueTypeConverter.java @@ -1,15 +1,12 @@ package dynamicquad.agilehub.global.util; import dynamicquad.agilehub.issue.controller.request.IssueType; -import lombok.extern.slf4j.Slf4j; import org.springframework.core.convert.converter.Converter; -@Slf4j public class StringToIssueTypeConverter implements Converter { @Override public IssueType convert(String source) { - log.info("StringToIssueTypeConverter convert source: {}", source); return IssueType.parsing(source); } diff --git a/src/main/java/dynamicquad/agilehub/issue/controller/request/IssueRequest.java b/src/main/java/dynamicquad/agilehub/issue/controller/request/IssueRequest.java index 689ef27..907ebc9 100644 --- a/src/main/java/dynamicquad/agilehub/issue/controller/request/IssueRequest.java +++ b/src/main/java/dynamicquad/agilehub/issue/controller/request/IssueRequest.java @@ -1,5 +1,6 @@ package dynamicquad.agilehub.issue.controller.request; +import dynamicquad.agilehub.issue.domain.IssueLabel; import dynamicquad.agilehub.issue.domain.IssueStatus; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; @@ -38,6 +39,9 @@ public static class IssueCreateRequest { @NotNull(message = "상태는 필수입니다.") private IssueStatus status; + @Schema(description = "이슈 라벨 (PLAN, DESIGN, DEVELOP, TEST, FEEDBACK)", example = "PLAN") + private IssueLabel label; + @Schema(description = "이슈 내용", example = "이슈 내용") private String content; @@ -80,6 +84,9 @@ public static class IssueEditRequest { @NotNull(message = "상태는 필수입니다.") private IssueStatus status; + @Schema(description = "이슈 라벨 (PLAN, DESIGN, DEVELOP, TEST, FEEDBACK)", example = "PLAN, DESIGN, DEVELOP, TEST, FEEDBACK") + private IssueLabel label; + @Schema(description = "이슈 내용", example = "이슈 내용") private String content; diff --git a/src/main/java/dynamicquad/agilehub/issue/controller/response/EpicResponse.java b/src/main/java/dynamicquad/agilehub/issue/controller/response/EpicResponse.java index 96940c1..3da88d3 100644 --- a/src/main/java/dynamicquad/agilehub/issue/controller/response/EpicResponse.java +++ b/src/main/java/dynamicquad/agilehub/issue/controller/response/EpicResponse.java @@ -1,8 +1,8 @@ package dynamicquad.agilehub.issue.controller.response; import dynamicquad.agilehub.issue.controller.request.IssueType; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.domain.epic.Epic; +import dynamicquad.agilehub.member.dto.AssigneeDto; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -16,10 +16,11 @@ public class EpicResponse { private String key; private String status; private String type; + private String label; private String startDate; private String endDate; private AssigneeDto assignee; - //TODO: 태그 추가 필요 + public static EpicResponse fromEntity(Epic epic, String projectKey, AssigneeDto assigneeDto) { return EpicResponse.builder() @@ -27,6 +28,7 @@ public static EpicResponse fromEntity(Epic epic, String projectKey, AssigneeDto .title(epic.getTitle()) .key(projectKey + "-" + epic.getNumber()) .status(epic.getStatus().toString()) + .label(epic.getLabel().toString()) .type(IssueType.EPIC.toString()) .startDate(epic.getStartDate() == null ? "" : epic.getStartDate().toString()) .endDate(epic.getEndDate() == null ? "" : epic.getEndDate().toString()) diff --git a/src/main/java/dynamicquad/agilehub/issue/controller/response/IssueResponse.java b/src/main/java/dynamicquad/agilehub/issue/controller/response/IssueResponse.java index d386efa..2e663dc 100644 --- a/src/main/java/dynamicquad/agilehub/issue/controller/response/IssueResponse.java +++ b/src/main/java/dynamicquad/agilehub/issue/controller/response/IssueResponse.java @@ -1,5 +1,6 @@ package dynamicquad.agilehub.issue.controller.response; +import dynamicquad.agilehub.member.dto.AssigneeDto; import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; @@ -17,6 +18,7 @@ public static class IssueDto { private String title; private String type; private String status; + private String label; private String startDate; private String endDate; private ContentDto content; @@ -37,30 +39,6 @@ public ContentDto() { } } - @Builder - @Getter - @AllArgsConstructor - @EqualsAndHashCode - public static class AssigneeDto { - private Long id; - private String name; - private String profileImageURL; - - public AssigneeDto() { - this.id = null; - this.name = ""; - this.profileImageURL = ""; - } - - public static AssigneeDto from(Long id, String name, String profileImageURL) { - return AssigneeDto.builder() - .id(id) - .name(name) - .profileImageURL(profileImageURL) - .build(); - } - } - @Builder @Getter @AllArgsConstructor @@ -79,6 +57,7 @@ public static class SubIssueDto { private Long issueId; private String key; private String status; + private String label; private String type; private String title; private AssigneeDto assignee; diff --git a/src/main/java/dynamicquad/agilehub/issue/controller/response/SimpleIssueResponse.java b/src/main/java/dynamicquad/agilehub/issue/controller/response/SimpleIssueResponse.java index 9423774..403a67a 100644 --- a/src/main/java/dynamicquad/agilehub/issue/controller/response/SimpleIssueResponse.java +++ b/src/main/java/dynamicquad/agilehub/issue/controller/response/SimpleIssueResponse.java @@ -1,8 +1,8 @@ package dynamicquad.agilehub.issue.controller.response; import dynamicquad.agilehub.issue.controller.request.IssueType; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.domain.Issue; +import dynamicquad.agilehub.member.dto.AssigneeDto; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -16,6 +16,7 @@ public class SimpleIssueResponse { private String type; private String key; private String status; + private String label; private AssigneeDto assignee; public static SimpleIssueResponse fromEntity(Issue issue, String projectKey, IssueType issueType, @@ -25,6 +26,7 @@ public static SimpleIssueResponse fromEntity(Issue issue, String projectKey, Iss .title(issue.getTitle()) .type(issueType.toString()) .status(String.valueOf(issue.getStatus())) + .label(String.valueOf(issue.getLabel())) .assignee(assignee) .key(projectKey + "-" + issue.getNumber()) .build(); diff --git a/src/main/java/dynamicquad/agilehub/issue/controller/response/StoryResponse.java b/src/main/java/dynamicquad/agilehub/issue/controller/response/StoryResponse.java index 4d7bd84..cf29419 100644 --- a/src/main/java/dynamicquad/agilehub/issue/controller/response/StoryResponse.java +++ b/src/main/java/dynamicquad/agilehub/issue/controller/response/StoryResponse.java @@ -1,8 +1,8 @@ package dynamicquad.agilehub.issue.controller.response; import dynamicquad.agilehub.issue.controller.request.IssueType; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.domain.story.Story; +import dynamicquad.agilehub.member.dto.AssigneeDto; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -15,30 +15,25 @@ public class StoryResponse { private String title; private String key; private String status; + private String label; private String type; private String startDate; private String endDate; private Long parentId; private AssigneeDto assignee; - // TODO: 태그 추가 필요 - public static StoryResponse fromEntity(Story story, String projectKey, Long parentId) { + public static StoryResponse fromEntity(Story story, String projectKey, Long parentId, AssigneeDto assigneeDto) { return StoryResponse.builder() .id(story.getId()) .title(story.getTitle()) .key(projectKey + "-" + story.getNumber()) .status(story.getStatus().toString()) + .label(story.getLabel().toString()) .type(IssueType.STORY.toString()) .startDate(story.getStartDate() == null ? "" : story.getStartDate().toString()) .endDate(story.getEndDate() == null ? "" : story.getEndDate().toString()) .parentId(parentId) - .assignee( - story.getAssignee() == null ? new AssigneeDto() : - AssigneeDto.builder() - .id(story.getAssignee().getId()) - .name(story.getAssignee().getName()) - .build() - ) + .assignee(assigneeDto) .build(); } } diff --git a/src/main/java/dynamicquad/agilehub/issue/controller/response/TaskResponse.java b/src/main/java/dynamicquad/agilehub/issue/controller/response/TaskResponse.java index df554cf..98d3f64 100644 --- a/src/main/java/dynamicquad/agilehub/issue/controller/response/TaskResponse.java +++ b/src/main/java/dynamicquad/agilehub/issue/controller/response/TaskResponse.java @@ -1,8 +1,8 @@ package dynamicquad.agilehub.issue.controller.response; import dynamicquad.agilehub.issue.controller.request.IssueType; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.domain.task.Task; +import dynamicquad.agilehub.member.dto.AssigneeDto; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -15,28 +15,23 @@ public class TaskResponse { private String title; private String key; private String status; + private String label; private String type; private Long parentId; private AssigneeDto assignee; - // TODO: 태그 추가 필요 - public static TaskResponse fromEntity(Task task, String projectKey, Long parentId) { + public static TaskResponse fromEntity(Task task, String projectKey, Long parentId, AssigneeDto assigneeDto) { return TaskResponse.builder() .id(task.getId()) .title(task.getTitle()) .key(projectKey + "-" + task.getNumber()) .status(task.getStatus().toString()) + .label(task.getLabel().toString()) .type(IssueType.TASK.toString()) .parentId(parentId) - .assignee( - task.getAssignee() == null ? new AssigneeDto() : - AssigneeDto.builder() - .id(task.getAssignee().getId()) - .name(task.getAssignee().getName()) - .build() - ) + .assignee(assigneeDto) .build(); } - + } diff --git a/src/main/java/dynamicquad/agilehub/issue/domain/Issue.java b/src/main/java/dynamicquad/agilehub/issue/domain/Issue.java index 0a10e0b..406378e 100644 --- a/src/main/java/dynamicquad/agilehub/issue/domain/Issue.java +++ b/src/main/java/dynamicquad/agilehub/issue/domain/Issue.java @@ -54,6 +54,9 @@ public abstract class Issue { @Enumerated(EnumType.STRING) private IssueStatus status; + @Enumerated(EnumType.STRING) + private IssueLabel label; + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member assignee; @@ -76,20 +79,23 @@ public void setSprint(Sprint newSprint) { this.sprint = newSprint; } - protected Issue(String title, String content, int number, IssueStatus status, Member assignee, Project project) { + + protected Issue(String title, String content, int number, IssueStatus status, IssueLabel label, Member assignee, + Project project) { this.title = title; this.content = content; this.number = number; this.status = status; + this.label = label; this.assignee = assignee; this.project = project; - } protected void updateIssue(IssueEditRequest request, Member assignee) { this.title = request.getTitle(); this.content = request.getContent(); this.status = request.getStatus(); + this.label = request.getLabel(); this.assignee = assignee; } diff --git a/src/main/java/dynamicquad/agilehub/issue/domain/IssueLabel.java b/src/main/java/dynamicquad/agilehub/issue/domain/IssueLabel.java new file mode 100644 index 0000000..b756686 --- /dev/null +++ b/src/main/java/dynamicquad/agilehub/issue/domain/IssueLabel.java @@ -0,0 +1,17 @@ +package dynamicquad.agilehub.issue.domain; + +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.stream.Stream; + +public enum IssueLabel { + NONE, PLAN, DESIGN, DEVELOP, TEST, FEEDBACK; + + @JsonCreator + public static IssueLabel parsing(String value) { + return Stream.of(IssueLabel.values()) + .filter(label -> label.toString().equalsIgnoreCase(value)) + .findFirst() + .orElse(NONE); + } + +} diff --git a/src/main/java/dynamicquad/agilehub/issue/domain/epic/Epic.java b/src/main/java/dynamicquad/agilehub/issue/domain/epic/Epic.java index 5a85868..d8939dc 100644 --- a/src/main/java/dynamicquad/agilehub/issue/domain/epic/Epic.java +++ b/src/main/java/dynamicquad/agilehub/issue/domain/epic/Epic.java @@ -2,6 +2,7 @@ import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueEditRequest; import dynamicquad.agilehub.issue.domain.Issue; +import dynamicquad.agilehub.issue.domain.IssueLabel; import dynamicquad.agilehub.issue.domain.IssueStatus; import dynamicquad.agilehub.issue.domain.story.Story; import dynamicquad.agilehub.member.domain.Member; @@ -31,13 +32,13 @@ public class Epic extends Issue { private List stories = new ArrayList<>(); @Builder - private Epic(String title, String content, int number, IssueStatus status, Member assignee, Project project, - LocalDate startDate, LocalDate endDate) { - super(title, content, number, status, assignee, project); + private Epic(String title, String content, int number, IssueStatus status, IssueLabel label, Member assignee, + Project project, LocalDate startDate, LocalDate endDate) { + super(title, content, number, status, label, assignee, project); this.startDate = startDate; this.endDate = endDate; } - + public void updateEpic(IssueEditRequest request, Member assignee) { super.updateIssue(request, assignee); this.startDate = request.getStartDate(); diff --git a/src/main/java/dynamicquad/agilehub/issue/domain/story/Story.java b/src/main/java/dynamicquad/agilehub/issue/domain/story/Story.java index 2b77729..e789d29 100644 --- a/src/main/java/dynamicquad/agilehub/issue/domain/story/Story.java +++ b/src/main/java/dynamicquad/agilehub/issue/domain/story/Story.java @@ -2,6 +2,7 @@ import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueEditRequest; import dynamicquad.agilehub.issue.domain.Issue; +import dynamicquad.agilehub.issue.domain.IssueLabel; import dynamicquad.agilehub.issue.domain.IssueStatus; import dynamicquad.agilehub.issue.domain.epic.Epic; import dynamicquad.agilehub.issue.domain.task.Task; @@ -40,9 +41,10 @@ public class Story extends Issue { private List tasks = new ArrayList<>(); @Builder - private Story(String title, String content, int number, IssueStatus status, Member assignee, Project project, + private Story(String title, String content, int number, IssueStatus status, IssueLabel label, Member assignee, + Project project, int storyPoint, LocalDate startDate, LocalDate endDate, Epic epic) { - super(title, content, number, status, assignee, project); + super(title, content, number, status, label, assignee, project); this.storyPoint = storyPoint; this.startDate = startDate; this.endDate = endDate; diff --git a/src/main/java/dynamicquad/agilehub/issue/domain/task/Task.java b/src/main/java/dynamicquad/agilehub/issue/domain/task/Task.java index 86d4f2d..777a48a 100644 --- a/src/main/java/dynamicquad/agilehub/issue/domain/task/Task.java +++ b/src/main/java/dynamicquad/agilehub/issue/domain/task/Task.java @@ -3,6 +3,7 @@ import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueEditRequest; import dynamicquad.agilehub.issue.domain.Issue; +import dynamicquad.agilehub.issue.domain.IssueLabel; import dynamicquad.agilehub.issue.domain.IssueStatus; import dynamicquad.agilehub.issue.domain.story.Story; import dynamicquad.agilehub.member.domain.Member; @@ -28,9 +29,10 @@ public class Task extends Issue { private Story story; @Builder - private Task(String title, String content, int number, IssueStatus status, Member assignee, Project project, + private Task(String title, String content, int number, IssueStatus status, IssueLabel label, Member assignee, + Project project, Story story) { - super(title, content, number, status, assignee, project); + super(title, content, number, status, label, assignee, project); this.story = story; if (story != null) { story.getTasks().add(this); diff --git a/src/main/java/dynamicquad/agilehub/issue/service/IssueQueryService.java b/src/main/java/dynamicquad/agilehub/issue/service/IssueQueryService.java index d75f1c0..f9337ce 100644 --- a/src/main/java/dynamicquad/agilehub/issue/service/IssueQueryService.java +++ b/src/main/java/dynamicquad/agilehub/issue/service/IssueQueryService.java @@ -8,7 +8,6 @@ import dynamicquad.agilehub.issue.controller.response.EpicResponse; import dynamicquad.agilehub.issue.controller.response.EpicResponse.EpicStatisticDto; import dynamicquad.agilehub.issue.controller.response.EpicResponse.EpicWithStatisticResponse; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.ContentDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.IssueDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.SubIssueDto; @@ -24,7 +23,7 @@ import dynamicquad.agilehub.issue.domain.task.TaskRepository; import dynamicquad.agilehub.issue.service.factory.IssueFactory; import dynamicquad.agilehub.issue.service.factory.IssueFactoryProvider; -import dynamicquad.agilehub.member.domain.Member; +import dynamicquad.agilehub.member.dto.AssigneeDto; import dynamicquad.agilehub.member.dto.MemberRequestDto.AuthMember; import dynamicquad.agilehub.project.domain.Project; import dynamicquad.agilehub.project.service.MemberProjectService; @@ -90,7 +89,10 @@ public List getStoriesByEpic(String key, Long epicId, AuthMember List storiesByEpic = storyRepository.findStoriesByEpicId(epicId); return storiesByEpic.stream() - .map(story -> StoryResponse.fromEntity(story, project.getKey(), epicId)) + .map(story -> { + AssigneeDto assigneeDto = createAssigneeDto(story); + return StoryResponse.fromEntity(story, project.getKey(), epicId, assigneeDto); + }) .toList(); } @@ -100,7 +102,10 @@ public List getTasksByStory(String key, Long storyId, AuthMember a List tasksByStory = taskRepository.findByStoryId(storyId); return tasksByStory.stream() - .map(task -> TaskResponse.fromEntity(task, project.getKey(), storyId)) + .map(task -> { + AssigneeDto assigneeDto = createAssigneeDto(task); + return TaskResponse.fromEntity(task, project.getKey(), storyId, assigneeDto); + }) .toList(); } @@ -144,15 +149,6 @@ public List getTasks(String key, AuthMember authMember) { .toList(); } - private AssigneeDto createAssigneeDto(Issue issue) { - - if (issue.getAssignee() == null) { - return new AssigneeDto(); - } - return AssigneeDto.from(issue.getAssignee().getId(), issue.getAssignee().getName(), - issue.getAssignee().getProfileImageUrl()); - } - private List getEpicWithStatisticResponses(List epicResponses, List epicStatics) { return epicResponses.stream() @@ -169,19 +165,20 @@ private List getEpicWithStatisticResponses(List getEpicResponses(List epicsByProject, Project project) { return epicsByProject.stream() .map(epic -> { - Member assignee = epic.getAssignee(); - if (assignee == null) { - return EpicResponse.fromEntity(epic, project.getKey(), new AssigneeDto()); - } - AssigneeDto assigneeDto = AssigneeDto.builder() - .id(assignee.getId()) - .name(assignee.getName()) - .build(); + AssigneeDto assigneeDto = createAssigneeDto(epic); return EpicResponse.fromEntity(epic, project.getKey(), assigneeDto); - }) .toList(); } + private AssigneeDto createAssigneeDto(Issue issue) { + + if (issue.getAssignee() == null) { + return new AssigneeDto(); + } + return AssigneeDto.from(issue.getAssignee().getId(), issue.getAssignee().getName(), + issue.getAssignee().getProfileImageUrl()); + } + } diff --git a/src/main/java/dynamicquad/agilehub/issue/service/factory/EpicFactory.java b/src/main/java/dynamicquad/agilehub/issue/service/factory/EpicFactory.java index c4f73d6..ccaaaf2 100644 --- a/src/main/java/dynamicquad/agilehub/issue/service/factory/EpicFactory.java +++ b/src/main/java/dynamicquad/agilehub/issue/service/factory/EpicFactory.java @@ -4,7 +4,6 @@ import dynamicquad.agilehub.global.header.status.ErrorStatus; import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueCreateRequest; import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueEditRequest; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.ContentDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.IssueDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.SubIssueDto; @@ -16,6 +15,7 @@ import dynamicquad.agilehub.issue.domain.story.StoryRepository; import dynamicquad.agilehub.issue.service.ImageService; import dynamicquad.agilehub.member.domain.Member; +import dynamicquad.agilehub.member.dto.AssigneeDto; import dynamicquad.agilehub.member.service.MemberService; import dynamicquad.agilehub.project.domain.Project; import java.util.List; @@ -51,18 +51,7 @@ public Long createIssue(IssueCreateRequest request, Project project) { int issueNumber = (int) (issueRepository.countByProjectKey(project.getKey()) + 1); Member assignee = memberService.findMember(request.getAssigneeId(), project.getId()); - - // TODO: EPIC toEntity 메서드에 이 로직 넣기 [ ] - Epic epic = Epic.builder() - .title(request.getTitle()) - .content(request.getContent()) - .number(issueNumber) - .status(request.getStatus()) - .assignee(assignee) - .project(project) - .startDate(request.getStartDate()) - .endDate(request.getEndDate()) - .build(); + Epic epic = toEntity(request, project, issueNumber, assignee); issueRepository.save(epic); if (request.getFiles() != null && !request.getFiles().isEmpty()) { @@ -100,13 +89,14 @@ public ContentDto createContentDto(Issue issue) { @Override public IssueDto createIssueDto(Issue issue, ContentDto contentDto, AssigneeDto assigneeDto) { Epic epic = getEpic(issue); - //TODO: IssueDto 클래스에 해당 부분 fromEntity 메서드로 만들기 [ ] + return IssueDto.builder() .issueId(epic.getId()) .key(epic.getProject().getKey() + "-" + epic.getNumber()) .title(epic.getTitle()) .type(EPIC) .status(String.valueOf(epic.getStatus())) + .label(String.valueOf(epic.getLabel())) .startDate(epic.getStartDate() == null ? "" : epic.getStartDate().toString()) .endDate(epic.getEndDate() == null ? "" : epic.getEndDate().toString()) .content(contentDto) @@ -134,13 +124,7 @@ public List createChildIssueDtos(Issue issue) { private SubIssueDto getStoryToSubIssueDto(Story story) { - AssigneeDto assigneeDto = Optional.ofNullable(story.getAssignee()) - //TODO: AssigneeDto 클래스에 해당 부분 fromEntity 메서드로 만들기 [ ] - .map(assignee -> AssigneeDto.builder() - .id(assignee.getId()) - .name(assignee.getName()) - .build()) - .orElse(new AssigneeDto()); + AssigneeDto assigneeDto = createAssigneeDto(story); return SubIssueDto.builder() .issueId(story.getId()) @@ -152,6 +136,12 @@ private SubIssueDto getStoryToSubIssueDto(Story story) { .build(); } + private AssigneeDto createAssigneeDto(Story story) { + return Optional.ofNullable(story.getAssignee()) + .map(assignee -> AssigneeDto.from(assignee.getId(), assignee.getName(), assignee.getProfileImageUrl())) + .orElse(new AssigneeDto()); + } + private Epic getEpic(Issue issue) { if (!(issue instanceof Epic epic)) { log.error("issue is not instance of Epic = {}", issue.getClass()); @@ -160,5 +150,19 @@ private Epic getEpic(Issue issue) { return epic; } + private Epic toEntity(IssueCreateRequest request, Project project, int issueNumber, Member assignee) { + return Epic.builder() + .title(request.getTitle()) + .content(request.getContent()) + .number(issueNumber) + .status(request.getStatus()) + .label(request.getLabel()) + .assignee(assignee) + .project(project) + .startDate(request.getStartDate()) + .endDate(request.getEndDate()) + .build(); + } + } diff --git a/src/main/java/dynamicquad/agilehub/issue/service/factory/IssueFactory.java b/src/main/java/dynamicquad/agilehub/issue/service/factory/IssueFactory.java index d91953b..3149e70 100644 --- a/src/main/java/dynamicquad/agilehub/issue/service/factory/IssueFactory.java +++ b/src/main/java/dynamicquad/agilehub/issue/service/factory/IssueFactory.java @@ -2,11 +2,11 @@ import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueCreateRequest; import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueEditRequest; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.ContentDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.IssueDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.SubIssueDto; import dynamicquad.agilehub.issue.domain.Issue; +import dynamicquad.agilehub.member.dto.AssigneeDto; import dynamicquad.agilehub.project.domain.Project; import java.util.List; diff --git a/src/main/java/dynamicquad/agilehub/issue/service/factory/StoryFactory.java b/src/main/java/dynamicquad/agilehub/issue/service/factory/StoryFactory.java index b79e3c1..63c48ea 100644 --- a/src/main/java/dynamicquad/agilehub/issue/service/factory/StoryFactory.java +++ b/src/main/java/dynamicquad/agilehub/issue/service/factory/StoryFactory.java @@ -5,7 +5,6 @@ import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueCreateRequest; import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueEditRequest; import dynamicquad.agilehub.issue.controller.request.IssueType; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.ContentDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.IssueDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.SubIssueDto; @@ -18,10 +17,10 @@ import dynamicquad.agilehub.issue.domain.task.TaskRepository; import dynamicquad.agilehub.issue.service.ImageService; import dynamicquad.agilehub.member.domain.Member; +import dynamicquad.agilehub.member.dto.AssigneeDto; import dynamicquad.agilehub.member.service.MemberService; import dynamicquad.agilehub.project.domain.Project; import java.util.List; -import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -56,22 +55,9 @@ public Long createIssue(IssueCreateRequest request, Project project) { Member assignee = memberService.findMember(request.getAssigneeId(), project.getId()); Epic upEpic = retrieveEpicFromParentIssue(request.getParentId()); - - // TODO: STORY toEntity 메서드에 이 로직 넣기 [ ] - Story story = Story.builder() - .title(request.getTitle()) - .content(request.getContent()) - .number(issueNumber) - .status(request.getStatus()) - .assignee(assignee) - .project(project) - .startDate(request.getStartDate()) - .endDate(request.getEndDate()) - .epic(upEpic) - .build(); + Story story = toEntity(request, project, issueNumber, assignee, upEpic); issueRepository.save(story); - if (request.getFiles() != null && !request.getFiles().isEmpty()) { imageService.saveImages(story, request.getFiles(), WORKING_DIRECTORY); } @@ -79,7 +65,6 @@ public Long createIssue(IssueCreateRequest request, Project project) { return story.getId(); } - @Override public Long updateIssue(Issue issue, Project project, IssueEditRequest request) { @@ -109,13 +94,14 @@ public ContentDto createContentDto(Issue issue) { @Override public IssueDto createIssueDto(Issue issue, ContentDto contentDto, AssigneeDto assigneeDto) { Story story = getStory(issue); - //TODO: IssueDto 클래스에 해당 부분 fromEntity 메서드로 만들기 [ ] + return IssueDto.builder() .issueId(story.getId()) .key(story.getProject().getKey() + "-" + story.getNumber()) .title(story.getTitle()) .type(STORY) .status(String.valueOf(story.getStatus())) + .label(String.valueOf(story.getLabel())) .startDate(story.getStartDate() == null ? "" : story.getStartDate().toString()) .endDate(story.getEndDate() == null ? "" : story.getEndDate().toString()) .content(contentDto) @@ -131,19 +117,13 @@ public SubIssueDto createParentIssueDto(Issue issue) { if (epic == null) { return new SubIssueDto(); } - - AssigneeDto assigneeDto = Optional.ofNullable(epic.getAssignee()) - //TODO: AssigneeDto 클래스에 해당 부분 fromEntity 메서드로 만들기 [ ] - .map(assignee -> AssigneeDto.builder() - .id(assignee.getId()) - .name(assignee.getName()) - .build()) - .orElse(new AssigneeDto()); + AssigneeDto assigneeDto = createAssigneeDto(epic); return SubIssueDto.builder() .issueId(epic.getId()) .key(epic.getProject().getKey() + "-" + epic.getNumber()) .status(String.valueOf(epic.getStatus())) + .label(String.valueOf(epic.getLabel())) .type(EPIC) .title(epic.getTitle()) .assignee(assigneeDto) @@ -176,18 +156,13 @@ private Story getStory(Issue issue) { private SubIssueDto getTaskToSubIssueDto(Task task) { - AssigneeDto assigneeDto = Optional.ofNullable(task.getAssignee()) - //TODO: AssigneeDto 클래스에 해당 부분 fromEntity 메서드로 만들기 [ ] - .map(assignee -> AssigneeDto.builder() - .id(assignee.getId()) - .name(assignee.getName()) - .build()) - .orElse(new AssigneeDto()); + AssigneeDto assigneeDto = createAssigneeDto(task); return SubIssueDto.builder() .issueId(task.getId()) .key(task.getProject().getKey() + "-" + task.getNumber()) .status(String.valueOf(task.getStatus())) + .label(String.valueOf(task.getLabel())) .type(TASK) .title(task.getTitle()) .assignee(assigneeDto) @@ -212,4 +187,30 @@ private void validateParentIssue(Long parentId) { throw new GeneralException(ErrorStatus.PARENT_ISSUE_NOT_EPIC); } } + + private Story toEntity(IssueCreateRequest request, Project project, int issueNumber, Member assignee, Epic upEpic) { + return Story.builder() + .title(request.getTitle()) + .content(request.getContent()) + .number(issueNumber) + .status(request.getStatus()) + .label(request.getLabel()) + .assignee(assignee) + .project(project) + .startDate(request.getStartDate()) + .endDate(request.getEndDate()) + .epic(upEpic) + .build(); + } + + private AssigneeDto createAssigneeDto(Issue issue) { + + if (issue.getAssignee() == null) { + return new AssigneeDto(); + } + return AssigneeDto.from(issue.getAssignee().getId(), issue.getAssignee().getName(), + issue.getAssignee().getProfileImageUrl()); + } + + } diff --git a/src/main/java/dynamicquad/agilehub/issue/service/factory/TaskFactory.java b/src/main/java/dynamicquad/agilehub/issue/service/factory/TaskFactory.java index 277ccca..b844e35 100644 --- a/src/main/java/dynamicquad/agilehub/issue/service/factory/TaskFactory.java +++ b/src/main/java/dynamicquad/agilehub/issue/service/factory/TaskFactory.java @@ -5,7 +5,6 @@ import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueCreateRequest; import dynamicquad.agilehub.issue.controller.request.IssueRequest.IssueEditRequest; import dynamicquad.agilehub.issue.controller.request.IssueType; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.ContentDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.IssueDto; import dynamicquad.agilehub.issue.controller.response.IssueResponse.SubIssueDto; @@ -14,6 +13,7 @@ import dynamicquad.agilehub.issue.domain.story.Story; import dynamicquad.agilehub.issue.domain.task.Task; import dynamicquad.agilehub.member.domain.Member; +import dynamicquad.agilehub.member.dto.AssigneeDto; import dynamicquad.agilehub.member.service.MemberService; import dynamicquad.agilehub.project.domain.Project; import java.util.List; @@ -43,19 +43,8 @@ public Long createIssue(IssueCreateRequest request, Project project) { int issueNumber = (int) (issueRepository.countByProjectKey(project.getKey()) + 1); Member assignee = memberService.findMember(request.getAssigneeId(), project.getId()); - Story upStory = retrieveStoryFromParentIssue(request.getParentId()); - - // TODO: TASK toEntity 메서드에 이 로직 넣기 [ ] - Task task = Task.builder() - .title(request.getTitle()) - .content(request.getContent()) - .number(issueNumber) - .status(request.getStatus()) - .assignee(assignee) - .project(project) - .story(upStory) - .build(); + Task task = toEntity(request, project, issueNumber, assignee, upStory); issueRepository.save(task); return task.getId(); @@ -82,13 +71,14 @@ public ContentDto createContentDto(Issue issue) { @Override public IssueDto createIssueDto(Issue issue, ContentDto contentDto, AssigneeDto assigneeDto) { Task task = getTask(issue); - //TODO: IssueDto 클래스에 해당 부분 fromEntity 메서드로 만들기 [ ] + return IssueDto.builder() .issueId(task.getId()) .key(task.getProject().getKey() + "-" + task.getNumber()) .title(task.getTitle()) .type(TASK) .status(String.valueOf(task.getStatus())) + .label(String.valueOf(task.getLabel())) .startDate("") .endDate("") .content(contentDto) @@ -106,24 +96,20 @@ public SubIssueDto createParentIssueDto(Issue issue) { return null; } - AssigneeDto assigneeDto = Optional.ofNullable(story.getAssignee()) - //TODO: AssigneeDto 클래스에 해당 부분 fromEntity 메서드로 만들기 [ ] - .map(assignee -> AssigneeDto.builder() - .id(assignee.getId()) - .name(assignee.getName()) - .build()) - .orElse(new AssigneeDto()); + AssigneeDto assigneeDto = createAssigneeDto(story); return SubIssueDto.builder() .issueId(story.getId()) .key(story.getProject().getKey() + "-" + story.getNumber()) .status(String.valueOf(story.getStatus())) + .label(String.valueOf(story.getLabel())) .type(STORY) .title(story.getTitle()) .assignee(assigneeDto) .build(); } + @Override public List createChildIssueDtos(Issue issue) { return List.of(); @@ -157,4 +143,24 @@ private void validateParentIssue(Long parentId) { } + private Task toEntity(IssueCreateRequest request, Project project, int issueNumber, Member assignee, + Story upStory) { + return Task.builder() + .title(request.getTitle()) + .content(request.getContent()) + .number(issueNumber) + .status(request.getStatus()) + .label(request.getLabel()) + .assignee(assignee) + .project(project) + .story(upStory) + .build(); + } + + private AssigneeDto createAssigneeDto(Story story) { + return Optional.ofNullable(story.getAssignee()) + .map(assignee -> AssigneeDto.from(assignee.getId(), assignee.getName(), assignee.getProfileImageUrl())) + .orElse(new AssigneeDto()); + } + } diff --git a/src/main/java/dynamicquad/agilehub/member/dto/AssigneeDto.java b/src/main/java/dynamicquad/agilehub/member/dto/AssigneeDto.java new file mode 100644 index 0000000..78b2ab6 --- /dev/null +++ b/src/main/java/dynamicquad/agilehub/member/dto/AssigneeDto.java @@ -0,0 +1,30 @@ +package dynamicquad.agilehub.member.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +@Builder +@Getter +@AllArgsConstructor +@EqualsAndHashCode +public class AssigneeDto { + private Long id; + private String name; + private String profileImageURL; + + public AssigneeDto() { + this.id = null; + this.name = ""; + this.profileImageURL = ""; + } + + public static AssigneeDto from(Long id, String name, String profileImageURL) { + return AssigneeDto.builder() + .id(id) + .name(name) + .profileImageURL(profileImageURL) + .build(); + } +} diff --git a/src/main/java/dynamicquad/agilehub/sprint/controller/response/SprintResponse.java b/src/main/java/dynamicquad/agilehub/sprint/controller/response/SprintResponse.java index ffce913..df4a40d 100644 --- a/src/main/java/dynamicquad/agilehub/sprint/controller/response/SprintResponse.java +++ b/src/main/java/dynamicquad/agilehub/sprint/controller/response/SprintResponse.java @@ -1,9 +1,9 @@ package dynamicquad.agilehub.sprint.controller.response; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.domain.Issue; import dynamicquad.agilehub.issue.domain.epic.Epic; import dynamicquad.agilehub.issue.domain.story.Story; +import dynamicquad.agilehub.member.dto.AssigneeDto; import dynamicquad.agilehub.sprint.domain.Sprint; import java.util.List; import lombok.AllArgsConstructor; @@ -40,6 +40,7 @@ public static SprintCreateResponse fromEntity(Sprint sprint) { public static class SprintReadResponse { private Long sprintId; private String title; + private String status; private String description; private String startDate; private String endDate; @@ -58,6 +59,7 @@ public static class IssueInSprintDto { private Long issueId; private String key; private String status; + private String label; private String startDate; private String endDate; private AssigneeDto assigneeDto; @@ -68,6 +70,7 @@ public IssueInSprintDto() { this.issueId = null; this.key = ""; this.status = ""; + this.label = ""; this.startDate = ""; this.endDate = ""; this.assigneeDto = new AssigneeDto(); @@ -93,6 +96,7 @@ public static IssueInSprintDto fromEntity(Issue issue, String key, AssigneeDto a .issueId(issue.getId()) .key(key + "-" + issue.getNumber()) .status(String.valueOf(issue.getStatus())) + .label(String.valueOf(issue.getLabel())) .startDate(startDate) .endDate(endDate) .assigneeDto(assigneeDto) diff --git a/src/main/java/dynamicquad/agilehub/sprint/service/SprintQueryService.java b/src/main/java/dynamicquad/agilehub/sprint/service/SprintQueryService.java index efde50a..ff595a0 100644 --- a/src/main/java/dynamicquad/agilehub/sprint/service/SprintQueryService.java +++ b/src/main/java/dynamicquad/agilehub/sprint/service/SprintQueryService.java @@ -1,8 +1,8 @@ package dynamicquad.agilehub.sprint.service; -import dynamicquad.agilehub.issue.controller.response.IssueResponse.AssigneeDto; import dynamicquad.agilehub.issue.domain.Issue; import dynamicquad.agilehub.issue.domain.IssueRepository; +import dynamicquad.agilehub.member.dto.AssigneeDto; import dynamicquad.agilehub.project.service.ProjectQueryService; import dynamicquad.agilehub.sprint.controller.response.SprintResponse.IssueInSprintDto; import dynamicquad.agilehub.sprint.controller.response.SprintResponse.SprintReadResponse; @@ -36,6 +36,7 @@ public List getSprints(String key) { return SprintReadResponse.builder() .sprintId(sprint.getId()) .title(sprint.getTitle()) + .status(String.valueOf(sprint.getStatus())) .description(sprint.getTargetDescription()) .startDate(sprint.getStartDate() == null ? "" : sprint.getStartDate().toString()) .endDate(sprint.getEndDate() == null ? "" : sprint.getEndDate().toString()) diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index aacc7a2..cc4a970 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -10,7 +10,7 @@ spring: password: ${MYSQL_PASSWORD} jpa: hibernate: - ddl-auto: update + ddl-auto: create properties: hibernate: format_sql: true diff --git a/src/main/resources/shema.sql b/src/main/resources/shema.sql index bb2d8f6..93a2e9f 100644 --- a/src/main/resources/shema.sql +++ b/src/main/resources/shema.sql @@ -32,6 +32,7 @@ create table issue ( content varchar(255), title varchar(255), status enum ('DO','PROGRESS','DONE'), + label enum ('NONE', 'PLAN', 'DESIGN', 'DEVELOP', 'TEST', 'FEEDBACK'), primary key (issue_id) ) engine=InnoDB; create table member (