-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #198 from Gongjakso/feat/portfolio
feat: 포트폴리오 CRUD API (공작소 양식) 개발
- Loading branch information
Showing
9 changed files
with
376 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
src/main/java/com/gongjakso/server/domain/portfolio/controller/PortfolioController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package com.gongjakso.server.domain.portfolio.controller; | ||
|
||
import com.gongjakso.server.domain.portfolio.dto.request.PortfolioReq; | ||
import com.gongjakso.server.domain.portfolio.dto.response.PortfolioRes; | ||
import com.gongjakso.server.domain.portfolio.service.PortfolioService; | ||
import com.gongjakso.server.global.common.ApplicationResponse; | ||
import com.gongjakso.server.global.security.PrincipalDetails; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.PutMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("api/v2/mypage/portfolio") | ||
public class PortfolioController { | ||
|
||
private final PortfolioService portfolioService; | ||
|
||
@Operation(description = "포트폴리오 등록 API") | ||
@PostMapping("") | ||
public ApplicationResponse<PortfolioRes> registerPortfolio(@AuthenticationPrincipal PrincipalDetails principalDetails, | ||
@Valid @RequestBody PortfolioReq portfolioReq) { | ||
return ApplicationResponse.ok(portfolioService.registerPortfolio(principalDetails.getMember(), portfolioReq)); | ||
} | ||
|
||
@Operation(description = "포트폴리오 상세 조회 API") | ||
@GetMapping("/{portfolio_id}") | ||
public ApplicationResponse<PortfolioRes> getPortfolio(@AuthenticationPrincipal PrincipalDetails principalDetails, | ||
@PathVariable("portfolio_id") Long portfolioId) { | ||
return ApplicationResponse.ok(portfolioService.getPortfolio(principalDetails.getMember(), portfolioId)); | ||
} | ||
|
||
@Operation(description = "포트폴리오 수정 API") | ||
@PutMapping("/{portfolio_id}") | ||
public ApplicationResponse<PortfolioRes> updatePortfolio(@AuthenticationPrincipal PrincipalDetails principalDetails, | ||
@PathVariable("portfolio_id") Long portfolioId, | ||
@Valid @RequestBody PortfolioReq portfolioReq) { | ||
return ApplicationResponse.ok(portfolioService.updatePortfolio(principalDetails.getMember(), portfolioId, portfolioReq)); | ||
} | ||
|
||
@Operation(description = "포트폴리오 삭제 API") | ||
@DeleteMapping("/{portfolio_id}") | ||
public ApplicationResponse<Void> deletePortfolio(@AuthenticationPrincipal PrincipalDetails principalDetails, | ||
@PathVariable("portfolio_id") Long portfolioId) { | ||
portfolioService.deletePortfolio(principalDetails.getMember(), portfolioId); | ||
|
||
return ApplicationResponse.ok(); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
src/main/java/com/gongjakso/server/domain/portfolio/dto/request/PortfolioReq.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package com.gongjakso.server.domain.portfolio.dto.request; | ||
|
||
import java.time.LocalDate; | ||
import java.util.List; | ||
import lombok.Builder; | ||
|
||
@Builder | ||
public record PortfolioReq ( | ||
List<Education> educationList, | ||
List<Work> workList, | ||
List<Activty> activityList, | ||
List<Award> awardList, | ||
List<Certificate> certificateList, | ||
List<Sns> snsList | ||
) { | ||
public record Education ( | ||
String school, | ||
String grade, | ||
Boolean isActive | ||
) { | ||
} | ||
|
||
public record Work ( | ||
String company, | ||
String partition, | ||
LocalDate enteredAt, | ||
LocalDate exitedAt, | ||
Boolean isActive, | ||
String detail | ||
) { | ||
} | ||
|
||
public record Activty ( | ||
String name, | ||
Boolean isActive | ||
) { | ||
} | ||
public record Award ( | ||
String contestName, | ||
String awardName, | ||
LocalDate awardDate | ||
) { | ||
} | ||
public record Certificate ( | ||
String name, | ||
String rating, | ||
LocalDate certificationDate | ||
) { | ||
} | ||
public record Sns ( | ||
String snsLink | ||
) { | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/com/gongjakso/server/domain/portfolio/dto/response/PortfolioRes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.gongjakso.server.domain.portfolio.dto.response; | ||
|
||
import com.fasterxml.jackson.annotation.JsonInclude; | ||
import com.gongjakso.server.domain.portfolio.entity.Portfolio; | ||
import com.gongjakso.server.domain.portfolio.vo.PortfolioData; | ||
import lombok.Builder; | ||
import java.util.List; | ||
|
||
@Builder | ||
@JsonInclude(JsonInclude.Include.NON_NULL) | ||
public record PortfolioRes ( | ||
Long id, | ||
List<PortfolioData.Education> educationList, | ||
List<PortfolioData.Work> workList, | ||
List<PortfolioData.Activity> activityList, | ||
List<PortfolioData.Award> awardList, | ||
List<PortfolioData.Certificate> certificateList, | ||
List<PortfolioData.Sns> snsList | ||
) { | ||
public static PortfolioRes from(Portfolio portfolio) { | ||
PortfolioData portfolioData = portfolio.getPortfolioData(); | ||
return new PortfolioRes( | ||
portfolio.getId(), | ||
portfolioData.educationList(), | ||
portfolioData.workList(), | ||
portfolioData.activityList(), | ||
portfolioData.awardList(), | ||
portfolioData.certificateList(), | ||
portfolioData.snsList() | ||
); | ||
} | ||
} |
28 changes: 26 additions & 2 deletions
28
src/main/java/com/gongjakso/server/domain/portfolio/entity/Portfolio.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,45 @@ | ||
package com.gongjakso.server.domain.portfolio.entity; | ||
|
||
import com.gongjakso.server.domain.member.entity.Member; | ||
import com.gongjakso.server.domain.portfolio.vo.PortfolioData; | ||
import com.gongjakso.server.global.common.BaseTimeEntity; | ||
import jakarta.persistence.*; | ||
import java.time.LocalDate; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import org.hibernate.annotations.JdbcTypeCode; | ||
import org.hibernate.annotations.SQLDelete; | ||
import org.hibernate.type.SqlTypes; | ||
|
||
@Getter | ||
@Entity | ||
@Table(name = "portfolio") | ||
@SQLDelete(sql = "UPDATE portfolio SET deleted_at = NOW() where id = ?") | ||
@SQLDelete(sql = "UPDATE portfolio SET deleted_at = NOW() where portfolio_id = ?") | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class Portfolio extends BaseTimeEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "id",nullable = false,columnDefinition = "bigint") | ||
@Column(name = "portfolio_id", nullable = false, columnDefinition = "bigint") | ||
private Long id; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "member_id") | ||
private Member member; | ||
|
||
@Column(name = "portfolio_data", columnDefinition = "json") | ||
@JdbcTypeCode(SqlTypes.JSON) | ||
private PortfolioData portfolioData; | ||
|
||
@Builder | ||
public Portfolio(Member member, PortfolioData portfolioData) { | ||
this.member = member; | ||
this.portfolioData = portfolioData; | ||
} | ||
|
||
public void update(PortfolioData updatedData) { | ||
this.portfolioData = updatedData; | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/com/gongjakso/server/domain/portfolio/repository/PortfolioRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.gongjakso.server.domain.portfolio.repository; | ||
|
||
import com.gongjakso.server.domain.portfolio.entity.Portfolio; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface PortfolioRepository extends JpaRepository<Portfolio, Long> { | ||
Optional<Portfolio> findByIdAndDeletedAtIsNull(Long portfolioId); | ||
} |
139 changes: 139 additions & 0 deletions
139
src/main/java/com/gongjakso/server/domain/portfolio/service/PortfolioService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package com.gongjakso.server.domain.portfolio.service; | ||
|
||
import com.gongjakso.server.domain.member.entity.Member; | ||
import com.gongjakso.server.domain.portfolio.dto.request.PortfolioReq; | ||
import com.gongjakso.server.domain.portfolio.dto.response.PortfolioRes; | ||
import com.gongjakso.server.domain.portfolio.entity.Portfolio; | ||
import com.gongjakso.server.domain.portfolio.vo.PortfolioData; | ||
import com.gongjakso.server.domain.portfolio.repository.PortfolioRepository; | ||
import com.gongjakso.server.global.exception.ApplicationException; | ||
import com.gongjakso.server.global.exception.ErrorCode; | ||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class PortfolioService { | ||
|
||
private final PortfolioRepository portfolioRepository; | ||
|
||
// PortfolioReq -> PortfolioData 변환 | ||
private PortfolioData convertToPortfolioData(PortfolioReq portfolioReq) { | ||
List<PortfolioData.Education> educationList = portfolioReq.educationList() != null | ||
? portfolioReq.educationList().stream() | ||
.map(education -> new PortfolioData.Education( | ||
education.school(), | ||
education.grade(), | ||
education.isActive() | ||
)) | ||
.toList() | ||
: List.of(); | ||
|
||
List<PortfolioData.Work> workList = portfolioReq.workList() != null | ||
? portfolioReq.workList().stream() | ||
.map(work -> new PortfolioData.Work( | ||
work.company(), | ||
work.partition(), | ||
work.enteredAt(), | ||
work.exitedAt(), | ||
work.isActive(), | ||
work.detail() | ||
)) | ||
.toList() | ||
: List.of(); | ||
|
||
List<PortfolioData.Activity> activityList = portfolioReq.activityList() != null | ||
? portfolioReq.activityList().stream() | ||
.map(activity -> new PortfolioData.Activity( | ||
activity.name(), | ||
activity.isActive() | ||
)) | ||
.toList() | ||
: List.of(); | ||
|
||
List<PortfolioData.Award> awardList = portfolioReq.awardList() != null | ||
? portfolioReq.awardList().stream() | ||
.map(award -> new PortfolioData.Award( | ||
award.contestName(), | ||
award.awardName(), | ||
award.awardDate() | ||
)) | ||
.toList() | ||
: List.of(); | ||
|
||
List<PortfolioData.Certificate> certificateList = portfolioReq.certificateList() != null | ||
? portfolioReq.certificateList().stream() | ||
.map(certificate -> new PortfolioData.Certificate( | ||
certificate.name(), | ||
certificate.rating(), | ||
certificate.certificationDate() | ||
)) | ||
.toList() | ||
: List.of(); | ||
|
||
List<PortfolioData.Sns> snsList = portfolioReq.snsList() != null | ||
? portfolioReq.snsList().stream() | ||
.map(sns -> new PortfolioData.Sns( | ||
sns.snsLink() | ||
)) | ||
.toList() | ||
: List.of(); | ||
|
||
return new PortfolioData(educationList, workList, activityList, awardList, certificateList, snsList); | ||
} | ||
|
||
@Transactional | ||
public PortfolioRes registerPortfolio(Member member, PortfolioReq portfolioReq) { | ||
if (member == null) { | ||
throw new ApplicationException(ErrorCode.UNAUTHORIZED_EXCEPTION); | ||
} | ||
PortfolioData portfolioData = convertToPortfolioData(portfolioReq); | ||
Portfolio portfolio = Portfolio.builder() | ||
.member(member) | ||
.portfolioData(portfolioData) | ||
.build(); | ||
Portfolio savedPortfolio = portfolioRepository.save(portfolio); | ||
|
||
return PortfolioRes.from(savedPortfolio); | ||
} | ||
|
||
public PortfolioRes getPortfolio(Member member, Long portfolioId) { | ||
Portfolio portfolio = portfolioRepository.findByIdAndDeletedAtIsNull(portfolioId) | ||
.orElseThrow(() -> new ApplicationException(ErrorCode.PORTFOLIO_NOT_FOUND_EXCEPTION)); | ||
if (!portfolio.getMember().getId().equals(member.getId())) { | ||
throw new ApplicationException(ErrorCode.FORBIDDEN_EXCEPTION); | ||
} | ||
|
||
return PortfolioRes.from(portfolio); | ||
} | ||
|
||
@Transactional | ||
public PortfolioRes updatePortfolio(Member member, Long portfolioId, PortfolioReq portfolioReq) { | ||
Portfolio portfolio = portfolioRepository.findById(portfolioId) | ||
.orElseThrow(() -> new ApplicationException(ErrorCode.PORTFOLIO_NOT_FOUND_EXCEPTION)); | ||
if (!portfolio.getMember().getId().equals(member.getId())) { | ||
throw new ApplicationException(ErrorCode.FORBIDDEN_EXCEPTION); | ||
} | ||
PortfolioData updatedPortfolioData = convertToPortfolioData(portfolioReq); | ||
portfolio.update(updatedPortfolioData); | ||
Portfolio updatedPortfolio = portfolioRepository.save(portfolio); | ||
|
||
return PortfolioRes.from(updatedPortfolio); | ||
} | ||
|
||
@Transactional | ||
public void deletePortfolio(Member member, Long portfolioId) { | ||
Portfolio portfolio = portfolioRepository.findById(portfolioId) | ||
.orElseThrow(() -> new ApplicationException(ErrorCode.PORTFOLIO_NOT_FOUND_EXCEPTION)); | ||
if (portfolio.getDeletedAt() != null) { | ||
throw new ApplicationException(ErrorCode.ALREADY_DELETE_EXCEPTION); | ||
} | ||
if (!portfolio.getMember().getId().equals(member.getId())) { | ||
throw new ApplicationException(ErrorCode.FORBIDDEN_EXCEPTION); | ||
} | ||
portfolioRepository.delete(portfolio); | ||
} | ||
} |
Oops, something went wrong.