diff --git a/src/main/java/org/cotato/csquiz/api/project/controller/ProjectController.java b/src/main/java/org/cotato/csquiz/api/project/controller/ProjectController.java new file mode 100644 index 00000000..0fdfbac6 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/project/controller/ProjectController.java @@ -0,0 +1,27 @@ +package org.cotato.csquiz.api.project.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.cotato.csquiz.api.project.dto.ProjectDetailResponse; +import org.cotato.csquiz.domain.generation.service.ProjectService; +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; + +@Tag(name = "프로젝트 API") +@RestController +@RequiredArgsConstructor +@RequestMapping("/v2/api/projects") +public class ProjectController { + + private final ProjectService projectService; + + @Operation(summary = "특정 프로젝트 상세 정보 조회 API") + @GetMapping("/{projectId}") + public ResponseEntity getProjectDetail(@PathVariable("projectId") Long projectId) { + return ResponseEntity.ok().body(projectService.getProjectDetail(projectId)); + } +} diff --git a/src/main/java/org/cotato/csquiz/api/project/dto/ProjectDetailResponse.java b/src/main/java/org/cotato/csquiz/api/project/dto/ProjectDetailResponse.java new file mode 100644 index 00000000..13588ee6 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/project/dto/ProjectDetailResponse.java @@ -0,0 +1,38 @@ +package org.cotato.csquiz.api.project.dto; + +import java.util.List; +import org.cotato.csquiz.domain.generation.entity.Project; +import org.cotato.csquiz.domain.generation.entity.ProjectImage; +import org.cotato.csquiz.domain.generation.entity.ProjectMember; + +public record ProjectDetailResponse( + Long projectId, + String name, + String introduction, + String githubUrl, + String behanceUrl, + String projectUrl, + Long generationId, + Integer generationNumber, + List imageInfos, + List memberInfos +) { + public static ProjectDetailResponse of(Project project, Integer generationNumber, List projectImages, List projectMembers){ + return new ProjectDetailResponse( + project.getId(), + project.getName(), + project.getIntroduction(), + project.getGithubUrl(), + project.getBehanceUrl(), + project.getProjectUrl(), + project.getGenerationId(), + generationNumber, + projectImages.stream() + .map(ProjectImageInfoResponse::from) + .toList(), + projectMembers.stream() + .map(ProjectMemberInfoResponse::from) + .toList() + ); + } +} diff --git a/src/main/java/org/cotato/csquiz/api/project/dto/ProjectImageInfoResponse.java b/src/main/java/org/cotato/csquiz/api/project/dto/ProjectImageInfoResponse.java new file mode 100644 index 00000000..b9b7905e --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/project/dto/ProjectImageInfoResponse.java @@ -0,0 +1,18 @@ +package org.cotato.csquiz.api.project.dto; + +import org.cotato.csquiz.domain.generation.entity.ProjectImage; +import org.cotato.csquiz.domain.generation.enums.ProjectImageType; + +public record ProjectImageInfoResponse( + Long imageId, + String imageUrl, + ProjectImageType projectImageType +) { + public static ProjectImageInfoResponse from(ProjectImage projectImage) { + return new ProjectImageInfoResponse( + projectImage.getId(), + projectImage.getS3Info().getUrl(), + projectImage.getProjectImageType() + ); + } +} diff --git a/src/main/java/org/cotato/csquiz/api/project/dto/ProjectMemberInfoResponse.java b/src/main/java/org/cotato/csquiz/api/project/dto/ProjectMemberInfoResponse.java new file mode 100644 index 00000000..aa51e544 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/project/dto/ProjectMemberInfoResponse.java @@ -0,0 +1,18 @@ +package org.cotato.csquiz.api.project.dto; + +import org.cotato.csquiz.domain.auth.enums.MemberPosition; +import org.cotato.csquiz.domain.generation.entity.ProjectMember; + +public record ProjectMemberInfoResponse( + Long memberId, + String name, + MemberPosition memberPosition +) { + public static ProjectMemberInfoResponse from(ProjectMember projectMember) { + return new ProjectMemberInfoResponse( + projectMember.getId(), + projectMember.getName(), + projectMember.getMemberPosition() + ); + } +} diff --git a/src/main/java/org/cotato/csquiz/domain/generation/repository/GenerationRepository.java b/src/main/java/org/cotato/csquiz/domain/generation/repository/GenerationRepository.java index 806dc194..6e3293e9 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/repository/GenerationRepository.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/repository/GenerationRepository.java @@ -4,9 +4,14 @@ import java.util.Optional; import org.cotato.csquiz.domain.generation.entity.Generation; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface GenerationRepository extends JpaRepository { Optional findByNumber(int number); List findByNumberGreaterThanEqual(int generationNumber); + + @Query("SELECT g.number FROM Generation g WHERE g.id = :generationId") + Integer findGenerationNumberByGenerationId(@Param("generationId") Long generationId); } diff --git a/src/main/java/org/cotato/csquiz/domain/generation/repository/ProjectImageRepository.java b/src/main/java/org/cotato/csquiz/domain/generation/repository/ProjectImageRepository.java new file mode 100644 index 00000000..e065269b --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/generation/repository/ProjectImageRepository.java @@ -0,0 +1,10 @@ +package org.cotato.csquiz.domain.generation.repository; + +import java.util.List; +import org.cotato.csquiz.domain.generation.entity.ProjectImage; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProjectImageRepository extends JpaRepository { + List findByProjectId(Long projectId); + List findAllByProjectId(Long projectId); +} diff --git a/src/main/java/org/cotato/csquiz/domain/generation/repository/ProjectMemberRepository.java b/src/main/java/org/cotato/csquiz/domain/generation/repository/ProjectMemberRepository.java new file mode 100644 index 00000000..5b192a82 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/generation/repository/ProjectMemberRepository.java @@ -0,0 +1,9 @@ +package org.cotato.csquiz.domain.generation.repository; + +import java.util.List; +import org.cotato.csquiz.domain.generation.entity.ProjectMember; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProjectMemberRepository extends JpaRepository { + List findAllByProjectId(Long projectId); +} diff --git a/src/main/java/org/cotato/csquiz/domain/generation/repository/ProjectRepository.java b/src/main/java/org/cotato/csquiz/domain/generation/repository/ProjectRepository.java new file mode 100644 index 00000000..1f45355a --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/generation/repository/ProjectRepository.java @@ -0,0 +1,7 @@ +package org.cotato.csquiz.domain.generation.repository; + +import org.cotato.csquiz.domain.generation.entity.Project; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProjectRepository extends JpaRepository{ +} diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/ProjectService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/ProjectService.java new file mode 100644 index 00000000..2f161c88 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/ProjectService.java @@ -0,0 +1,39 @@ +package org.cotato.csquiz.domain.generation.service; + +import jakarta.persistence.EntityNotFoundException; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.cotato.csquiz.api.project.dto.ProjectDetailResponse; +import org.cotato.csquiz.domain.generation.entity.Project; +import org.cotato.csquiz.domain.generation.entity.ProjectImage; +import org.cotato.csquiz.domain.generation.entity.ProjectMember; +import org.cotato.csquiz.domain.generation.repository.GenerationRepository; +import org.cotato.csquiz.domain.generation.repository.ProjectImageRepository; +import org.cotato.csquiz.domain.generation.repository.ProjectMemberRepository; +import org.cotato.csquiz.domain.generation.repository.ProjectRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class ProjectService { + + private final ProjectRepository projectRepository; + private final ProjectImageRepository projectImageRepository; + private final ProjectMemberRepository projectMemberRepository; + private final GenerationRepository generationRepository; + + @Transactional + public ProjectDetailResponse getProjectDetail(Long projectId) { + + Project project = projectRepository.findById(projectId) + .orElseThrow(() -> new EntityNotFoundException("찾으려는 프로젝트가 존재하지 않습니다.")); + + List images = projectImageRepository.findAllByProjectId(projectId); + List members = projectMemberRepository.findAllByProjectId(projectId); + Integer generationNumber = generationRepository.findGenerationNumberByGenerationId(project.getGenerationId()); + + return ProjectDetailResponse.of(project, generationNumber, images, members); + } +}