Skip to content

Commit e1c1a8f

Browse files
committed
2 parents 118a23a + 085d1f7 commit e1c1a8f

File tree

34 files changed

+1027
-112
lines changed

34 files changed

+1027
-112
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ dependencies {
5050

5151
// AWS S3
5252
implementation("io.awspring.cloud:spring-cloud-aws-starter-s3:3.4.0")
53+
implementation("com.amazonaws:aws-java-sdk-s3:1.12.777")
5354

5455
runtimeOnly("com.h2database:h2")
5556
runtimeOnly("com.mysql:mysql-connector-j")

src/main/java/com/back/domain/cocktail/comment/dto/CocktailCommentResponseDto.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
public record CocktailCommentResponseDto(
99
Long commentId,
10-
Long postId,
10+
Long cocktailId,
1111
String userNickName,
1212
LocalDateTime createdAt,
1313
LocalDateTime updatedAt,

src/main/java/com/back/domain/cocktail/comment/entity/CocktailComment.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
import java.time.LocalDateTime;
1616

1717
@Entity
18+
@Table(
19+
name = "cocktail_comment",
20+
uniqueConstraints = @UniqueConstraint(columnNames = {"cocktail_id", "user_id"}) // 사용자 1개 댓글 제한
21+
)
1822
@Getter
1923
@EntityListeners(AuditingEntityListener.class)
2024
@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED)

src/main/java/com/back/domain/cocktail/comment/repository/CocktailCommentRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ public interface CocktailCommentRepository extends JpaRepository<CocktailComment
1212
List<CocktailComment> findTop10ByCocktailIdOrderByIdDesc(Long cocktailId);
1313

1414
List<CocktailComment> findTop10ByCocktailIdAndIdLessThanOrderByIdDesc(Long cocktailId, Long lastId);
15+
16+
boolean existsByCocktailIdAndUserId(Long cocktailId, Long id);
1517
}

src/main/java/com/back/domain/cocktail/comment/service/CocktailCommentService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ public CocktailCommentResponseDto createCocktailComment(Long cocktailId, Cocktai
3131
Cocktail cocktail = cocktailRepository.findById(cocktailId)
3232
.orElseThrow(() -> new IllegalArgumentException("칵테일이 존재하지 않습니다. id=" + cocktailId));
3333

34+
// 사용자당 댓글 1개 제한 체크
35+
boolean exists = cocktailCommentRepository.existsByCocktailIdAndUserId(cocktailId, user.getId());
36+
if (exists) {
37+
throw new IllegalArgumentException("이미 댓글을 작성하셨습니다.");
38+
}
39+
3440
CocktailComment cocktailComment = CocktailComment.builder()
3541
.cocktail(cocktail)
3642
.user(user)

src/main/java/com/back/domain/cocktail/controller/CocktailController.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ public RsData<List<CocktailSearchResponseDto>> searchAndFilter(
5656
// 서비스 호출
5757
List<CocktailSearchResponseDto> searchResults = cocktailService.searchAndFilter(cocktailSearchRequestDto);
5858

59-
// RsData로 통일된 응답 반환
6059
return RsData.successOf(searchResults);
6160
}
6261
}

src/main/java/com/back/domain/cocktail/controller/CocktailShareController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public ResponseEntity<RsData<Map<String, String>>> getShareLink(@PathVariable Lo
2424
.map(cocktail -> {
2525
Map<String, String> response = Map.of(
2626
// 공유 URL
27-
"url", "https://www.ssoul.o-r.kr/cocktails/" + cocktail.getId(),
27+
"url", "https://www.ssoul.life/cocktails/" + cocktail.getId(),
2828
// 공유 제목
2929
"title", cocktail.getCocktailName(),
3030
// 공유 이미지 (선택)

src/main/java/com/back/domain/mybar/controller/MyBarController.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
import com.back.domain.mybar.dto.MyBarListResponseDto;
44
import com.back.domain.mybar.service.MyBarService;
5-
import com.back.global.exception.ServiceException;
65
import com.back.global.rsData.RsData;
76
import com.back.global.security.SecurityUser;
87
import io.swagger.v3.oas.annotations.Operation;
98
import jakarta.validation.constraints.Max;
109
import jakarta.validation.constraints.Min;
1110
import lombok.RequiredArgsConstructor;
1211
import org.springframework.format.annotation.DateTimeFormat;
12+
import org.springframework.security.access.prepost.PreAuthorize;
1313
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1414
import org.springframework.validation.annotation.Validated;
1515
import org.springframework.web.bind.annotation.*;
@@ -20,6 +20,7 @@
2020
@RequestMapping("/me/bar")
2121
@RequiredArgsConstructor
2222
@Validated
23+
@PreAuthorize("isAuthenticated()")
2324
public class MyBarController {
2425

2526
/**
@@ -40,14 +41,13 @@ public class MyBarController {
4041
@GetMapping
4142
@Operation(summary = "내 바 목록", description = "내가 킵한 칵테일 목록 조회. 무한 스크롤 커서 지원")
4243
public RsData<MyBarListResponseDto> getMyBarList(
43-
@AuthenticationPrincipal(errorOnInvalidType = false) SecurityUser principal,
44+
@AuthenticationPrincipal SecurityUser principal,
4445
@RequestParam(required = false)
4546
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastKeptAt,
4647
@RequestParam(required = false) Long lastId,
4748
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit
4849
) {
49-
Long userId = principal != null ? principal.getId() : null;
50-
if (userId == null) throw new ServiceException(401, "로그인이 필요합니다.");
50+
Long userId = principal.getId();
5151
MyBarListResponseDto body = myBarService.getMyBar(userId, lastKeptAt, lastId, limit);
5252
return RsData.successOf(body);
5353
}
@@ -61,11 +61,10 @@ public RsData<MyBarListResponseDto> getMyBarList(
6161
@PostMapping("/{cocktailId}/keep")
6262
@Operation(summary = "킵 추가/복원", description = "해당 칵테일을 내 바에 킵합니다. 이미 삭제 상태면 복원")
6363
public RsData<Void> keep(
64-
@AuthenticationPrincipal(errorOnInvalidType = false) SecurityUser principal,
64+
@AuthenticationPrincipal SecurityUser principal,
6565
@PathVariable Long cocktailId
6666
) {
67-
Long userId = principal != null ? principal.getId() : null;
68-
if (userId == null) throw new ServiceException(401, "로그인이 필요합니다.");
67+
Long userId = principal.getId();
6968
myBarService.keep(userId, cocktailId);
7069
return RsData.of(201, "kept"); // Aspect가 HTTP 201로 설정
7170
}
@@ -79,11 +78,10 @@ public RsData<Void> keep(
7978
@DeleteMapping("/{cocktailId}/keep")
8079
@Operation(summary = "킵 해제", description = "내 바에서 해당 칵테일을 삭제(소프트 삭제, 멱등)")
8180
public RsData<Void> unkeep(
82-
@AuthenticationPrincipal(errorOnInvalidType = false) SecurityUser principal,
81+
@AuthenticationPrincipal SecurityUser principal,
8382
@PathVariable Long cocktailId
8483
) {
85-
Long userId = principal != null ? principal.getId() : null;
86-
if (userId == null) throw new ServiceException(401, "로그인이 필요합니다.");
84+
Long userId = principal.getId();
8785
myBarService.unkeep(userId, cocktailId);
8886
return RsData.of(200, "deleted");
8987
}

src/main/java/com/back/domain/myhistory/controller/MyHistoryController.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
import com.back.domain.myhistory.dto.MyHistoryLikedPostListDto;
77
import com.back.domain.myhistory.service.MyHistoryService;
88
import com.back.global.rsData.RsData;
9+
import com.back.global.security.SecurityUser;
910
import io.swagger.v3.oas.annotations.Operation;
1011
import jakarta.validation.constraints.Max;
1112
import jakarta.validation.constraints.Min;
1213
import lombok.RequiredArgsConstructor;
1314
import org.springframework.format.annotation.DateTimeFormat;
15+
import org.springframework.security.access.prepost.PreAuthorize;
1416
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1517
import org.springframework.validation.annotation.Validated;
1618
import org.springframework.web.bind.annotation.*;
@@ -21,6 +23,7 @@
2123
@RequestMapping("/me")
2224
@RequiredArgsConstructor
2325
@Validated
26+
@PreAuthorize("isAuthenticated()")
2427
public class MyHistoryController {
2528

2629
private final MyHistoryService myHistoryService;
@@ -36,11 +39,12 @@ public class MyHistoryController {
3639
@GetMapping("/posts")
3740
@Operation(summary = "내 게시글 목록", description = "내가 작성한 게시글 최신순 목록. 무한스크롤 파라미터 지원")
3841
public RsData<MyHistoryPostListDto> getMyPosts(
39-
@AuthenticationPrincipal(expression = "id") Long userId,
42+
@AuthenticationPrincipal SecurityUser principal,
4043
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastCreatedAt,
4144
@RequestParam(required = false) Long lastId,
4245
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit
4346
) {
47+
Long userId = principal.getId();
4448
MyHistoryPostListDto body = myHistoryService.getMyPosts(userId, lastCreatedAt, lastId, limit);
4549
return RsData.successOf(body);
4650
}
@@ -54,9 +58,10 @@ public RsData<MyHistoryPostListDto> getMyPosts(
5458
@GetMapping("/posts/{id}")
5559
@Operation(summary = "내 게시글로 이동", description = "내가 작성한 게시글 상세 링크 정보 반환")
5660
public RsData<com.back.domain.myhistory.dto.MyHistoryPostGoResponseDto> goFromPost(
57-
@AuthenticationPrincipal(expression = "id") Long userId,
61+
@AuthenticationPrincipal SecurityUser principal,
5862
@PathVariable("id") Long postId
5963
) {
64+
Long userId = principal.getId();
6065
var body = myHistoryService.getPostLinkFromMyPost(userId, postId);
6166
return RsData.successOf(body);
6267
}
@@ -72,11 +77,12 @@ public RsData<com.back.domain.myhistory.dto.MyHistoryPostGoResponseDto> goFromPo
7277
@GetMapping("/comments")
7378
@Operation(summary = "내 댓글 목록", description = "내가 작성한 댓글 최신순 목록. 무한스크롤 파라미터 지원")
7479
public RsData<MyHistoryCommentListDto> getMyComments(
75-
@AuthenticationPrincipal(expression = "id") Long userId,
80+
@AuthenticationPrincipal SecurityUser principal,
7681
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastCreatedAt,
7782
@RequestParam(required = false) Long lastId,
7883
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit
7984
) {
85+
Long userId = principal.getId();
8086
MyHistoryCommentListDto body = myHistoryService.getMyComments(userId, lastCreatedAt, lastId, limit);
8187
return RsData.successOf(body);
8288
}
@@ -92,11 +98,12 @@ public RsData<MyHistoryCommentListDto> getMyComments(
9298
@GetMapping("/likes")
9399
@Operation(summary = "좋아요한 게시글 목록", description = "좋아요한 게시글 최신순 목록. 무한스크롤 파라미터 지원")
94100
public RsData<MyHistoryLikedPostListDto> getMyLikedPosts(
95-
@AuthenticationPrincipal(expression = "id") Long userId,
101+
@AuthenticationPrincipal SecurityUser principal,
96102
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastCreatedAt,
97103
@RequestParam(required = false) Long lastId,
98104
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit
99105
) {
106+
Long userId = principal.getId();
100107
MyHistoryLikedPostListDto body = myHistoryService.getMyLikedPosts(userId, lastCreatedAt, lastId, limit);
101108
return RsData.successOf(body);
102109
}
@@ -110,9 +117,10 @@ public RsData<MyHistoryLikedPostListDto> getMyLikedPosts(
110117
@GetMapping("/comments/{id}")
111118
@Operation(summary = "댓글에서 게시글 이동", description = "내 댓글이 달린 게시글 상세 링크 정보 반환")
112119
public RsData<MyHistoryCommentGoResponseDto> goFromComment(
113-
@AuthenticationPrincipal(expression = "id") Long userId,
120+
@AuthenticationPrincipal SecurityUser principal,
114121
@PathVariable("id") Long commentId
115122
) {
123+
Long userId = principal.getId();
116124
var body = myHistoryService.getPostLinkFromMyComment(userId, commentId);
117125
return RsData.successOf(body);
118126
}
@@ -126,9 +134,10 @@ public RsData<MyHistoryCommentGoResponseDto> goFromComment(
126134
@GetMapping("/likes/{id}")
127135
@Operation(summary = "좋아요 목록에서 이동", description = "좋아요한 게시글 상세 링크 정보 반환")
128136
public RsData<com.back.domain.myhistory.dto.MyHistoryPostGoResponseDto> goFromLikedPost(
129-
@AuthenticationPrincipal(expression = "id") Long userId,
137+
@AuthenticationPrincipal SecurityUser principal,
130138
@PathVariable("id") Long postId
131139
) {
140+
Long userId = principal.getId();
132141
var body = myHistoryService.getPostLinkFromMyLikedPost(userId, postId);
133142
return RsData.successOf(body);
134143
}

src/main/java/com/back/domain/myhistory/dto/MyHistoryLikedPostItemDto.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.back.domain.myhistory.dto;
22

33
import com.back.domain.post.post.entity.Post;
4+
import com.back.domain.post.post.entity.PostImage;
45
import com.back.domain.post.post.entity.PostLike;
56
import java.time.LocalDateTime;
7+
import java.util.List;
68
import lombok.Builder;
79
import lombok.Getter;
810

@@ -11,7 +13,7 @@
1113
public class MyHistoryLikedPostItemDto {
1214
private Long id;
1315
private String title;
14-
private String imageUrl;
16+
private List<String> imageUrls;
1517
private LocalDateTime likedAt;
1618
private Integer likeCount;
1719
private Integer commentCount;
@@ -21,7 +23,9 @@ public static MyHistoryLikedPostItemDto from(PostLike pl) {
2123
return MyHistoryLikedPostItemDto.builder()
2224
.id(p.getId())
2325
.title(p.getTitle())
24-
.imageUrl(p.getImageUrl())
26+
.imageUrls(p.getImages().stream()
27+
.map(PostImage::getUrl)
28+
.toList())
2529
.likedAt(pl.getCreatedAt())
2630
.likeCount(p.getLikeCount())
2731
.commentCount(p.getCommentCount())

0 commit comments

Comments
 (0)