Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public BaseResponse<SliceResponse<ClothRecommendListResponse>> recommendCategory
@Parameter(description = "이전 페이지의 옷ID (첫 요청 시 생략)") @RequestParam(required = false)
Long lastClothId,
@Parameter(description = "페이지당 조회할 옷 수") @RequestParam @PageSize Integer size,
@Parameter(description = " 카테고리 ID") @RequestParam Long categoryId,
@Parameter(description = "상위 카테고리 ID") @RequestParam Long categoryId,
@Parameter(description = "요청 계절") @RequestParam Season season) {
SliceResponse<ClothRecommendListResponse> response =
clothService.recommendCategoryClothes(lastClothId, size, categoryId, season);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.clokey.domain.cloth.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;

@Schema(description = "테스트용 presignedUrl 발급 요청 (로컬 환경 전용)")
public record TestPresignedUrlRequest(
@NotNull(message = "발급할 presignedUrl 개수는 필수입니다.")
@Min(value = 1, message = "발급할 presignedUrl 개수는 1개 이상이어야 합니다.")
@Schema(description = "발급할 presignedUrl 개수", example = "5")
Integer count) {}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
public interface ClothRepositoryCustom {

Slice<ClothRecommendListResponse> findAllMemberRecommendClothesByCategoryAndSeason(
Long lastClothId, int size, Long categoryId, Long memberId, Season season);
Long lastClothId, int size, List<Long> categoryIds, Long memberId, Season season);

Slice<ClothListResponse> findAllMemberClothesByCategoriesAndSeasons(
Long lastClothId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ public class ClothRepositoryImpl implements ClothRepositoryCustom {

@Override
public Slice<ClothRecommendListResponse> findAllMemberRecommendClothesByCategoryAndSeason(
Long lastClothId, int size, Long categoryId, Long memberId, Season season) {
Long lastClothId, int size, List<Long> categoryIds, Long memberId, Season season) {
if (categoryIds == null || categoryIds.isEmpty()) {
return new SliceImpl<>(List.of(), PageRequest.of(0, size), false);
}

Season nextSeason = season.next();
Season previousSeason = season.previous();
Expand Down Expand Up @@ -65,7 +68,7 @@ public Slice<ClothRecommendListResponse> findAllMemberRecommendClothesByCategory
queryFactory
.selectFrom(cloth)
.where(
cloth.category.id.eq(categoryId),
cloth.category.id.in(categoryIds),
cloth.member.id.eq(memberId),
seasonCondition)
.orderBy(seasonPriority.asc(), cloth.id.asc())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,11 @@ public ClothCreateResponse createClothes(ClothCreateRequests request) {
public SliceResponse<ClothRecommendListResponse> recommendCategoryClothes(
Long lastClothId, int size, Long categoryId, Season season) {
final Member currentMember = memberUtil.getCurrentMember();
List<Long> categoryIds = resolveCategoryIds(categoryId);

Slice<ClothRecommendListResponse> result =
clothRepository.findAllMemberRecommendClothesByCategoryAndSeason(
lastClothId, size, categoryId, currentMember.getId(), season);
lastClothId, size, categoryIds, currentMember.getId(), season);

return SliceResponse.from(result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
import org.clokey.notification.enums.NotificationType;
import org.clokey.notification.enums.ReadStatus;
import org.clokey.notification.enums.RedirectType;

public record NotificationListResponse(
@Schema(description = "알림의 ID", example = "1L") Long notificationId,
@Schema(description = "알림의 ID", example = "1") Long notificationId,
@Schema(description = "알림의 이미지 URL", example = "https://testiamge.com")
String notificationImageUrl,
@Schema(description = "알림의 내용", example = "테스트 알림입니다.") String notificationContent,
@Schema(description = "redirectInfo(historyId 등)", example = "1L") String redirectInfo,
@Schema(description = "RedirectType(Member, History 등)", example = "MEMBER_REDIRECT")
RedirectType redirectType,
@Schema(description = "알림의 타입", example = "COMMENT") NotificationType notificationType,
@Schema(description = "알림 이동 정보") NotificationActionResponse action,
@Schema(description = "읽음 상태(ReadStatus)", example = "NOT_READ") ReadStatus readStatus,
@Schema(description = "알림이 생성된 시간", example = "2025-11-25T12:39:03.123456")
LocalDateTime createdAt) {}
LocalDateTime createdAt) {
public record NotificationActionResponse(
@Schema(description = "알림 이동 타입", example = "HISTORY_REDIRECT")
RedirectType redirectType,
@Schema(description = "알림 이동 정보(historyId 등)", example = "1") String redirectInfo) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ public Slice<NotificationListResponse> findAllNotificationsByMemberId(
codiveNotification.id,
codiveNotification.notificationImageUrl,
codiveNotification.content,
codiveNotification.redirectInfo,
codiveNotification.redirectType,
codiveNotification.notificationType,
Projections.constructor(
NotificationListResponse.NotificationActionResponse
.class,
codiveNotification.redirectType,
codiveNotification.redirectInfo),
codiveNotification.readStatus,
codiveNotification.createdAt))
.from(codiveNotification)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.clokey.member.entity.Member;
import org.clokey.member.enums.MemberStatus;
import org.clokey.notification.entity.CodiveNotification;
import org.clokey.notification.enums.NotificationType;
import org.clokey.notification.enums.ReadStatus;
import org.clokey.notification.enums.RedirectType;
import org.clokey.response.SliceResponse;
Expand Down Expand Up @@ -55,6 +56,7 @@ public class CodiveNotificationServiceImpl implements CodiveNotificationService

private static final String TODAY_TEMPERATURE_NOTIFICATION =
"오늘의 기온은 %d도 입니다!\n날씨에 맞는 오늘의 옷차림이 기다리고 있어요👀";
private static final String TODAY_TEMPERATURE_IMAGE_URL = "https://example.com/temperature.png";

@Override
public void sendNewFollowerNotification(Long followFromId, Long followToId) {
Expand Down Expand Up @@ -90,7 +92,8 @@ public void sendNewFollowerNotification(Long followFromId, Long followToId) {
content,
profileImageUrl,
followToMember.getNickname(),
RedirectType.MEMBER_REDIRECT);
RedirectType.MEMBER_REDIRECT,
NotificationType.FOLLOW);

codiveNotificationRepository.save(codiveNotification);
}
Expand Down Expand Up @@ -131,7 +134,8 @@ public void sendNewPendingFollowerNotification(Long followFromId, Long followToI
content,
profileImageUrl,
followToMember.getNickname(),
RedirectType.MEMBER_REDIRECT);
RedirectType.MEMBER_REDIRECT,
NotificationType.FOLLOW_REQUEST);

codiveNotificationRepository.save(codiveNotification);
}
Expand Down Expand Up @@ -173,7 +177,8 @@ public void sendNewCommentNotification(NewCommentEvent event) {
content,
profileImageUrl,
String.valueOf(event.historyId()),
RedirectType.HISTORY_REDIRECT);
RedirectType.HISTORY_REDIRECT,
NotificationType.COMMENT);

codiveNotificationRepository.save(codiveNotification);
}
Expand Down Expand Up @@ -212,7 +217,8 @@ public void sendNewReplyNotification(NewReplyEvent event) {
content,
profileImageUrl,
String.valueOf(event.historyId()),
RedirectType.HISTORY_REDIRECT);
RedirectType.HISTORY_REDIRECT,
NotificationType.REPLY);

codiveNotificationRepository.save(codiveNotification);
}
Expand All @@ -221,11 +227,15 @@ public void sendNewReplyNotification(NewReplyEvent event) {
@Override
public void sendNewTemperatureNotification(TemperatureNotificationRequest request) {
Member receiver = memberUtil.getCurrentMember();
String content = "";
String content =
String.format(TODAY_TEMPERATURE_NOTIFICATION, Math.round(request.temperature()));

if (isAbleToSendNotification(receiver)) {

Notification notification = Notification.builder().setBody(content).build();
Notification notification =
Notification.builder()
.setBody(content)
.setImage(TODAY_TEMPERATURE_IMAGE_URL)
.build();
Message message =
Message.builder()
.setToken(receiver.getDeviceToken())
Expand All @@ -237,6 +247,17 @@ public void sendNewTemperatureNotification(TemperatureNotificationRequest reques
} catch (FirebaseMessagingException e) {
throw new BaseCustomException(NotificationErrorCode.NOTIFICATION_FIREBASE_ERROR);
}

CodiveNotification codiveNotification =
CodiveNotification.createCodiveNotification(
receiver,
content,
TODAY_TEMPERATURE_IMAGE_URL,
"",
RedirectType.NONE,
NotificationType.TEMPERATURE_DAILY);

codiveNotificationRepository.save(codiveNotification);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import org.clokey.member.enums.OauthProvider;
import org.clokey.member.enums.Visibility;
import org.clokey.notification.entity.CodiveNotification;
import org.clokey.notification.enums.NotificationType;
import org.clokey.notification.enums.RedirectType;
import org.clokey.report.entity.Report;
import org.clokey.report.enums.ReportReason;
Expand Down Expand Up @@ -479,7 +480,8 @@ void setUp() {
"testContent",
"notificationImageUrl",
"redirectInfo",
RedirectType.HISTORY_REDIRECT);
RedirectType.HISTORY_REDIRECT,
NotificationType.COMMENT);
codiveNotificationRepository.save(notification);

// Follow 생성 (targetMember가 팔로우하는 경우)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,10 @@ void setUp() {
memberRepository.save(member);
given(memberUtil.getCurrentMember()).willReturn(member);

Category category1 = Category.createCategory("testCategory1", null);
Category category2 = Category.createCategory("testCategory2", null);
categoryRepository.saveAll(List.of(category1, category2));
Category parentCategory1 = Category.createCategory("testParentCategory1", null);
Category parentCategory2 = Category.createCategory("testParentCategory2", null);
Category category1 = Category.createCategory("testCategory1", parentCategory1);
categoryRepository.saveAll(List.of(parentCategory1, parentCategory2, category1));

Cloth cloth1 =
Cloth.createCloth(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.clokey.domain.notification.dto.response.NotificationListResponse;
import org.clokey.domain.notification.dto.response.UnreadNotificationResponse;
import org.clokey.domain.notification.service.CodiveNotificationService;
import org.clokey.notification.enums.NotificationType;
import org.clokey.notification.enums.ReadStatus;
import org.clokey.notification.enums.RedirectType;
import org.clokey.response.SliceResponse;
Expand Down Expand Up @@ -71,16 +72,18 @@ class 알림_목록_조회할_시 {
2L,
"https://image.example",
"테스트 알림2 내용입니다.",
"2",
RedirectType.HISTORY_REDIRECT,
NotificationType.COMMENT,
new NotificationListResponse.NotificationActionResponse(
RedirectType.HISTORY_REDIRECT, "2"),
ReadStatus.NOT_READ,
LocalDateTime.now()),
new NotificationListResponse(
1L,
"https://image.example",
"테스트 알림1 내용입니다.",
"2",
RedirectType.MEMBER_REDIRECT,
NotificationType.FOLLOW,
new NotificationListResponse.NotificationActionResponse(
RedirectType.MEMBER_REDIRECT, "2"),
ReadStatus.READ,
LocalDateTime.now()));

Expand All @@ -95,7 +98,17 @@ class 알림_목록_조회할_시 {
.andExpect(jsonPath("$.code").value("COMMON200"))
.andExpect(jsonPath("$.message").value("성공입니다."))
.andExpect(jsonPath("$.result.content[0].notificationId").value("2"))
.andExpect(jsonPath("$.result.content[0].notificationType").value("COMMENT"))
.andExpect(
jsonPath("$.result.content[0].action.redirectType")
.value("HISTORY_REDIRECT"))
.andExpect(jsonPath("$.result.content[0].action.redirectInfo").value("2"))
.andExpect(jsonPath("$.result.content[1].notificationId").value("1"))
.andExpect(jsonPath("$.result.content[1].notificationType").value("FOLLOW"))
.andExpect(
jsonPath("$.result.content[1].action.redirectType")
.value("MEMBER_REDIRECT"))
.andExpect(jsonPath("$.result.content[1].action.redirectInfo").value("2"))
.andExpect(jsonPath("$.result.isLast").value(true));
}

Expand Down
Loading