Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions src/main/java/book/book/common/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ public enum ErrorCode {
// Ranking 도메인 (R001번대)
RANKING_NOT_FOUND("R001", "랭킹 정보를 찾을 수 없습니다.", HttpStatus.NOT_FOUND),

// Onboarding 도메인 (O001번대)
ONBOARDING_NOT_FOUND("O001", "온보딩 정보를 찾을 수 없습니다.", HttpStatus.NOT_FOUND),
ONBOARDING_CATEGORY_NOT_FOUND("O002", "해당하는 카테고리를 찾을 수 없습니다.", HttpStatus.BAD_REQUEST),
ONBOARDING_KEYWORD_NOT_FOUND("O003", "해당하는 키워드를 찾을 수 없습니다.", HttpStatus.BAD_REQUEST),

;

private final String code;
Expand Down
74 changes: 74 additions & 0 deletions src/main/java/book/book/onboarding/api/OnboardingApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package book.book.onboarding.api;

import book.book.common.response.ResponseForm;
import book.book.onboarding.dto.OnboardingCategoryDto;
import book.book.onboarding.dto.OnboardingKeywordDto;
import book.book.onboarding.dto.OnboardingResultRequest;
import book.book.onboarding.dto.OnboardingResultResponse;
import book.book.onboarding.service.OnboardingService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
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.RestController;

@RestController
@RequiredArgsConstructor
@Tag(name = "onboarding", description = "온보딩 관련 API")
public class OnboardingApi {
private final OnboardingService onboardingService;

@Operation(summary = "온보딩 책 분야 목록 가져오기")
@GetMapping("/api/v2/onboarding/categories")
public ResponseForm<List<OnboardingCategoryDto>> getOnboardingCategories() {
return new ResponseForm<>(onboardingService.getOnboardingCategories());
}

@PreAuthorize("hasRole('ADMIN')")
@Operation(summary = "온보딩 책 분야 목록 추가하기")
@PostMapping("/api/v2/onboarding/categories")
public ResponseForm<Void> postOnboardingCategories(
@RequestBody List<OnboardingCategoryDto> request) {
onboardingService.postOnboardingCategories(request);
return ResponseForm.ok();
}

@Operation(summary = "온보딩 키워드 목록 가져오기")
@GetMapping("/api/v2/onboarding/categories/{categoryId}/keywords")
public ResponseForm<List<OnboardingKeywordDto>> getOnboardingKeywords(@PathVariable String categoryId) {
return new ResponseForm<>(onboardingService.getOnboardingKeywords(categoryId));
}

@PreAuthorize("hasRole('ADMIN')")
@Operation(summary = "온보딩 키워드 목록 추가하기")
@PostMapping("/api/v2/onboarding/categories/{categoryId}/keywords")
public ResponseForm<Void> postOnboardingKeywords(
@PathVariable String categoryId,
@RequestBody List<String> keywords) {
onboardingService.postOnboardingKeywords(categoryId, keywords);
return ResponseForm.ok();
}

@Operation(summary = "로그인한 멤버가 온보딩때 입력한 정보 확인하기")
@GetMapping("/api/v2/onboarding")
public ResponseForm<OnboardingResultResponse> getMemberPreferences(
@AuthenticationPrincipal Long memberId) {
return new ResponseForm<>(onboardingService.getMemberPreferences(memberId));
}

@Operation(summary = "온보딩 결과 저장하기")
@PutMapping("/api/v2/onboarding")
public ResponseForm<Void> putMemberPreferences(
@AuthenticationPrincipal Long memberId,
@RequestBody OnboardingResultRequest request) {
onboardingService.saveMemberPreferences(memberId, request);
return ResponseForm.ok();
}
}
15 changes: 15 additions & 0 deletions src/main/java/book/book/onboarding/dto/OnboardingCategoryDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package book.book.onboarding.dto;

import book.book.onboarding.entity.OnboardingCategory;

public record OnboardingCategoryDto(
String id,
String name
) {
public static OnboardingCategoryDto from(OnboardingCategory entity) {
if (entity == null) {
return null;
}
return new OnboardingCategoryDto(entity.getId(), entity.getName());
}
}
15 changes: 15 additions & 0 deletions src/main/java/book/book/onboarding/dto/OnboardingKeywordDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package book.book.onboarding.dto;

import book.book.onboarding.entity.OnboardingKeyword;

public record OnboardingKeywordDto(
Long id,
String name
) {
public static OnboardingKeywordDto from(OnboardingKeyword entity) {
if (entity == null) {
return null;
}
return new OnboardingKeywordDto(entity.getId(), entity.getName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package book.book.onboarding.dto;

import java.util.List;
import lombok.Builder;

@Builder
public record OnboardingResultRequest(
String category,
List<Long> keywords,
String favoriteAuthor,
String favoriteBook
) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package book.book.onboarding.dto;

import java.util.List;
import lombok.Builder;

@Builder
public record OnboardingResultResponse(
OnboardingCategoryDto category,
List<OnboardingKeywordDto> keywords,
String favoriteAuthor,
String favoriteBook
) {
}

55 changes: 55 additions & 0 deletions src/main/java/book/book/onboarding/entity/MemberOnboarding.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package book.book.onboarding.entity;

import book.book.common.BaseTimeEntity;
import book.book.member.entity.Member;
import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "member_onboarding")
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MemberOnboarding extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", unique = true, nullable = false)
private Member member;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id")
private OnboardingCategory category;

@OneToMany(mappedBy = "memberOnboarding", fetch = FetchType.LAZY)
@Builder.Default
private List<MemberOnboardingKeyword> memberOnboardingKeywords = new ArrayList<>();

@Column(length = 200)
private String favoriteAuthor;

@Column(length = 200)
private String favoriteBook;

public void updateCategory(OnboardingCategory category) {
this.category = category;
}

public void updateFavoriteAuthor(String favoriteAuthor) {
this.favoriteAuthor = favoriteAuthor;
}

public void updateFavoriteBook(String favoriteBook) {
this.favoriteBook = favoriteBook;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package book.book.onboarding.entity;

import book.book.common.BaseTimeEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Table(
name = "member_onboarding_keyword",
uniqueConstraints = {
@UniqueConstraint(
name = "member_onboarding_keyword_uk",
columnNames = {"member_onboarding_id", "keyword_id"}
)
}
)
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MemberOnboardingKeyword extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_onboarding_id", nullable = false)
private MemberOnboarding memberOnboarding;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "keyword_id", nullable = false)
private OnboardingKeyword keyword;
}

19 changes: 19 additions & 0 deletions src/main/java/book/book/onboarding/entity/OnboardingCategory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package book.book.onboarding.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(name = "onboarding_category")
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OnboardingCategory {

@Id
private String id;

@Column(nullable = false)
private String name;
}
32 changes: 32 additions & 0 deletions src/main/java/book/book/onboarding/entity/OnboardingKeyword.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package book.book.onboarding.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(
name = "onboarding_keyword",
uniqueConstraints = {
@UniqueConstraint(
name = "onboarding_keyword_uk",
columnNames = {"name", "category_id"}
)
}
)
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OnboardingKeyword {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false)
private String name;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id", nullable = false)
private OnboardingCategory category;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package book.book.onboarding.repository;

import book.book.onboarding.entity.MemberOnboarding;
import book.book.onboarding.entity.MemberOnboardingKeyword;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface MemberOnboardingKeywordRepository extends JpaRepository<MemberOnboardingKeyword, Long> {

List<MemberOnboardingKeyword> findAllByMemberOnboarding(MemberOnboarding member);

@Modifying(clearAutomatically = true)
@Query("DELETE FROM MemberOnboardingKeyword mok WHERE mok.memberOnboarding.id = :memberOnboardingId")
void deleteAllByMemberOnboardingId(@Param("memberOnboardingId") Long memberOnboardingId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package book.book.onboarding.repository;

import book.book.onboarding.entity.MemberOnboarding;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface MemberOnboardingRepository extends JpaRepository<MemberOnboarding, Long> {

Optional<MemberOnboarding> findByMemberId(Long memberId);

@Query("SELECT DISTINCT mo FROM MemberOnboarding mo " +
"LEFT JOIN FETCH mo.category " +
"LEFT JOIN FETCH mo.memberOnboardingKeywords mok " +
"LEFT JOIN FETCH mok.keyword " +
"WHERE mo.member.id = :memberId")
Optional<MemberOnboarding> findByMemberIdWithCategory(@Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package book.book.onboarding.repository;

import book.book.onboarding.entity.OnboardingCategory;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OnboardingCategoryRepository extends JpaRepository<OnboardingCategory, String> {

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package book.book.onboarding.repository;

import book.book.onboarding.entity.OnboardingKeyword;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OnboardingKeywordRepository extends JpaRepository<OnboardingKeyword, Long> {

List<OnboardingKeyword> findAllByCategoryId(String categoryId);
}

Loading
Loading