Skip to content

Commit 1126bc6

Browse files
authored
Merge pull request #169 from Central-MakeUs/dev
[fix] ν™ˆ 및 μ†Œμ‹ νŽ˜μ΄μ§€ μˆ˜μ •μ‚¬ν•­ 반영
2 parents 882dccd + 2b8ce36 commit 1126bc6

File tree

15 files changed

+318
-121
lines changed

15 files changed

+318
-121
lines changed

β€Žsrc/main/java/com/example/ForDay/domain/activity/controller/ActivityController.javaβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.example.ForDay.domain.activity.controller;
22

33
import com.example.ForDay.domain.activity.dto.request.UpdateActivityReqDto;
4+
import com.example.ForDay.domain.activity.dto.response.GetAiRecommendItemsResDto;
45
import com.example.ForDay.domain.activity.service.ActivityService;
56
import com.example.ForDay.global.common.response.dto.MessageResDto;
67
import com.example.ForDay.global.oauth.CustomUserDetails;
@@ -29,4 +30,9 @@ public MessageResDto deleteActivity(@PathVariable(name = "activityId") Long acti
2930
@AuthenticationPrincipal CustomUserDetails user) {
3031
return activityService.deleteActivity(activityId, user);
3132
}
33+
34+
@GetMapping("/ai-recommend/items")
35+
public GetAiRecommendItemsResDto getAiRecommendItems(@AuthenticationPrincipal CustomUserDetails user) {
36+
return activityService.getAiRecommendItems(user);
37+
}
3238
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.example.ForDay.domain.activity.dto.response;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import lombok.NoArgsConstructor;
6+
7+
import java.util.List;
8+
9+
@Data
10+
@AllArgsConstructor
11+
@NoArgsConstructor
12+
public class GetAiRecommendItemsResDto {
13+
private MessageDto message;
14+
private List<ItemDto> activityItems;
15+
16+
@Data
17+
@AllArgsConstructor
18+
@NoArgsConstructor
19+
public static class MessageDto {
20+
private String message;
21+
}
22+
23+
@Data
24+
@AllArgsConstructor
25+
@NoArgsConstructor
26+
public static class ItemDto {
27+
private Long itemId;
28+
private Long hobbyId;
29+
private String hobbyName;
30+
private String content;
31+
private String description;
32+
}
33+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.example.ForDay.domain.activity.entity;
2+
3+
import com.example.ForDay.domain.hobby.entity.Hobby;
4+
import com.example.ForDay.global.common.mapped.BaseTimeEntity;
5+
import jakarta.persistence.*;
6+
import lombok.*;
7+
8+
@Entity
9+
@Table(name = "activity_recommend_items")
10+
@Getter
11+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
12+
@AllArgsConstructor
13+
@Builder
14+
public class ActivityRecommendItem extends BaseTimeEntity {
15+
@Id
16+
@GeneratedValue(strategy = GenerationType.IDENTITY)
17+
@Column(name = "activity_recommend_item_id")
18+
private Long id;
19+
20+
@ManyToOne(fetch = FetchType.LAZY)
21+
@JoinColumn(name = "user_hobby_id", nullable = false)
22+
private Hobby hobby;
23+
24+
private String content;
25+
private String description;
26+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.example.ForDay.domain.activity.repository;
2+
3+
import com.example.ForDay.domain.activity.entity.ActivityRecommendItem;
4+
import com.example.ForDay.domain.hobby.entity.Hobby;
5+
import org.springframework.data.jpa.repository.JpaRepository;
6+
import org.springframework.data.jpa.repository.Modifying;
7+
import org.springframework.data.jpa.repository.Query;
8+
import org.springframework.data.repository.query.Param;
9+
10+
import java.time.LocalDateTime;
11+
import java.util.List;
12+
13+
public interface ActivityRecommendItemRepository extends JpaRepository<ActivityRecommendItem, Long> {
14+
@Query("SELECT a FROM ActivityRecommendItem a " +
15+
"JOIN FETCH a.hobby " +
16+
"WHERE a.hobby IN :hobbies " +
17+
"AND a.createdAt >= :start AND a.createdAt <= :end")
18+
List<ActivityRecommendItem> findAllByHobbiesAndDate(
19+
@Param("hobbies") List<Hobby> hobbies,
20+
@Param("start") LocalDateTime start,
21+
@Param("end") LocalDateTime end
22+
);
23+
24+
@Modifying
25+
@Query("DELETE FROM ActivityRecommendItem a WHERE a.createdAt < :targetDate")
26+
void deleteOldItems(@Param("targetDate") LocalDateTime targetDate);
27+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.example.ForDay.domain.activity.service;
2+
3+
import com.example.ForDay.domain.activity.repository.ActivityRecommendItemRepository;
4+
import lombok.RequiredArgsConstructor;
5+
import lombok.extern.slf4j.Slf4j;
6+
import org.springframework.scheduling.annotation.Scheduled;
7+
import org.springframework.stereotype.Component;
8+
import org.springframework.transaction.annotation.Transactional;
9+
10+
import java.time.LocalDateTime;
11+
12+
@Component
13+
@RequiredArgsConstructor
14+
@Slf4j
15+
public class ActivityItemScheduler {
16+
17+
private final ActivityRecommendItemRepository activityRecommendItemRepository;
18+
19+
/**
20+
* 맀일 μƒˆλ²½ 3μ‹œμ— μ‹€ν–‰ (cron: 초 λΆ„ μ‹œ 일 μ›” μš”μΌ)
21+
* 였늘 κΈ°μ€€μœΌλ‘œ 이틀(48μ‹œκ°„) μ „ μƒμ„±λœ μ•„μ΄ν…œ μ‚­μ œ
22+
*/
23+
@Scheduled(cron = "0 0 3 * * *")
24+
@Transactional
25+
public void deleteOldRecommendItems() {
26+
// κΈ°μ€€ μ‹œκ°„ 계산: ν˜„μž¬ μ‹œκ°„ - 2일
27+
LocalDateTime targetDate = LocalDateTime.now().minusDays(2);
28+
29+
log.info("[Scheduler] μΆ”μ²œ μ•„μ΄ν…œ μ‚­μ œ μ‹œμž‘ (κΈ°μ€€ μ‹œκ°„: {})", targetDate);
30+
31+
try {
32+
activityRecommendItemRepository.deleteOldItems(targetDate);
33+
log.info("[Scheduler] μΆ”μ²œ μ•„μ΄ν…œ μ‚­μ œ μ™„λ£Œ");
34+
} catch (Exception e) {
35+
log.error("[Scheduler] μ‚­μ œ 쀑 였λ₯˜ λ°œμƒ: {}", e.getMessage());
36+
}
37+
}
38+
}

β€Žsrc/main/java/com/example/ForDay/domain/activity/service/ActivityService.javaβ€Ž

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
import com.example.ForDay.domain.activity.dto.FastAPIHobbyCardReqDto;
55
import com.example.ForDay.domain.activity.dto.request.UpdateActivityReqDto;
66
import com.example.ForDay.domain.activity.dto.response.FastAPIHobbyCardResDto;
7+
import com.example.ForDay.domain.activity.dto.response.GetAiRecommendItemsResDto;
78
import com.example.ForDay.domain.activity.entity.Activity;
9+
import com.example.ForDay.domain.activity.entity.ActivityRecommendItem;
10+
import com.example.ForDay.domain.activity.repository.ActivityRecommendItemRepository;
811
import com.example.ForDay.domain.friend.repository.FriendRelationRepository;
912
import com.example.ForDay.domain.friend.type.FriendRelationStatus;
1013
import com.example.ForDay.domain.hobby.dto.request.FastAPIRecommendReqDto;
@@ -36,6 +39,11 @@
3639
import org.springframework.util.StringUtils;
3740
import org.springframework.web.client.RestTemplate;
3841

42+
import java.time.LocalDate;
43+
import java.time.LocalDateTime;
44+
import java.time.LocalTime;
45+
import java.util.Collections;
46+
import java.util.List;
3947
import java.util.Objects;
4048

4149
@Slf4j
@@ -52,6 +60,7 @@ public class ActivityService {
5260
private final HobbyRepository hobbyRepository;
5361
private final FriendRelationRepository friendRelationRepository;
5462
private final RestTemplate restTemplate;
63+
private final ActivityRecommendItemRepository recommendItemRepository;
5564

5665
@Value("${fastapi.url}")
5766
private String fastApiBaseUrl;
@@ -353,6 +362,46 @@ public CollectActivityResDto collectActivity(Long hobbyId, Long activityId, Cust
353362
return new CollectActivityResDto(hobby.getId(), hobby.getHobbyName(), build.getId(), build.getContent(), "ν™œλ™μ΄ μ •μƒμ μœΌλ‘œ λ‹΄κ²ΌμŠ΅λ‹ˆλ‹€.");
354363
}
355364

365+
@Transactional(readOnly = true)
366+
public GetAiRecommendItemsResDto getAiRecommendItems(CustomUserDetails user) {
367+
User currentUser = userUtil.getCurrentUser(user);
368+
String currentUserId = currentUser.getId();
369+
370+
// λ©”μ„Έμ§€ 쑰회 -> λ…Όμ˜ ν•œ ν›„ μˆ˜μ • μ˜ˆμ •
371+
372+
// 1. ν˜„μž¬ μœ μ €μ˜ ν˜„μž¬ μ§„ν–‰ 쀑인 μ·¨λ―Έ 쑰회
373+
List<Hobby> progressHobbies = hobbyRepository.findAllByUserIdAndStatusOrderByIdDesc(
374+
currentUserId,
375+
HobbyStatus.IN_PROGRESS
376+
);
377+
378+
if (progressHobbies.isEmpty()) {
379+
return new GetAiRecommendItemsResDto(new GetAiRecommendItemsResDto.MessageDto(), Collections.emptyList());
380+
}
381+
382+
// 2. 였늘 λ‚ μ§œ λ²”μœ„ μ„€μ •
383+
LocalDateTime startOfToday = LocalDate.now().atStartOfDay();
384+
LocalDateTime endOfToday = LocalDate.now().atTime(LocalTime.MAX);
385+
386+
// 3. 였늘 μƒμ„±λœ μΆ”μ²œ μ•„μ΄ν…œ 쑰회
387+
List<ActivityRecommendItem> items = recommendItemRepository.findAllByHobbiesAndDate(
388+
progressHobbies, startOfToday, endOfToday
389+
);
390+
391+
// 4. DTO λ³€ν™˜
392+
List<GetAiRecommendItemsResDto.ItemDto> itemDtos = items.stream()
393+
.map(item -> new GetAiRecommendItemsResDto.ItemDto(
394+
item.getId(),
395+
item.getHobby().getId(),
396+
item.getHobby().getHobbyName(),
397+
item.getContent(),
398+
item.getDescription()
399+
))
400+
.toList();
401+
402+
return new GetAiRecommendItemsResDto(new GetAiRecommendItemsResDto.MessageDto(), itemDtos);
403+
}
404+
356405
// μœ ν‹Έ 클래슀
357406
private Activity getActivityByUserId(Long activityId, String userId) {
358407
return activityRepository.findByIdAndUserId(activityId, userId).orElseThrow(() -> new CustomException(ErrorCode.ACTIVITY_NOT_FOUND));

β€Žsrc/main/java/com/example/ForDay/domain/auth/service/AuthService.javaβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public GuestLoginResDto guestLogin(GuestLoginReqDto reqDto) {
119119
String guestUserId = reqDto.getGuestUserId();
120120
boolean newUser;
121121

122-
if(reqDto.getGuestUserId().startsWith("withdrawn")) {
122+
if(guestUserId != null && StringUtils.hasText(guestUserId) && guestUserId.startsWith("withdrawn")) {
123123
throw new CustomException(ErrorCode.USER_NOT_FOUND);
124124
}
125125

β€Žsrc/main/java/com/example/ForDay/domain/hobby/controller/HobbyController.javaβ€Ž

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,6 @@ public CollectActivityResDto collectActivity(@PathVariable(name = "hobbyId") Lon
168168
return activityService.collectActivity(hobbyId, activityId, user);
169169
}
170170

171-
@Override
172-
@GetMapping("/stories/tabs")
173-
public GetHobbyStoryTabsResDto getHobbyStoryTabs(@AuthenticationPrincipal CustomUserDetails user) {
174-
return hobbyService.getHobbyStoryTabs(user);
175-
}
176-
177171
@Override
178172
@GetMapping("/check")
179173
public CanCreateHobbyResDto canCreateHobby(@RequestParam(value = "name") String name,

β€Žsrc/main/java/com/example/ForDay/domain/hobby/controller/HobbyControllerDocs.javaβ€Ž

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,26 +1222,6 @@ CollectActivityResDto collectActivity(
12221222

12231223
@AuthenticationPrincipal CustomUserDetails user);
12241224

1225-
1226-
@Operation(
1227-
summary = "μ·¨λ―Έ μŠ€ν† λ¦¬ νƒ­ 쑰회",
1228-
description = "μ‚¬μš©μžκ°€ μ§„ν–‰ 쀑인 μ·¨λ―Έ λͺ©λ‘μ„ μ΅œμ‹ μˆœμœΌλ‘œ μ‘°νšŒν•©λ‹ˆλ‹€. κ²°κ³Όκ°€ μ—†μœΌλ©΄ 빈 리슀트λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€."
1229-
)
1230-
@ApiResponses(value = {
1231-
@ApiResponse(
1232-
responseCode = "200",
1233-
description = "쑰회 성곡",
1234-
content = @Content(schema = @Schema(implementation = GetHobbyStoryTabsResDto.class))
1235-
),
1236-
@ApiResponse(
1237-
responseCode = "200 (Empty)",
1238-
description = "μ§„ν–‰ 쀑인 μ·¨λ―Έκ°€ 없을 λ•Œ",
1239-
content = @Content(examples = @ExampleObject(value = "{\"status\": 200, \"success\": true, \"data\": {\"tabInfo\": []}}"))
1240-
)
1241-
})
1242-
GetHobbyStoryTabsResDto getHobbyStoryTabs(@AuthenticationPrincipal CustomUserDetails user);
1243-
1244-
12451225
@Operation(summary = "μ·¨λ―Έ 이름 쀑볡 확인", description = "μ‚¬μš©μžκ°€ μƒμ„±ν•˜λ €λŠ” μ·¨λ―Έ 이름이 이미 λ“±λ‘λ˜μ–΄ μžˆλŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.")
12461226
@ApiResponses(value = {
12471227
@ApiResponse(responseCode = "200", description = "성곡적인 응닡 (쀑볡 μ—¬λΆ€λŠ” data.availability둜 확인)")

β€Žsrc/main/java/com/example/ForDay/domain/hobby/repository/HobbyRepositoryImpl.javaβ€Ž

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ public class HobbyRepositoryImpl implements HobbyRepositoryCustom {
3535
@Override
3636
public GetHomeHobbyInfoResDto getHomeHobbyInfo(Long targetHobbyId, User currentUser) {
3737

38+
var isCurrentHobbyExpr = new CaseBuilder()
39+
.when(hobby.id.eq(targetHobbyId)).then(true)
40+
.otherwise(false);
41+
42+
var currentHobbyOrderKey = new CaseBuilder()
43+
.when(hobby.id.eq(targetHobbyId)).then(0)
44+
.otherwise(1);
45+
3846
// 1. Hobby 리슀트 쑰회 (ν˜„μž¬ μ‚¬μš©μžμ˜ μ§„ν–‰ 쀑인 μ·¨λ―Έλ“€)
3947
List<GetHomeHobbyInfoResDto.InProgressHobbyDto> hobbyList = queryFactory
4048
.select(Projections.constructor(GetHomeHobbyInfoResDto.InProgressHobbyDto.class,
@@ -46,7 +54,8 @@ public GetHomeHobbyInfoResDto getHomeHobbyInfo(Long targetHobbyId, User currentU
4654
.from(hobby)
4755
.where(hobby.user.eq(currentUser),
4856
hobby.status.eq(HobbyStatus.IN_PROGRESS))
49-
.orderBy(hobby.createdAt.desc())
57+
.orderBy(currentHobbyOrderKey.asc(),
58+
hobby.createdAt.desc())
5059
.fetch();
5160

5261
if (hobbyList.isEmpty()) return null;
@@ -111,13 +120,13 @@ public Map<HobbyStatus, Long> getCountsByStatus(User user) {
111120
public OnboardingDataDto getOnboardingDate(User user) {
112121
return queryFactory
113122
.select(Projections.constructor(OnboardingDataDto.class,
114-
hobby.id,
115-
hobby.hobbyInfoId,
116-
hobby.hobbyName,
117-
hobby.hobbyPurpose,
118-
hobby.hobbyTimeMinutes,
119-
hobby.executionCount,
120-
hobby.goalDays
123+
hobby.id,
124+
hobby.hobbyInfoId,
125+
hobby.hobbyName,
126+
hobby.hobbyPurpose,
127+
hobby.hobbyTimeMinutes,
128+
hobby.executionCount,
129+
hobby.goalDays
121130
)
122131
)
123132
.from(hobby)

0 commit comments

Comments
Β (0)