Skip to content

Commit 30df5d3

Browse files
authored
✨ feat: add user item add isliked in response dto (#515)
1 parent 40306b3 commit 30df5d3

File tree

8 files changed

+163
-6
lines changed

8 files changed

+163
-6
lines changed

backend/streetdrop-api/src/main/java/com/depromeet/domains/item/dao/ItemDao.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ public class ItemDao {
2020
private String artistName;
2121
private String albumThumbnail;
2222
private Long itemCount;
23+
private boolean isLiked;
2324
}

backend/streetdrop-api/src/main/java/com/depromeet/domains/item/dto/response/ItemGroupByDateResponseDto.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ public record ItemGroupByDateResponseDto(
1010
List<ItemGroupResponseDto> value
1111
) {
1212
}
13+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.depromeet.domains.item.dto.response;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
5+
import java.util.List;
6+
7+
public record ItemGroupByDateResponseV2Dto(
8+
@Schema(description = "날짜", example = "2주전")
9+
String date,
10+
@Schema(description = "아이템 그룹", example = "아이템 그룹")
11+
List<ItemGroupResponseV2Dto> value
12+
){}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.depromeet.domains.item.dto.response;
2+
3+
import com.depromeet.domains.music.dto.response.MusicResponseDto;
4+
import com.depromeet.domains.user.dto.response.UserResponseDto;
5+
import com.fasterxml.jackson.annotation.JsonFormat;
6+
import io.swagger.v3.oas.annotations.media.Schema;
7+
import lombok.Builder;
8+
9+
import java.time.LocalDateTime;
10+
11+
12+
@Builder
13+
public record ItemGroupResponseV2Dto(
14+
@Schema(description = "아이템 아이디", example = "1")
15+
Long itemId,
16+
17+
@Schema(description = "사용자 정보")
18+
UserResponseDto user,
19+
20+
@Schema(description = "사용자 위치", example = "성동구 성수1가 1동")
21+
ItemLocationResponseDto location,
22+
23+
@Schema(description = "음악 정보")
24+
MusicResponseDto music,
25+
26+
@Schema(description = "사용자 코멘트", example = "이 노래 좋아요")
27+
String content,
28+
29+
@Schema(description = "생성시간", example = "yyyy-MM-dd HH:mm:ss")
30+
@JsonFormat(
31+
shape = JsonFormat.Shape.STRING,
32+
pattern = "yyyy-MM-dd HH:mm:ss",
33+
locale = "Asia/Seoul"
34+
)
35+
LocalDateTime createdAt,
36+
37+
@Schema(description = "아이템 좋아요 개수", example = "1")
38+
long itemLikeCount,
39+
40+
@Schema(description = "아이템 좋아요 여부", example = "true")
41+
boolean isLiked
42+
43+
) {
44+
}

backend/streetdrop-api/src/main/java/com/depromeet/domains/item/repository/ItemRepositoryImpl.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import com.depromeet.domains.item.dao.ItemDao;
44
import com.depromeet.domains.user.dto.request.ItemOrderType;
55
import com.querydsl.core.types.Projections;
6+
import com.querydsl.core.types.dsl.CaseBuilder;
67
import com.querydsl.core.types.dsl.DateExpression;
78
import com.querydsl.core.types.dsl.DateTimePath;
89
import com.querydsl.core.types.dsl.Expressions;
10+
import com.querydsl.jpa.JPAExpressions;
911
import com.querydsl.jpa.impl.JPAQueryFactory;
1012
import lombok.RequiredArgsConstructor;
1113
import org.springframework.stereotype.Repository;
@@ -23,6 +25,7 @@
2325
import static com.depromeet.music.artist.QArtist.artist;
2426
import static com.depromeet.music.song.QSong.song;
2527
import static com.querydsl.core.types.dsl.Expressions.currentDate;
28+
import static com.querydsl.jpa.JPAExpressions.select;
2629

2730
@Repository
2831
@RequiredArgsConstructor
@@ -37,6 +40,11 @@ public List<ItemDao> findByUserId(Long userId, long lastCursor, ItemOrderType or
3740
DateExpression<Date> currentWeekExpr = currentDate();
3841
DateTimePath<LocalDateTime> createdAtExpr = item.createdAt;
3942

43+
var isLikedSubQuery = JPAExpressions.select(itemLike.id)
44+
.from(itemLike)
45+
.where(itemLike.item.id.eq(item.id)
46+
.and(itemLike.user.id.eq(userId)));
47+
4048
var query = queryFactory.select(
4149
Projections.constructor(
4250
ItemDao.class,
@@ -49,7 +57,8 @@ public List<ItemDao> findByUserId(Long userId, long lastCursor, ItemOrderType or
4957
album.name.as("albumName"),
5058
artist.name.as("artistName"),
5159
albumCover.albumThumbnail.as("albumThumbnail"),
52-
itemLike.count().as("itemCount")
60+
itemLike.count().as("itemCount"),
61+
isLikedSubQuery.exists().as("isLiked")
5362
)
5463
).from(item)
5564
.join(itemLocation).on(item.id.eq(itemLocation.item.id))
@@ -89,7 +98,8 @@ public List<ItemDao> findByUserIdAndState(Long userId, long lastCursor, ItemOrde
8998
album.name.as("albumName"),
9099
artist.name.as("artistName"),
91100
albumCover.albumThumbnail.as("albumThumbnail"),
92-
itemLike.count().as("itemCount")
101+
itemLike.count().as("itemCount"),
102+
itemLike.user.id.eq(userId).as("isLiked")
93103
)
94104
).from(item)
95105
.join(itemLocation).on(item.id.eq(itemLocation.item.id))
@@ -131,7 +141,8 @@ public List<ItemDao> findByUserIdAndCity(Long userId, long lastCursor, ItemOrder
131141
album.name.as("albumName"),
132142
artist.name.as("artistName"),
133143
albumCover.albumThumbnail.as("albumThumbnail"),
134-
itemLike.count().as("itemCount")
144+
itemLike.count().as("itemCount"),
145+
itemLike.user.id.eq(userId).as("isLiked")
135146
)
136147
).from(item)
137148
.join(itemLocation).on(item.id.eq(itemLocation.item.id))
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.depromeet.domains.user.controller;
2+
3+
import com.depromeet.common.dto.PaginationResponseDto;
4+
import com.depromeet.common.dto.ResponseDto;
5+
import com.depromeet.domains.user.dto.request.ItemOrderType;
6+
import com.depromeet.domains.user.service.UserItemService;
7+
import com.depromeet.security.annotation.ReqUser;
8+
import com.depromeet.user.User;
9+
import io.swagger.v3.oas.annotations.Operation;
10+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
11+
import io.swagger.v3.oas.annotations.tags.Tag;
12+
import lombok.RequiredArgsConstructor;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.web.bind.annotation.GetMapping;
15+
import org.springframework.web.bind.annotation.RequestMapping;
16+
import org.springframework.web.bind.annotation.RequestParam;
17+
import org.springframework.web.bind.annotation.RestController;
18+
19+
20+
@RestController
21+
@RequiredArgsConstructor
22+
@RequestMapping("/v2/users/me/items")
23+
@Tag(name = "🏃User Item", description = "User Item API")
24+
public class UserItemV2Controller {
25+
26+
private final UserItemService userItemService;
27+
28+
@Operation(summary = "사용자가 드랍한 아이템 조회 V2")
29+
@ApiResponse(responseCode = "200", description = "사용자가 드랍한 아이템 조회 성공")
30+
@GetMapping("/drop")
31+
public ResponseEntity<PaginationResponseDto<?, ?>> getUserDropItemsV2(
32+
@ReqUser User user,
33+
@RequestParam(defaultValue = "RECENT", required = false) ItemOrderType orderType,
34+
@RequestParam(value = "state", required = false) String state,
35+
@RequestParam(value = "city", required = false) String city,
36+
@RequestParam(defaultValue = "9223372036854775000") long lastCursor
37+
) {
38+
var response = userItemService.getDropItemsV2(user, lastCursor, orderType, state, city);
39+
return ResponseDto.ok(response);
40+
}
41+
42+
}

backend/streetdrop-api/src/main/java/com/depromeet/domains/user/service/UserItemService.java

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
import com.depromeet.common.dto.InfiniteScrollMetaResponseDto;
44
import com.depromeet.common.dto.PaginationResponseDto;
55
import com.depromeet.domains.item.dao.ItemDao;
6-
import com.depromeet.domains.item.dto.response.ItemGroupByDateResponseDto;
7-
import com.depromeet.domains.item.dto.response.ItemGroupResponseDto;
8-
import com.depromeet.domains.item.dto.response.ItemLocationResponseDto;
6+
import com.depromeet.domains.item.dto.response.*;
97
import com.depromeet.domains.item.repository.ItemLikeRepository;
108
import com.depromeet.domains.item.repository.ItemLocationRepository;
119
import com.depromeet.domains.item.repository.ItemRepository;
@@ -57,6 +55,31 @@ public class UserItemService {
5755
return new PaginationResponseDto<>(itemGroupByDateResponseDto, meta);
5856
}
5957

58+
59+
@Transactional(readOnly = true)
60+
public PaginationResponseDto<?, ?> getDropItemsV2(User user, long nextCursor, ItemOrderType orderType, String state, String city) {
61+
List<ItemDao> itemList = getItemList(user, nextCursor, orderType, state, city);
62+
List<ItemGroupByDateResponseV2Dto> itemGroupByDateResponseDto = itemList
63+
.stream()
64+
.map(ItemDao::getWeekAgo)
65+
.distinct()
66+
.map(value -> {
67+
List<ItemGroupResponseV2Dto> itemGroupResponseDtoList = itemList.stream()
68+
.filter(itemDao -> itemDao.getWeekAgo() == value)
69+
.map(itemDao -> itemDaotoItemGroupResponseV2Dto(user, itemDao))
70+
.toList();
71+
return new ItemGroupByDateResponseV2Dto(getWeeksAgo(value), itemGroupResponseDtoList);
72+
})
73+
.toList();
74+
75+
var meta = InfiniteScrollMetaResponseDto
76+
.builder()
77+
.totalCount(itemList.size())
78+
.nextCursor(-1).build();
79+
80+
return new PaginationResponseDto<>(itemGroupByDateResponseDto, meta);
81+
}
82+
6083
private List<ItemDao> getItemList(User user, long nextCursor, ItemOrderType orderType, String state, String city) {
6184
if (state == null) {
6285
return itemRepository.findByUserId(user.getId(), nextCursor, orderType);
@@ -99,6 +122,28 @@ private ItemGroupResponseDto itemDaotoItemGroupResponseDto(User user, ItemDao it
99122
}
100123

101124

125+
private ItemGroupResponseV2Dto itemDaotoItemGroupResponseV2Dto(User user, ItemDao itemDao) {
126+
return ItemGroupResponseV2Dto
127+
.builder()
128+
.itemId(itemDao.getItemId())
129+
.user(new UserResponseDto(user))
130+
.location(new ItemLocationResponseDto(itemDao.getLocationName()))
131+
.music(
132+
MusicResponseDto.builder()
133+
.title(itemDao.getSongName())
134+
.artist(itemDao.getArtistName())
135+
.albumImage(itemDao.getAlbumThumbnail())
136+
.genre(List.of())
137+
.build()
138+
)
139+
.content(itemDao.getContent())
140+
.createdAt(itemDao.getCreatedAt())
141+
.itemLikeCount(itemDao.getItemCount())
142+
.isLiked(itemDao.isLiked())
143+
.build();
144+
}
145+
146+
102147
@Transactional(readOnly = true)
103148
public PaginationResponseDto<?, ?> getLikedItems(User user, long nextCursor, ItemOrderType itemOrderType, String state, String city) {
104149
return itemLikeService.getLikedItemsByUser(user, nextCursor, itemOrderType, state, city);

backend/streetdrop-api/src/main/java/com/depromeet/security/config/WebSecurityConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
3232
.and().csrf().disable()
3333
.authorizeHttpRequests()
3434
.requestMatchers("/users/**").authenticated()
35+
.requestMatchers("/v2/users/**").authenticated()
3536
.requestMatchers("/items/**").authenticated()
3637
.requestMatchers("/pop-up/**").authenticated()
3738
.requestMatchers(HttpMethod.POST, "notifications/tokens").authenticated()

0 commit comments

Comments
 (0)