Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.likelion.trendithon.domain.card.controller;

import jakarta.servlet.http.HttpServletRequest;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
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;

import com.likelion.trendithon.domain.card.dto.request.CreateExperienceRequest;
import com.likelion.trendithon.domain.card.dto.request.UpdateExperienceRequest;
import com.likelion.trendithon.domain.card.service.ExperienceService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;

@RestController
@AllArgsConstructor
@RequestMapping("/api/cards")
@Tag(name = "Card", description = "Card 관리 API")
public class ExperienceController {

private ExperienceService experienceService;

@Operation(summary = "[ 토큰 O | 카드 경험 ]", description = "다른 사용자가 생성한 카드 경험 등록")
@PostMapping("/experience")
public ResponseEntity<?> createExperience(
@Parameter(description = "경험할 카드 ID") Long cardId,
@Parameter(description = "경험 내용") @RequestBody
CreateExperienceRequest createExperienceRequest,
HttpServletRequest httpServletRequest) {
return experienceService.createExperience(cardId, createExperienceRequest, httpServletRequest);
}

@Operation(summary = "[ 토큰 O | 사용자 경험 조회 ]", description = "사용자가 현재 도전 중인 경험 조회")
@GetMapping("/experience")
public ResponseEntity<?> getEnableExperience(HttpServletRequest httpServletRequest) {
return experienceService.getEnableExperience(httpServletRequest);
}

@Operation(summary = "[ 토큰 O | 사용자 경험 수정 ]", description = "사용자가 현재 도전 중인 경험 종료일 변경")
@PutMapping("/experience")
public ResponseEntity<?> updateExperience(
@Parameter(description = "경험 종료일") @RequestBody
UpdateExperienceRequest updateExperienceRequest,
HttpServletRequest httpServletRequest) {
return experienceService.updateExperience(updateExperienceRequest, httpServletRequest);
}

@Operation(summary = "[ 토큰 O | 사용자 경험 포기 ]", description = "사용자가 현재 도전 중인 경험 포기")
@PutMapping("/experience/quit")
public ResponseEntity<?> quitExperience(HttpServletRequest httpServletRequest) {
return experienceService.quitExperience(httpServletRequest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.likelion.trendithon.domain.card.dto.request;

import java.time.LocalDate;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

@Getter
public class CreateExperienceRequest {

@Schema(description = "카드 표지", example = "#000000")
private String cover;

@Schema(description = "시작 날짜", example = "2025.01.01")
private LocalDate startDate;

@Schema(description = "종료 날짜", example = "2025.01.01")
private LocalDate endDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.likelion.trendithon.domain.card.dto.request;

import java.time.LocalDate;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

@Getter
public class UpdateExperienceRequest {

@Schema(description = "종료 날짜", example = "2025.01.01")
private LocalDate endDate;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public class CardResponse {
@Schema(description = "응답 메세지", example = "카드 조회에 성공하였습니다.")
private String message;

@Schema(description = "카드")
private Card card;
@Schema(description = "조회한 카드 ID", example = "1")
private Long cardId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.likelion.trendithon.domain.card.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class CreateExperienceResponse {

@Schema(description = "카드 생성 결과", example = "true")
private boolean success;

@Schema(description = "응답 메세지", example = "카드 생성에 성공하였습니다.")
private String message;

@Schema(description = "카드 ID", example = "1")
private Long cardId;

@Schema(description = "생성된 경험 ID", example = "1")
private Long experienceId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.likelion.trendithon.domain.card.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class ExperienceResponse {

@Schema(description = "경험 조회 결과", example = "true")
private boolean success;

@Schema(description = "응답 메세지", example = "경험 조회에 성공하였습니다.")
private String message;

@Schema(description = "조회한 경험 ID", example = "1")
private Long experienceId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.likelion.trendithon.domain.card.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class UpdateExperienceResponse {

@Schema(description = "경험 수정 결과", example = "true")
private boolean success;

@Schema(description = "응답 메세지", example = "경험 수정에 성공하였습니다.")
private String message;

@Schema(description = "수정된 경험 ID", example = "1")
private Long experienceId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ public class Card {
private String cover;

@OneToMany(mappedBy = "card", cascade = CascadeType.ALL, orphanRemoval = true)
private List<UserCard> userCardList = new ArrayList<>();
private List<Experience> experienceList = new ArrayList<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.likelion.trendithon.domain.card.entity;

import java.time.LocalDate;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;

import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

import com.likelion.trendithon.domain.user.entity.User;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
public class Experience {

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "login_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "card_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private Card card;

@Column(name = "state", nullable = false)
private boolean state;

@Column(name = "cover", nullable = false)
private String cover;

@Column(name = "start_date", nullable = false)
private LocalDate startDate;

@Column(name = "end_date", nullable = false)
private LocalDate endDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.likelion.trendithon.domain.card.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

import com.likelion.trendithon.domain.card.entity.Experience;

public interface ExperienceRepository extends JpaRepository<Experience, Long> {
Optional<Experience> findByStateAndUserLoginId(boolean state, String loginId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
@Slf4j
public class CardService {

private CardRepository cardRepository;
private UserRepository userRepository;
private JwtUtil jwtUtil;
private final CardRepository cardRepository;
private final UserRepository userRepository;
private final JwtUtil jwtUtil;

// 카드 생성
@Transactional
Expand Down Expand Up @@ -79,6 +79,33 @@ public ResponseEntity<CreateCardResponse> createCard(
}
}

// 카드 한 장 조회
@Transactional
public ResponseEntity<CardResponse> getCardById(Long id) {

try {
Card card =
cardRepository
.findById(id)
.orElseThrow(() -> new IllegalArgumentException("카드를 찾을 수 없습니다."));
log.info("[GET /api/cards/{}] 특정 카드 조회 성공 - 조회한 카드 ID: {}", id, id);
return ResponseEntity.ok(
CardResponse.builder()
.success(true)
.message("카드 조회에 성공하였습니다.")
.cardId(card.getCardId())
.build());
} catch (IllegalArgumentException e) {
log.error("[GET /api/cards/{}] 특정 카드 조회 실패", id);
return ResponseEntity.ok(
CardResponse.builder().success(false).message(e.getMessage()).build());
} catch (Exception e) {
log.error("[GET /api/cards/{}] 특정 카드 조회 실패 - 에러: {}", id, e.getMessage());
return ResponseEntity.ok(
CardResponse.builder().success(false).message("카드 조회 중 오류가 발생하였습니다.").build());
}
}

// 랜덤 카드 세 장 조회
@Transactional
public ResponseEntity<RandomCardResponse> getRandomCards() {
Expand Down Expand Up @@ -115,31 +142,7 @@ public ResponseEntity<RandomCardResponse> getRandomCards() {
.build());
}
}

// 카드 한 장 조회
@Transactional
public ResponseEntity<CardResponse> getCardById(Long id) {

try {
Card card =
cardRepository
.findById(id)
.orElseThrow(() -> new IllegalArgumentException("카드를 찾을 수 없습니다."));
log.info("[GET /api/cards/{}] 특정 카드 조회 성공 - 조회한 카드 ID: {}", id, id);
return ResponseEntity.ok(
CardResponse.builder().success(true).message("카드 조회에 성공하였습니다.").card(card).build());
} catch (IllegalArgumentException e) {
log.error("[GET /api/cards/{}] 특정 카드 조회 실패", id);
return ResponseEntity.ok(
CardResponse.builder().success(false).message(e.getMessage()).build());
} catch (Exception e) {
log.error("[GET /api/cards/{}] 특정 카드 조회 실패 - 에러: {}", id, e.getMessage());
return ResponseEntity.ok(
CardResponse.builder().success(false).message("카드 조회 중 오류가 발생하였습니다.").build());
}
}

// 모든 카드 조회

@Transactional
public ResponseEntity<CardListResponse> getAllCards() {
try {
Expand Down
Loading
Loading