Skip to content

Commit 3877396

Browse files
feat: 킬링파트 좋아요 & 타인 킬링파트 목록 조회 & 개인 킬링파트 캘린더 조회
# 변경점 👍 close: #11 1. DiaryLike 추가 및 좋아요, 좋아요 취소 기능 2. 타인 킬링파트 조회용 API - 본인 좋아요 표시 여부 반영 3. 월별 KillingPart(Diary) 목록 조회 - userId, 날짜 인덱스 추가 타인 킬링파트 조회 시 scope를 고려해서 killing_part는 content를 비공개, private는 처음부터 조회하지 않도록 구성했습니다. # 비고 ✏ 월별 킬링파트 목록 조회 시 개수가 최대 30개이기도 하고 캘린더 전환 시 페이지네이션이 오히려 불편할 것 같아서 단순 리스트로 반환했습니다. 그리고 월별 목록 조회는 현재 홈에서 마이페이지에서만 사용한다고 판단해 scope를 고려하지 않았습니다. --------- Co-authored-by: jinwon1234 <[email protected]>
1 parent 9779f15 commit 3877396

21 files changed

+972
-42
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
HELP.md
22
.gradle
33
build/
4+
src/main/generated/
45
!gradle/wrapper/gradle-wrapper.jar
56
!**/src/main/**/build/
67
!**/src/test/**/build/

src/main/java/apptive/team5/diary/controller/DiaryController.java

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import apptive.team5.diary.domain.DiaryEntity;
44
import apptive.team5.diary.dto.DiaryCreateRequest;
5-
import apptive.team5.diary.dto.DiaryResponse;
6-
import apptive.team5.diary.dto.DiaryUpdateRequest;
5+
import apptive.team5.diary.dto.DiaryResponseDto;
6+
import apptive.team5.diary.dto.DiaryUpdateRequestDto;
7+
import apptive.team5.diary.dto.UserDiaryResponseDto;
78
import apptive.team5.diary.service.DiaryService;
89
import jakarta.validation.Valid;
910
import lombok.RequiredArgsConstructor;
1011
import org.springframework.data.domain.Page;
1112
import org.springframework.data.domain.PageRequest;
13+
import org.springframework.format.annotation.DateTimeFormat;
1214
import org.springframework.http.HttpStatus;
1315
import org.springframework.http.ResponseEntity;
1416
import org.springframework.security.core.annotation.AuthenticationPrincipal;
@@ -23,6 +25,8 @@
2325
import org.springframework.web.bind.annotation.RestController;
2426

2527
import java.net.URI;
28+
import java.time.LocalDate;
29+
import java.util.List;
2630

2731
@RestController
2832
@RequiredArgsConstructor
@@ -32,7 +36,7 @@ public class DiaryController {
3236
private final DiaryService diaryService;
3337

3438
@GetMapping("/my")
35-
public ResponseEntity<Page<DiaryResponse>> getMyMusicDiary(
39+
public ResponseEntity<Page<DiaryResponseDto>> getMyMusicDiary(
3640
@AuthenticationPrincipal
3741
Long userId,
3842
@RequestParam(defaultValue = "0")
@@ -41,11 +45,39 @@ public ResponseEntity<Page<DiaryResponse>> getMyMusicDiary(
4145
int size
4246
) {
4347

44-
Page<DiaryResponse> response = diaryService.getMyDiaries(userId, PageRequest.of(page, size));
48+
Page<DiaryResponseDto> response = diaryService.getMyDiaries(userId, PageRequest.of(page, size));
4549

4650
return ResponseEntity.status(HttpStatus.OK).body(response);
4751
}
4852

53+
@GetMapping("/user/{userId}")
54+
public ResponseEntity<Page<UserDiaryResponseDto>> getUserDiaries(
55+
@PathVariable
56+
Long userId,
57+
@AuthenticationPrincipal
58+
Long currentUserId,
59+
@RequestParam(defaultValue = "0")
60+
int page,
61+
@RequestParam(defaultValue = "5")
62+
int size
63+
) {
64+
Page<UserDiaryResponseDto> response = diaryService.getUserDiaries(userId, currentUserId, PageRequest.of(page, size));
65+
return ResponseEntity.status(HttpStatus.OK).body(response);
66+
}
67+
68+
@GetMapping("/my/calendar")
69+
public ResponseEntity<List<DiaryResponseDto>> getMyDiariesByPeriod(
70+
@AuthenticationPrincipal
71+
Long userId,
72+
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
73+
LocalDate start,
74+
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
75+
LocalDate end
76+
) {
77+
List<DiaryResponseDto> response = diaryService.getMyDiariesByPeriod(userId, start, end);
78+
return ResponseEntity.status(HttpStatus.OK).body(response);
79+
}
80+
4981
@PostMapping
5082
public ResponseEntity<Void> createDiary(@AuthenticationPrincipal Long userId, @Valid @RequestBody DiaryCreateRequest diaryRequest) {
5183
DiaryEntity diary = diaryService.createDiary(userId, diaryRequest);
@@ -60,7 +92,7 @@ public ResponseEntity<Void> updateDiary(
6092
@PathVariable
6193
Long diaryId,
6294
@RequestBody
63-
DiaryUpdateRequest updateRequest
95+
DiaryUpdateRequestDto updateRequest
6496
) {
6597
diaryService.updateDiary(userId, diaryId, updateRequest);
6698

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package apptive.team5.diary.controller;
2+
3+
import apptive.team5.diary.service.DiaryLikeService;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.http.HttpStatus;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
8+
import org.springframework.web.bind.annotation.DeleteMapping;
9+
import org.springframework.web.bind.annotation.PathVariable;
10+
import org.springframework.web.bind.annotation.PostMapping;
11+
import org.springframework.web.bind.annotation.RequestMapping;
12+
import org.springframework.web.bind.annotation.RestController;
13+
14+
@RestController
15+
@RequiredArgsConstructor
16+
@RequestMapping("/api/diaries/{diaryId}/like")
17+
public class DiaryLikeController {
18+
19+
private final DiaryLikeService diaryLikeService;
20+
21+
@PostMapping
22+
public ResponseEntity<Void> likeDiary(
23+
@AuthenticationPrincipal
24+
Long userId,
25+
@PathVariable
26+
Long diaryId
27+
) {
28+
diaryLikeService.likeDiary(userId, diaryId);
29+
30+
return ResponseEntity.status(HttpStatus.CREATED).build();
31+
}
32+
33+
@DeleteMapping
34+
public ResponseEntity<Void> unlikeDiary(
35+
@AuthenticationPrincipal
36+
Long userId,
37+
@PathVariable
38+
Long diaryId
39+
) {
40+
diaryLikeService.unlikeDiary(userId, diaryId);
41+
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
42+
}
43+
}

src/main/java/apptive/team5/diary/domain/DiaryEntity.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package apptive.team5.diary.domain;
22

33
import apptive.team5.global.entity.BaseTimeEntity;
4+
import apptive.team5.global.exception.ExceptionCode;
45
import apptive.team5.user.domain.UserEntity;
56
import jakarta.persistence.Column;
67
import jakarta.persistence.Entity;
@@ -11,8 +12,10 @@
1112
import jakarta.persistence.GeneratedValue;
1213
import jakarta.persistence.GenerationType;
1314
import jakarta.persistence.Id;
15+
import jakarta.persistence.Index;
1416
import jakarta.persistence.JoinColumn;
1517
import jakarta.persistence.ManyToOne;
18+
import jakarta.persistence.Table;
1619
import lombok.AccessLevel;
1720
import lombok.AllArgsConstructor;
1821
import lombok.Getter;
@@ -23,6 +26,12 @@
2326
@Getter
2427
@AllArgsConstructor
2528
@NoArgsConstructor(access = AccessLevel.PROTECTED)
29+
@Table(
30+
name = "diary_entity",
31+
indexes = {
32+
@Index(name = "idx_diary_user_created", columnList = "user_id, createDateTime")
33+
}
34+
)
2635
public class DiaryEntity extends BaseTimeEntity {
2736

2837
@Id
@@ -54,8 +63,7 @@ public class DiaryEntity extends BaseTimeEntity {
5463
@ManyToOne(fetch = FetchType.LAZY, optional = false)
5564
@JoinColumn(
5665
name = "user_id",
57-
nullable = false,
58-
foreignKey = @ForeignKey(name = "fk_diary_user_id_ref_user_id")
66+
nullable = false
5967
)
6068
private UserEntity user;
6169

@@ -87,11 +95,23 @@ public DiaryEntity(
8795
}
8896

8997
public void validateOwner(UserEntity user) {
90-
if (!this.user.equals(user)) {
91-
throw new AccessDeniedException("해당 다이어리에 대한 권한이 없습니다.");
98+
if (!isOwner(user.getId())) {
99+
throw new AccessDeniedException(ExceptionCode.ACCESS_DENIED_DIARY.getDescription());
92100
}
93101
}
94102

103+
public boolean isMyDiary(Long userId) {
104+
return isOwner(userId);
105+
}
106+
107+
private boolean isOwner(Long userId) {
108+
return this.user.getId().equals(userId);
109+
}
110+
111+
public boolean isScopeKillingPart() {
112+
return this.scope == DiaryScope.KILLING_PART;
113+
}
114+
95115
public void update(
96116
String musicTitle,
97117
String artist,
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package apptive.team5.diary.domain;
2+
3+
import apptive.team5.user.domain.UserEntity;
4+
import jakarta.persistence.Column;
5+
import jakarta.persistence.Entity;
6+
import jakarta.persistence.FetchType;
7+
import jakarta.persistence.ForeignKey;
8+
import jakarta.persistence.GeneratedValue;
9+
import jakarta.persistence.GenerationType;
10+
import jakarta.persistence.Id;
11+
import jakarta.persistence.JoinColumn;
12+
import jakarta.persistence.ManyToOne;
13+
import jakarta.persistence.Table;
14+
import jakarta.persistence.UniqueConstraint;
15+
import lombok.AccessLevel;
16+
import lombok.Getter;
17+
import lombok.NoArgsConstructor;
18+
19+
@Entity
20+
@Getter
21+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
22+
@Table(
23+
name = "diary_like",
24+
uniqueConstraints = {
25+
@UniqueConstraint(
26+
name = "uk_diary_like_user_diary",
27+
columnNames = {"user_id", "diary_id"}
28+
)
29+
}
30+
)
31+
public class DiaryLikeEntity {
32+
33+
@Id
34+
@GeneratedValue(strategy = GenerationType.IDENTITY)
35+
@Column(name = "diary_like_id")
36+
private Long id;
37+
38+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
39+
@JoinColumn(
40+
name = "user_id",
41+
nullable = false,
42+
foreignKey = @ForeignKey(name = "fk_diary_like_user_id_ref_user_id")
43+
)
44+
private UserEntity user;
45+
46+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
47+
@JoinColumn(
48+
name = "diary_id",
49+
nullable = false,
50+
foreignKey = @ForeignKey(name = "fk_diary_like_diary_id_ref_diary_id")
51+
)
52+
private DiaryEntity diary;
53+
54+
public DiaryLikeEntity(UserEntity user, DiaryEntity diary) {
55+
this.user = user;
56+
this.diary = diary;
57+
}
58+
}

src/main/java/apptive/team5/diary/dto/DiaryResponse.java renamed to src/main/java/apptive/team5/diary/dto/DiaryResponseDto.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import apptive.team5.diary.domain.DiaryScope;
66
import java.time.LocalDateTime;
77

8-
public record DiaryResponse(
8+
public record DiaryResponseDto(
99
String artist,
1010
String musicTitle,
1111
String albumImageUrl,
@@ -18,8 +18,8 @@ public record DiaryResponse(
1818
LocalDateTime createDate,
1919
LocalDateTime updateDate
2020
) {
21-
public static DiaryResponse from(DiaryEntity diary) {
22-
return new DiaryResponse(
21+
public static DiaryResponseDto from(DiaryEntity diary) {
22+
return new DiaryResponseDto(
2323
diary.getArtist(),
2424
diary.getMusicTitle(),
2525
diary.getAlbumImageUrl(),

src/main/java/apptive/team5/diary/dto/DiaryUpdateRequest.java renamed to src/main/java/apptive/team5/diary/dto/DiaryUpdateRequestDto.java

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

33
import apptive.team5.diary.domain.DiaryScope;
44

5-
public record DiaryUpdateRequest(
5+
public record DiaryUpdateRequestDto(
66
String artist,
77
String musicTitle,
88
String albumImageUrl,
@@ -13,7 +13,7 @@ public record DiaryUpdateRequest(
1313
String start,
1414
String end
1515
) {
16-
public static DiaryUpdateDto toUpdateDto(DiaryUpdateRequest updateRequest) {
16+
public static DiaryUpdateDto toUpdateDto(DiaryUpdateRequestDto updateRequest) {
1717
return new DiaryUpdateDto(
1818
updateRequest.musicTitle,
1919
updateRequest.artist,
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package apptive.team5.diary.dto;
2+
3+
import apptive.team5.diary.domain.DiaryEntity;
4+
import apptive.team5.diary.domain.DiaryScope;
5+
import apptive.team5.user.domain.UserEntity;
6+
7+
import java.time.LocalDateTime;
8+
9+
public record UserDiaryResponseDto(
10+
Long diaryId,
11+
String artist,
12+
String musicTitle,
13+
String albumImageUrl,
14+
String content,
15+
String videoUrl,
16+
DiaryScope scope,
17+
String duration,
18+
String start,
19+
String end,
20+
LocalDateTime createDate,
21+
LocalDateTime updateDate,
22+
boolean isLiked
23+
) {
24+
public static String defaultContentMsg = "비공개 일기입니다.";
25+
public static UserDiaryResponseDto from(DiaryEntity diary, boolean isLiked, Long currentUserId) {
26+
String contentResponse = diary.getContent();
27+
28+
if (!diary.isMyDiary(currentUserId) &&
29+
diary.isScopeKillingPart()) {
30+
contentResponse = defaultContentMsg;
31+
}
32+
33+
return new UserDiaryResponseDto(
34+
diary.getId(),
35+
diary.getArtist(),
36+
diary.getMusicTitle(),
37+
diary.getAlbumImageUrl(),
38+
contentResponse,
39+
diary.getVideoUrl(),
40+
diary.getScope(),
41+
diary.getDuration(),
42+
diary.getStart(),
43+
diary.getEnd(),
44+
diary.getCreateDateTime(),
45+
diary.getUpdateDateTime(),
46+
isLiked
47+
);
48+
}
49+
}

0 commit comments

Comments
 (0)