Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

프로젝트 상세 조회 기능 구현 #56

Merged
merged 26 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0917a07
chore: Project domain 내 File, Member 서브 패키지 생성 및 구조 변경
yenzip Feb 15, 2024
8f59ef1
chore: Flyway 기존 더미데이터 파일 이름 변경 및 더미데이터 추가
yenzip Feb 19, 2024
8ced1e0
chore: 스키마 project 테이블에 작성자 식별자 추가 및 indent 추가
yenzip Feb 19, 2024
c41fcdd
remove: 사용하지 않은 Member의 AuthorityType 제거 및 관련 Member 코드 수정
yenzip Feb 19, 2024
a1701f6
feat: UserSummaryResponse 비회원 관련 정적 오버 로딩 메서드 추가
yenzip Feb 19, 2024
1a56d94
feat: 기술 스택 조회 관련 응답 DTO 생성
yenzip Feb 19, 2024
7026256
feat: 프로젝트 팀원 조회 관련 응답 DTO 생성
yenzip Feb 19, 2024
b2b16da
feat: 프로젝트 작성자 식별자 추가 및 조회수 증가 메서드 추가
yenzip Feb 19, 2024
6b638d8
feat: 프로젝트 상세 조회 관련 응답 DTO 생성
yenzip Feb 19, 2024
46c42bb
feat: 프로젝트 관련 repository(Project, Member, ProjectSkill) 생성
yenzip Feb 19, 2024
a82cc51
feat: 프로젝트 service 생성 및 상세 조회 메서드 추가
yenzip Feb 19, 2024
0f424b5
refactor: FileType 이미지 유형 세분화
yenzip Feb 19, 2024
137f8c2
feat: 프로젝트 개요 이미지 리스트 조회 관련 DTO 생성
yenzip Feb 19, 2024
79447c6
feat: 프로젝트 상세 조회 응답 DTO에 개요 이미지 리스트 추가
yenzip Feb 19, 2024
3a96ad8
feat: 프로젝트 파일 관련 repository 생성
yenzip Feb 19, 2024
31bb3e1
feat: 프로젝트 service 상세 조회에서 개요에 사용되는 이미지 조회 로직 추가
yenzip Feb 19, 2024
b354d25
feat: 프로젝트 controller 생성 및 상세 조회 API 엔드포인트 추가
yenzip Feb 19, 2024
e6f794a
Merge branch 'dev' into feat/#05-read-project
yenzip Feb 19, 2024
e2d3831
fix: 변경된 응답 DTO 패키지 구조 반영
yenzip Feb 19, 2024
e883de4
style: 삼항 연산자 Checkstyle violation 해결
yenzip Feb 19, 2024
f8a50db
style: 필요없는 주석 제거
yenzip Feb 20, 2024
373e0e3
refactor: 프로젝트 service 팀원 조회 관련 로직 정적 메서드 오버로딩으로 변경
yenzip Feb 20, 2024
e48c9a9
feat: errorCode 인터페이스 생성
yenzip Feb 20, 2024
eb82378
feat: project 관련 errorCode 생성
yenzip Feb 20, 2024
0b847ac
feat: project service 에러 코드 적용
yenzip Feb 20, 2024
5a535f5
Merge branch 'dev' into feat/#05-read-project
yenzip Feb 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sidepeek_backend_secret
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package sixgaezzang.sidepeek.common.exception;

public interface ErrorCode {

int getCode();

String getMessage();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package sixgaezzang.sidepeek.projects.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sixgaezzang.sidepeek.projects.dto.response.ProjectResponse;
import sixgaezzang.sidepeek.projects.service.ProjectService;

@RestController
@RequestMapping("/projects")
@Tag(name = "Project", description = "Project API")
@RequiredArgsConstructor
public class ProjectController {

private final ProjectService projectService;

@GetMapping("/{id}")
@Operation(summary = "프로젝트 상세 조회")
@ApiResponse(responseCode = "200", description = "프로젝트 상세 조회 성공")
public ResponseEntity<ProjectResponse> getById(
@PathVariable Long id
) {
ProjectResponse response = projectService.findById(id);

return ResponseEntity.ok(response);
}

}
14 changes: 11 additions & 3 deletions src/main/java/sixgaezzang/sidepeek/projects/domain/Project.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public class Project extends BaseTimeEntity {
@Column(name = "github_url", columnDefinition = "TEXT")
private String githubUrl;

@Column(name = "owner_id", columnDefinition = "BIGINT")
private Long ownerId;

@Column(name = "description", nullable = false, columnDefinition = "TEXT")
private String description;

Expand All @@ -65,9 +68,10 @@ public class Project extends BaseTimeEntity {
private LocalDateTime deletedAt;

@Builder
public Project(String name, String subName, String overview, LocalDateTime startDate, LocalDateTime endDate,
String thumbnailUrl, String deployUrl, String githubUrl, String description,
String troubleshooting) {
public Project(String name, String subName, String overview, LocalDateTime startDate,
LocalDateTime endDate,
String thumbnailUrl, String deployUrl, String githubUrl, String description,
String troubleshooting) {
this.name = name;
this.subName = subName;
this.overview = overview;
Expand All @@ -82,4 +86,8 @@ public Project(String name, String subName, String overview, LocalDateTime start
this.viewCount = 0L;
}

public void increaseViewCount() {
this.viewCount++;
}

}
yenzip marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sixgaezzang.sidepeek.projects.domain.file;

public enum FileType {
IMAGE,
VIDEO
OVERVIEW_IMAGE,
DESCRIPTION_IMAGE,
TROUBLE_SHOOTING_IMAGE
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
Expand Down Expand Up @@ -36,21 +34,17 @@ public class Member {
@JoinColumn(name = "project_id")
private Project project;

@Column(name = "authority", nullable = false, length = 15, columnDefinition = "VARCHAR")
@Enumerated(EnumType.STRING)
private AuthorityType authority;

@Column(name = "role", nullable = false, length = 15)
private String role;

@Column(name = "nickname", nullable = false, length = 20)
private String nickname;

@Builder
public Member(User user, Project project, AuthorityType authority, String role, String nickname) {
public Member(User user, Project project, String role,
String nickname) {
this.user = user;
this.project = project;
this.authority = authority;
this.role = role;
this.nickname = nickname;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package sixgaezzang.sidepeek.projects.dto.response;

import lombok.Builder;
import sixgaezzang.sidepeek.projects.domain.member.Member;
import sixgaezzang.sidepeek.users.domain.User;
import sixgaezzang.sidepeek.users.dto.response.UserSummaryResponse;

@Builder
public record MemberSummary(
Long id,
String category,
UserSummaryResponse userSummary
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 UserSummaryResponse이름 그냥 UserSummaryㄹ 변경하느 것이 좋을까요? 이건 제가 제 PR 에서 반영하겠습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 UserSummary로 하면 더 통일성 있고 좋을 것 같아요! 반영해주시면 감사하겠습니다 👍

) {

public static MemberSummary from(Member member) {
User user = member.getUser();
UserSummaryResponse userSummaryResponse = (user == null)
? UserSummaryResponse.from(member.getNickname())
: UserSummaryResponse.from(user);
return MemberSummary.from(member, userSummaryResponse);
}

public static MemberSummary from(Member member, UserSummaryResponse userSummary) {
return MemberSummary.builder()
.id(member.getId())
.category(member.getRole())
.userSummary(userSummary)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package sixgaezzang.sidepeek.projects.dto.response;

import lombok.Builder;
import sixgaezzang.sidepeek.projects.domain.file.File;

@Builder
public record OverviewImageSummary(
Long id,
String url
) {

public static OverviewImageSummary from(File file) {
return OverviewImageSummary.builder()
.id(file.getId())
.url(file.getUrl())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package sixgaezzang.sidepeek.projects.dto.response;

import java.time.YearMonth;
import java.util.List;
import lombok.Builder;
import sixgaezzang.sidepeek.projects.domain.Project;

@Builder
public record ProjectResponse(
Long id,
String name,
String subName,
String overview,
String thumbnailUrl,
List<OverviewImageSummary> overviewImageUrl,
String githubUrl,
String deployUrl,
Long viewCount,
Long likeCount,
List<ProjectSkillSummary> techStacks,
YearMonth startDate,
YearMonth endDate,
List<MemberSummary> members,
String description,
String troubleShooting
) {

public static ProjectResponse from(Project project, List<OverviewImageSummary> overviewImageUrl,
List<ProjectSkillSummary> techStacks,
List<MemberSummary> members) {
return ProjectResponse.builder()
.id(project.getId())
.name(project.getName())
.subName(project.getSubName())
.overview(project.getOverview())
.thumbnailUrl(project.getThumbnailUrl())
.overviewImageUrl(overviewImageUrl)
.githubUrl(project.getGithubUrl())
.deployUrl(project.getDeployUrl())
.viewCount(project.getViewCount())
.likeCount(project.getLikeCount())
.techStacks(techStacks)
.startDate(YearMonth.from(project.getStartDate()))
.endDate(YearMonth.from(project.getEndDate()))
.members(members)
.description(project.getDescription())
.troubleShooting(project.getTroubleshooting())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package sixgaezzang.sidepeek.projects.dto.response;

import lombok.Builder;
import sixgaezzang.sidepeek.projects.domain.ProjectSkill;
import sixgaezzang.sidepeek.skill.dto.response.SkillResponse;

@Builder
public record ProjectSkillSummary(
Long id,
String category,
SkillResponse skill
) {

public static ProjectSkillSummary from(ProjectSkill projectSkill) {
return ProjectSkillSummary.builder()
.id(projectSkill.getId())
.category(projectSkill.getCategory())
.skill(SkillResponse.from(projectSkill.getSkill()))
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package sixgaezzang.sidepeek.projects.exception;

import sixgaezzang.sidepeek.common.exception.ErrorCode;

public enum ProjectErrorCode implements ErrorCode {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍👍👍


ID_NOT_EXISTING(2001, "해당 프로젝트가 존재하지 않습니다.");

private final int code;
private final String message;

ProjectErrorCode(int code, String message) {
this.code = code;
this.message = message;
}

@Override
public int getCode() {
return code;
}

@Override
public String getMessage() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package sixgaezzang.sidepeek.projects.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import sixgaezzang.sidepeek.projects.domain.Project;
import sixgaezzang.sidepeek.projects.domain.file.File;
import sixgaezzang.sidepeek.projects.domain.file.FileType;

public interface FileRepository extends JpaRepository<File, Long> {

List<File> findAllByProjectAndType(Project project, FileType type);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package sixgaezzang.sidepeek.projects.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import sixgaezzang.sidepeek.projects.domain.Project;
import sixgaezzang.sidepeek.projects.domain.member.Member;

public interface MemberRepository extends JpaRepository<Member, Long> {

List<Member> findAllByProject(Project project);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package sixgaezzang.sidepeek.projects.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import sixgaezzang.sidepeek.projects.domain.Project;

public interface ProjectRepository extends JpaRepository<Project, Long> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package sixgaezzang.sidepeek.projects.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import sixgaezzang.sidepeek.projects.domain.Project;
import sixgaezzang.sidepeek.projects.domain.ProjectSkill;

public interface ProjectSkillRepository extends JpaRepository<ProjectSkill, Long> {

List<ProjectSkill> findAllByProject(Project project);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package sixgaezzang.sidepeek.projects.service;

import jakarta.persistence.EntityNotFoundException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sixgaezzang.sidepeek.projects.domain.Project;
import sixgaezzang.sidepeek.projects.domain.file.FileType;
import sixgaezzang.sidepeek.projects.dto.response.MemberSummary;
import sixgaezzang.sidepeek.projects.dto.response.OverviewImageSummary;
import sixgaezzang.sidepeek.projects.dto.response.ProjectResponse;
import sixgaezzang.sidepeek.projects.dto.response.ProjectSkillSummary;
import sixgaezzang.sidepeek.projects.exception.ProjectErrorCode;
import sixgaezzang.sidepeek.projects.repository.FileRepository;
import sixgaezzang.sidepeek.projects.repository.MemberRepository;
import sixgaezzang.sidepeek.projects.repository.ProjectRepository;
import sixgaezzang.sidepeek.projects.repository.ProjectSkillRepository;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ProjectService {

private final ProjectRepository projectRepository;
private final ProjectSkillRepository projectSkillRepository;
private final MemberRepository memberRepository;
private final FileRepository fileRepository;

public ProjectResponse findById(Long id) {

Project project = projectRepository.findById(id)
.orElseThrow(
() -> new EntityNotFoundException(ProjectErrorCode.ID_NOT_EXISTING.getMessage()));

project.increaseViewCount();

List<OverviewImageSummary> overviewImages = fileRepository.findAllByProjectAndType(
project, FileType.OVERVIEW_IMAGE)
.stream()
.map(OverviewImageSummary::from)
.toList();

List<ProjectSkillSummary> techStacks = projectSkillRepository.findAllByProject(project)
.stream()
.map(ProjectSkillSummary::from)
.toList();

List<MemberSummary> members = memberRepository.findAllByProject(project)
.stream()
.map(MemberSummary::from)
.toList();

return ProjectResponse.from(project, overviewImages, techStacks, members);
}

}
Loading
Loading