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 @@ -20,9 +20,17 @@ public class AlarmDynamicRepositoryImpl implements AlarmDynamicRepository {
@Override
public List<Summary> findAlarms(Long userId, PageRequest pageRequest) {

return queryFactory.selectFrom(summary).innerJoin(summary.subscription, subscription).fetchJoin()
.where(subscription.user.id.eq(userId), subscription.isAlarmEnabled.eq(true))
.orderBy(summary.updatedAt.desc(), summary.id.desc()).offset(pageRequest.page() * pageRequest.size())
// 알람을 바꿨을 때 그 때를 기억해서 그 전에 목록은 안보이는게 맞다
return queryFactory.selectFrom(summary)
.innerJoin(summary.subscription, subscription).fetchJoin()
.where(
subscription.user.id.eq(userId),
subscription.isAlarmEnabled.eq(true),
subscription.lastAlarmToggleAt.isNull()
.or(summary.createdAt.goe(subscription.lastAlarmToggleAt))
)
.orderBy(summary.updatedAt.desc(), summary.id.desc())
.offset(pageRequest.page() * pageRequest.size())
.limit(pageRequest.size()).fetch();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ public class Subscription extends BaseEntity {
@Column(name = "last_seen_post_id", nullable = false)
private String lastSeenPostId;

// 마지막으로 isAlarmEnabled를 수정한 순간
@Column(name = "last_alarm_toggle_at", nullable = true)
private LocalDateTime lastAlarmToggleAt;

@CreationTimestamp
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
Expand Down Expand Up @@ -83,8 +87,9 @@ public void updateAlias(String alias) {
}

public void updateIsAlarmEnabled(Boolean alarmEnabled) {
if (alarmEnabled != null) {
if (alarmEnabled != null && this.isAlarmEnabled != alarmEnabled) {
this.isAlarmEnabled = alarmEnabled;
this.lastAlarmToggleAt = LocalDateTime.now();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

LocalDateTime.now()는 시스템의 기본 시간대를 사용합니다. 서버가 다른 시간대에서 실행될 경우 예기치 않은 동작을 유발할 수 있습니다. 시간대 문제를 방지하려면 LocalDateTime.now(ZoneOffset.UTC)와 같이 UTC를 명시적으로 사용하는 것이 좋습니다. 이 변경을 적용하려면 java.time.ZoneOffset을 import해야 합니다.

Suggested change
this.lastAlarmToggleAt = LocalDateTime.now();
this.lastAlarmToggleAt = LocalDateTime.now(java.time.ZoneOffset.UTC);

}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE subscriptions
ADD COLUMN last_alarm_toggle_at datetime(6) NULL;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.todaysound.todaysound_server.domain.user.entity.UserType;
import com.todaysound.todaysound_server.domain.user.repository.UserRepository;
import com.todaysound.todaysound_server.global.dto.PageRequest;
import com.todaysound.todaysound_server.global.utils.CryptoUtils;
import com.todaysound.todaysound_server.support.ServiceTestSupport;
import java.time.LocalDateTime;
import java.util.List;
Expand All @@ -39,36 +40,101 @@ class AlarmQueryServiceTest extends ServiceTestSupport {
@Autowired
private AlarmQueryService alarmQueryService;

// @Test
// void 최근_알람을_조회한다() {
// // given
// Url url = Url.create("http://example.com", "Example Site");
// urlRepository.save(url);
//
// User user = User.create("userId1", "hashedSecret", "fingerPrint", UserType.USER, true, "plainSecret");
// userRepository.save(user);
//
// Subscription subscription = Subscription.create(url, true, "alias", user, "lastSeenPostId");
// subscriptionRepository.save(subscription);
//
// Summary summary1 = Summary.create("hash1", "title1", "content1", "postUrl1", "postDate1", false, subscription);
// Summary summary2 = Summary.create("hash2", "title2", "content2", "postUrl2", "postDate2", false, subscription);
// Summary summary3 = Summary.create("hash3", "title3", "content3", "postUrl3", "postDate3", false, subscription);
// Summary summary4 = Summary.create("hash4", "title4", "content4", "postUrl4", "postDate4", false, subscription);
// ReflectionTestUtils.setField(summary4, "updatedAt", LocalDateTime.now().minusDays(1));
// ReflectionTestUtils.setField(summary3, "updatedAt", LocalDateTime.now().minusDays(2));
// ReflectionTestUtils.setField(summary2, "updatedAt", LocalDateTime.now().minusDays(3));
// ReflectionTestUtils.setField(summary1, "updatedAt", LocalDateTime.now().minusDays(4));
// summaryRepository.saveAll(List.of(summary1, summary2, summary3, summary4));
//
// // when
// List<RecentAlarmResponse> result = alarmQueryService.getRecentAlarms(new PageRequest(0, 5), user.getUserId(), user.getHashedSecret());
//
// // then
// assertThat(result.get(0).alias()).isEqualTo("title4");
// assertThat(result.get(1).alias()).isEqualTo("title3");
// assertThat(result.get(2).alias()).isEqualTo("title2");
// assertThat(result.get(3).alias()).isEqualTo("title1");
// }
@Test
void lastAlarmToggleAt_이전에_생성된_summary는_조회되지_않는다() {
// given
Url url = Url.create("http://example.com", "Example Site");
urlRepository.save(url);

String plainSecret = "plainSecret1";
User user = User.create("userId1", "hashedSecret", CryptoUtils.sha256(plainSecret), UserType.USER, true, plainSecret);
userRepository.save(user);

Subscription subscription = Subscription.create(url, true, "alias", user, "lastSeenPostId");
LocalDateTime toggleAt = LocalDateTime.now();
ReflectionTestUtils.setField(subscription, "lastAlarmToggleAt", toggleAt);
subscriptionRepository.save(subscription);

// lastAlarmToggleAt 이전에 생성된 summary
Summary summaryBefore = Summary.create("hash1", "title1", "content1", "postUrl1", "postDate1", false, subscription);
ReflectionTestUtils.setField(summaryBefore, "createdAt", toggleAt.minusDays(1));
ReflectionTestUtils.setField(summaryBefore, "updatedAt", toggleAt.minusDays(1));

// lastAlarmToggleAt 이후에 생성된 summary
Summary summaryAfter = Summary.create("hash2", "title2", "content2", "postUrl2", "postDate2", false, subscription);
ReflectionTestUtils.setField(summaryAfter, "createdAt", toggleAt.plusDays(1));
ReflectionTestUtils.setField(summaryAfter, "updatedAt", toggleAt.plusDays(1));

summaryRepository.saveAll(List.of(summaryBefore, summaryAfter));

// when
List<RecentAlarmResponse> result = alarmQueryService.getRecentAlarms(
new PageRequest(0, 10), user.getUserId(), plainSecret);

// then
assertThat(result).hasSize(1);
assertThat(result.get(0).alias()).isEqualTo("title2");
}

@Test
void lastAlarmToggleAt이_null이면_모든_summary가_조회된다() {
// given
Url url = Url.create("http://example.com", "Example Site");
urlRepository.save(url);

String plainSecret = "plainSecret2";
User user = User.create("userId2", "hashedSecret2", CryptoUtils.sha256(plainSecret), UserType.USER, true, plainSecret);
userRepository.save(user);

Subscription subscription = Subscription.create(url, true, "alias", user, "lastSeenPostId");
// lastAlarmToggleAt은 null (기본값)
subscriptionRepository.save(subscription);

Summary summary1 = Summary.create("hash1", "title1", "content1", "postUrl1", "postDate1", false, subscription);
Summary summary2 = Summary.create("hash2", "title2", "content2", "postUrl2", "postDate2", false, subscription);
ReflectionTestUtils.setField(summary1, "createdAt", LocalDateTime.now().minusDays(10));
ReflectionTestUtils.setField(summary1, "updatedAt", LocalDateTime.now().minusDays(10));
ReflectionTestUtils.setField(summary2, "createdAt", LocalDateTime.now().minusDays(5));
ReflectionTestUtils.setField(summary2, "updatedAt", LocalDateTime.now().minusDays(5));
summaryRepository.saveAll(List.of(summary1, summary2));

// when
List<RecentAlarmResponse> result = alarmQueryService.getRecentAlarms(
new PageRequest(0, 10), user.getUserId(), plainSecret);

// then
assertThat(result).hasSize(2);
}

@Test
void 알람이_꺼져있는_subscription의_summary는_조회되지_않는다() {
// given
Url url = Url.create("http://example.com", "Example Site");
urlRepository.save(url);

String plainSecret = "plainSecret3";
User user = User.create("userId3", "hashedSecret3", CryptoUtils.sha256(plainSecret), UserType.USER, true, plainSecret);
userRepository.save(user);

// 알람이 꺼진 구독
Subscription subscriptionOff = Subscription.create(url, false, "aliasOff", user, "lastSeenPostId");
subscriptionRepository.save(subscriptionOff);

// 알람이 켜진 구독
Subscription subscriptionOn = Subscription.create(url, true, "aliasOn", user, "lastSeenPostId");
subscriptionRepository.save(subscriptionOn);

Summary summaryOff = Summary.create("hash1", "titleOff", "content1", "postUrl1", "postDate1", false, subscriptionOff);
Summary summaryOn = Summary.create("hash2", "titleOn", "content2", "postUrl2", "postDate2", false, subscriptionOn);
summaryRepository.saveAll(List.of(summaryOff, summaryOn));

// when
List<RecentAlarmResponse> result = alarmQueryService.getRecentAlarms(
new PageRequest(0, 10), user.getUserId(), plainSecret);

// then
assertThat(result).hasSize(1);
assertThat(result.get(0).alias()).isEqualTo("titleOn");
}

}