Skip to content

Commit

Permalink
Merge pull request #83 from BaeJunH0/feat/#76-makeProjectDomain
Browse files Browse the repository at this point in the history
[Feat] #76 프로젝트 도메인과 기능 구현
  • Loading branch information
BaeJunH0 authored Jan 1, 2025
2 parents 6b57aa6 + 9d7ac83 commit 25ca985
Show file tree
Hide file tree
Showing 13 changed files with 443 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.sparksInTheStep.webBoard.global.errorHandling.errorCode;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@AllArgsConstructor
@Getter
public enum ProjectErrorCode implements ErrorCode{
NOT_FOUND(HttpStatus.NOT_FOUND, "Pr000", "No such project"),
NOT_TEAM_LEADER(HttpStatus.FORBIDDEN, "Pr001", "Project can be deleted by only team leader"),
ALREADY_EXIST_NAME(HttpStatus.FORBIDDEN, "Pr002", "Project's name is already using"),
ALREADY_JOINED_PROJECT(HttpStatus.FORBIDDEN, "Pr003", "Login user already in this project");

private final HttpStatus httpStatus;
private final String errorCode;
private final String message;

@Override
public HttpStatus httpStatus() {
return this.httpStatus;
}

@Override
public String code() {
return this.errorCode;
}

@Override
public String message() {
return this.message;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.sparksInTheStep.webBoard.member.domain;

import com.sparksInTheStep.webBoard.project.doamin.Project;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.sparksInTheStep.webBoard.project.application;

import com.sparksInTheStep.webBoard.global.errorHandling.CustomException;
import com.sparksInTheStep.webBoard.global.errorHandling.errorCode.ProjectErrorCode;
import com.sparksInTheStep.webBoard.project.doamin.JoinedProject;
import com.sparksInTheStep.webBoard.project.persistent.JoinedProjectRepository;
import com.sparksInTheStep.webBoard.member.domain.Member;
import com.sparksInTheStep.webBoard.member.persistent.MemberRepository;
import com.sparksInTheStep.webBoard.project.application.dto.ProjectCommand;
import com.sparksInTheStep.webBoard.project.application.dto.ProjectInfo;
import com.sparksInTheStep.webBoard.project.doamin.Project;
import com.sparksInTheStep.webBoard.project.persistent.ProjectRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class ProjectService {
private final ProjectRepository projectRepository;
private final MemberRepository memberRepository;
private final JoinedProjectRepository joinedProjectRepository;

@Transactional(readOnly = true)
public Page<ProjectInfo> getAllProjects(Pageable pageable){
return projectRepository.findAll(pageable).map(ProjectInfo::of);
}
@Transactional(readOnly = true)
public ProjectInfo getProject(Long id){
Project project = projectRepository.findById(id).orElseThrow(
() -> CustomException.of(ProjectErrorCode.NOT_FOUND)
);
return ProjectInfo.of(project);
}
@Transactional(readOnly = true)
public Page<ProjectInfo> getMyProjects(Pageable pageable, String nickname) {
Member member = memberRepository.findByNickname(nickname);
Page<JoinedProject> joinedProjects = joinedProjectRepository.findJoinedProjectsByMember(pageable, member);
return joinedProjects.map(JoinedProject::getProject).map(ProjectInfo::of);
}
@Transactional
public void makeProject(ProjectCommand projectCommand){
if(projectRepository.existsByName(projectCommand.name())) {
throw CustomException.of(ProjectErrorCode.ALREADY_EXIST_NAME);
}
Project project = Project.of(projectCommand);
projectRepository.save(project);
}
@Transactional
public void joinProject(Long id, String nickname) {
Project project = projectRepository.findById(id).orElseThrow(
() -> CustomException.of(ProjectErrorCode.NOT_FOUND)
);
Member member = memberRepository.findByNickname(nickname);

if(joinedProjectRepository.existsByMemberAndProject(member, project)){
throw CustomException.of(ProjectErrorCode.ALREADY_JOINED_PROJECT);
}
JoinedProject joinedProject = JoinedProject.from(member, project);
joinedProjectRepository.save(joinedProject);
}
@Transactional
public void updateProject(Long id, ProjectCommand projectCommand){
Project project = projectRepository.findById(id).orElseThrow(
() -> CustomException.of(ProjectErrorCode.NOT_FOUND)
);
if(projectRepository.existsByName(projectCommand.name())) {
throw CustomException.of(ProjectErrorCode.ALREADY_EXIST_NAME);
}
if(!project.getName().equals(projectCommand.nickname())) {
throw CustomException.of(ProjectErrorCode.NOT_TEAM_LEADER);
}

project.update(projectCommand.name(), projectCommand.info(), projectCommand.gitLink());
}

@Transactional
public void deleteProject(Long id, String nickname){
Project project = projectRepository.findById(id).orElseThrow(
() -> CustomException.of(ProjectErrorCode.NOT_FOUND)
);
if(!project.getName().equals(nickname)) {
throw CustomException.of(ProjectErrorCode.NOT_TEAM_LEADER);
}

projectRepository.delete(project);
}

@Transactional
public void withdrawProject(Long id, String nickname) {
Project project = projectRepository.findById(id).orElseThrow(
() -> CustomException.of(ProjectErrorCode.NOT_FOUND)
);
Member member = memberRepository.findByNickname(nickname);

if(!joinedProjectRepository.existsByMemberAndProject(member, project)){
throw CustomException.of(ProjectErrorCode.NOT_FOUND);
}

joinedProjectRepository.deleteByMemberAndProject(member, project);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.sparksInTheStep.webBoard.project.application.dto;

import com.sparksInTheStep.webBoard.project.presentation.dto.ProjectRequest;

public record ProjectCommand(String name, String info, String gitLink, String nickname) {
public static ProjectCommand from(ProjectRequest projectRequest, String nickname) {
return new ProjectCommand(
projectRequest.name(), projectRequest.info(), projectRequest.gitLink(), nickname
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.sparksInTheStep.webBoard.project.application.dto;

import com.sparksInTheStep.webBoard.project.doamin.Project;

public record ProjectInfo(String name, String info, String gitLink, String leaderName) {
public static ProjectInfo of(Project project){
return new ProjectInfo(
project.getName(), project.getInfo(), project.getGitLink(), project.getLeaderName()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.sparksInTheStep.webBoard.project.doamin;

import com.sparksInTheStep.webBoard.member.domain.Member;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Getter
public class JoinedProject {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
@ManyToOne
@JoinColumn(name = "project_id")
private Project project;

private JoinedProject(Member member, Project project) {
this.member = member;
this.project = project;
}

public static JoinedProject from(
Member member, Project project
){
return new JoinedProject(member, project);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.sparksInTheStep.webBoard.project.doamin;

import com.sparksInTheStep.webBoard.member.domain.Member;
import com.sparksInTheStep.webBoard.project.application.dto.ProjectCommand;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Getter
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String name;
@Column(nullable = false)
private String info;
@Column(nullable = false)
private String gitLink;
@Column(nullable = false)
private String leaderName;

private Project(String name, String info, String gitLink, String leaderName){
this.name = name;
this.info = info;
this.gitLink = gitLink;
this.leaderName = leaderName;
}

public static Project of(ProjectCommand projectCommand){
return new Project(
projectCommand.name(),
projectCommand.info(),
projectCommand.gitLink(),
projectCommand.name()
);
}

public void update(String name, String info, String gitLink){
this.name = name;
this.info = info;
this.gitLink = gitLink;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.sparksInTheStep.webBoard.project.persistent;

import com.sparksInTheStep.webBoard.project.doamin.JoinedProject;
import com.sparksInTheStep.webBoard.member.domain.Member;
import com.sparksInTheStep.webBoard.project.doamin.Project;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface JoinedProjectRepository extends JpaRepository<JoinedProject, Long> {
Page<JoinedProject> findJoinedProjectsByMember(Pageable pageable, Member member);

Boolean existsByMemberAndProject(Member member, Project project);

void deleteByMemberAndProject(Member member, Project project);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sparksInTheStep.webBoard.project.persistent;

import com.sparksInTheStep.webBoard.project.doamin.Project;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProjectRepository extends JpaRepository<Project, Long> {
Page<Project> findAll(Pageable pageable);

Boolean existsByName(String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.sparksInTheStep.webBoard.project.presentation;

import com.sparksInTheStep.webBoard.global.annotation.AuthorizedUser;
import com.sparksInTheStep.webBoard.member.application.dto.MemberInfo;
import com.sparksInTheStep.webBoard.project.presentation.dto.ProjectRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

public interface ProjectApiSpec {
@Operation(summary = "모든 프로젝트 조회", description = "모든 프로젝트를 조회합니다")
@ApiResponse(responseCode="200", description = "성공")
ResponseEntity<?> readAllProject(
@PageableDefault Pageable pageable
);
@Operation(summary = "특정 프로젝트 조회", description = "특정 프로젝트를 조회합니다")
@ApiResponse(responseCode="200", description = "성공")
ResponseEntity<?> readOneProject(
@PathVariable Long projectId
);
@Operation(summary = "프로젝트 생성", description = "프로젝트를 생성합니다")
@ApiResponse(responseCode="201", description = "성공")
ResponseEntity<?> createProject(
@RequestBody ProjectRequest projectRequest,
@AuthorizedUser MemberInfo.Default memberInfo
);
@Operation(summary = "프로젝트 수정", description = "프로젝트의 내용을 수정합니다 ( 프로젝트 장만 가능 )")
@ApiResponse(responseCode="200", description = "성공")
ResponseEntity<?> updateProject(
@PathVariable Long projectId,
@RequestBody ProjectRequest projectRequest,
@AuthorizedUser MemberInfo.Default memberInfo
);
@Operation(summary = "프로젝트 삭제", description = "프로젝트를 삭제합니다 ( 프로젝트 장만 가능 )")
@ApiResponse(responseCode="204", description = "성공")
ResponseEntity<?> deleteProject(
@PathVariable Long projectId,
@AuthorizedUser MemberInfo.Default memberInfo
);
@Operation(summary = "내가 가입된 프로젝트 조회", description = "가입한 프로젝트를 조회합니다")
@ApiResponse(responseCode="200", description = "성공")
ResponseEntity<?> readMyProject(
@PageableDefault Pageable pageable,
@AuthorizedUser MemberInfo.Default memberInfo
);
@Operation(summary = "프로젝트 가입", description = "프로젝트에 가입합니다")
@ApiResponse(responseCode="200", description = "성공")
ResponseEntity<?> joinToProject(
@PathVariable Long projectId,
@AuthorizedUser MemberInfo.Default memberInfo
);
@Operation(summary = "프로젝트 탈퇴", description = "프로젝트에서 탈퇴합니다")
@ApiResponse(responseCode="204", description = "성공")
ResponseEntity<?> withdrawProject(
@PathVariable Long projectId,
@AuthorizedUser MemberInfo.Default memberInfo
);
}
Loading

0 comments on commit 25ca985

Please sign in to comment.