Skip to content
Closed
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
2 changes: 1 addition & 1 deletion BackEnd_Config
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ dependencies {
implementation group:'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
implementation group:'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
implementation group:'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

// S3
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
}

tasks.named('compileJava') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public ResponseEntity<?> getAllCard() {
return cardService.getAllCards();
}

@Operation(summary = "[ 토큰 O | 카드 삭제 ]", description = "ID를 통해 특정 카드 삭제")
@Operation(summary = "[ 토큰 X | 카드 삭제 | 테스트용 ]", description = "ID를 통해 특정 카드 삭제")
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteCard(@PathVariable Long id) {
return cardService.deleteCard(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,38 @@

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

private ExperienceService experienceService;

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

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

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

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

import java.util.List;

import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.likelion.trendithon.domain.card.dto.request.CreateReviewRequest;
import com.likelion.trendithon.domain.card.service.ReviewService;

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

@RestController
@AllArgsConstructor
@RequestMapping("/api/reviews")
@Tag(name = "Review", description = "Review 관리 API")
public class ReviewController {

private final ReviewService reviewService;

@Operation(summary = "[ 토큰 O | 경험 리뷰 등록 ]", description = "경험을 완료한 카드 리뷰 등록")
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> createReview(
@Parameter(
description = "리뷰 내용",
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE))
@RequestPart
CreateReviewRequest createReviewRequest,
@Parameter(
description = "리뷰 이미지 리스트",
content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE))
@RequestPart(value = "images")
List<MultipartFile> images) {
return reviewService.createReview(createReviewRequest, images);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@
@Getter
public class CreateExperienceRequest {

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

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

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

@Schema(description = "종료 날짜", example = "2025.01.01")
@Schema(description = "종료 날짜", example = "2025-01-01")
private LocalDate endDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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 CreateReviewRequest {

@Schema(description = "리뷰할 경험 ID", example = "1")
private Long experienceId;

@Schema(description = "경험 점수", example = "3.5")
private Double score;

@Schema(description = "실제 종료 날짜", example = "2025-01-01")
private LocalDate endDate;

@Schema(description = "느낀 점", example = "좋았다.")
private String content;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.likelion.trendithon.domain.card.dto.response;

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

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -16,6 +14,15 @@ public class CardResponse {
@Schema(description = "응답 메세지", example = "카드 조회에 성공하였습니다.")
private String message;

@Schema(description = "조회한 카드 ID", example = "1")
private Long cardId;
@Schema(description = "조회한 카드 이모지", example = "모바일 키보드 이모지")
private String emoji;

@Schema(description = "조회한 카드 제목", example = "멋쟁이사자 되기")
private String title;

@Schema(description = "조회한 카드 내용", example = "나는 오늘 멋쟁이 사자가 되었다.")
private String content;

@Schema(description = "조회한 카드 표지", example = "#000000")
private String cover;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class CreateExperienceResponse {
@Schema(description = "카드 생성 결과", example = "true")
private boolean success;

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

@Schema(description = "카드 ID", example = "1")
Expand Down
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 CreateReviewResponse {

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

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

@Schema(description = "생성된 리뷰 ID", example = "1")
private Long reviewId;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.likelion.trendithon.domain.card.dto.response;

import java.time.LocalDate;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -14,6 +16,18 @@ public class ExperienceResponse {
@Schema(description = "응답 메세지", example = "경험 조회에 성공하였습니다.")
private String message;

@Schema(description = "조회한 경험 ID", example = "1")
private Long experienceId;
@Schema(description = "경험 제목", example = "멋쟁이사자 되기")
private String title;

@Schema(description = "경험 상태", example = "true")
private boolean state;

@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
Expand Up @@ -44,6 +44,9 @@ public class Experience {
@OnDelete(action = OnDeleteAction.CASCADE)
private Card card;

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

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.likelion.trendithon.domain.card.entity;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import jakarta.persistence.CascadeType;
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.OneToMany;
import jakarta.persistence.OneToOne;

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

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

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

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "experience_id", nullable = false)
private Experience experience;

@Column(name = "score", nullable = false)
private Double score;

@Column(name = "end_date", nullable = false)
private LocalDate endDate;

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

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

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 lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

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

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "review_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private Review review;

@Column(name = "image_url", nullable = false)
private String imageUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.likelion.trendithon.domain.card.repository;

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

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

public interface ReviewImageRepository extends JpaRepository<ReviewImage, Long> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.likelion.trendithon.domain.card.repository;

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

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

public interface ReviewRepository extends JpaRepository<Review, Long> {}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ public ResponseEntity<CardResponse> getCardById(Long id) {
CardResponse.builder()
.success(true)
.message("카드 조회에 성공하였습니다.")
.cardId(card.getCardId())
.emoji(card.getEmoji())
.title(card.getTitle())
.content(card.getContent())
.cover(card.getCover())
.build());
} catch (IllegalArgumentException e) {
log.error("[GET /api/cards/{}] 특정 카드 조회 실패", id);
Expand Down Expand Up @@ -142,7 +145,7 @@ public ResponseEntity<RandomCardResponse> getRandomCards() {
.build());
}
}

@Transactional
public ResponseEntity<CardListResponse> getAllCards() {
try {
Expand Down Expand Up @@ -171,6 +174,7 @@ public ResponseEntity<DeleteCardResponse> deleteCard(Long id) {
cardRepository
.findById(id)
.orElseThrow(() -> new IllegalArgumentException("카드를 찾을 수 없습니다."));
cardRepository.delete(card);
log.info("[DELETE /api/cards/{}] 특정 카드 삭제 성공 - 삭제한 카드 ID: {}", id, id);
return ResponseEntity.ok(
DeleteCardResponse.builder().success(true).message("카드 삭제에 성공하였습니다.").cardId(id).build());
Expand Down
Loading
Loading