Skip to content

Commit

Permalink
[BUG] 좋아요 반 정규화로 인한 템플릿 좋아요 시 해당 템플릿의 ModifiedAt 변경 문제 (#927)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyum-q authored Dec 16, 2024
1 parent 106873f commit 4d4b164
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseTimeEntity {
public abstract class BaseTimeEntity {

@CreatedDate
@Column(updatable = false, nullable = false)
private LocalDateTime createdAt;
protected LocalDateTime createdAt;

@LastModifiedDate
@Column(nullable = false)
private LocalDateTime modifiedAt;
protected LocalDateTime modifiedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package codezap.global.auditing;

import java.time.LocalDateTime;

import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.PostLoad;
import jakarta.persistence.PostPersist;
import jakarta.persistence.PostUpdate;
import jakarta.persistence.PreUpdate;
import jakarta.persistence.Transient;

@MappedSuperclass
public abstract class SkipModifiedAtBaseTimeEntity extends BaseTimeEntity {

@Transient
private LocalDateTime lastModifiedAt;

@Transient
private boolean isModified = true;

@PreUpdate
private void preUpdate() {
if (!isModified && lastModifiedAt != null) {
modifiedAt = lastModifiedAt;
return;
}
isModified = true;
}

@PostLoad
@PostPersist
@PostUpdate
private void postLoad() {
lastModifiedAt = modifiedAt;
}

public void skipModifiedAtUpdate() {
isModified = false;
}
}
8 changes: 6 additions & 2 deletions backend/src/main/java/codezap/template/domain/Template.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package codezap.template.domain;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -18,7 +19,7 @@
import org.hibernate.annotations.DynamicUpdate;

import codezap.category.domain.Category;
import codezap.global.auditing.BaseTimeEntity;
import codezap.global.auditing.SkipModifiedAtBaseTimeEntity;
import codezap.member.domain.Member;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand All @@ -32,7 +33,7 @@
@AllArgsConstructor
@Getter
@EqualsAndHashCode(of = "id", callSuper = false)
public class Template extends BaseTimeEntity {
public class Template extends SkipModifiedAtBaseTimeEntity {

private static final Long LIKES_COUNT_DEFAULT = 0L;

Expand Down Expand Up @@ -73,6 +74,7 @@ public Template(Member member, String title, String description, Category catego
}

public void updateTemplate(String title, String description, Category category, Visibility visibility) {
this.modifiedAt = LocalDateTime.now();
this.title = title;
this.description = description;
this.category = category;
Expand All @@ -88,10 +90,12 @@ public boolean isPrivate() {
}

public void increaseLike() {
skipModifiedAtUpdate();
this.likesCount++;
}

public void cancelLike() {
skipModifiedAtUpdate();
if (this.likesCount <= LIKES_COUNT_DEFAULT) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion backend/src/test/java/codezap/fixture/CategoryFixture.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public static Category getSecondCategory() {
}

public static Category get(Member member) {
return new Category(1L, member, "카테고리", false);
return new Category("카테고리", member);
}
}
24 changes: 19 additions & 5 deletions backend/src/test/java/codezap/likes/service/LikesServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

import java.time.LocalDateTime;
import java.util.List;

import jakarta.persistence.EntityManager;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;

import codezap.category.domain.Category;
import codezap.fixture.CategoryFixture;
import codezap.fixture.MemberFixture;
import codezap.fixture.TemplateFixture;
import codezap.global.ServiceTest;
import codezap.global.pagination.FixedPage;
import codezap.likes.domain.Likes;
import codezap.member.domain.Member;
import codezap.template.domain.Template;
Expand All @@ -26,22 +27,30 @@ class LikesServiceTest extends ServiceTest {
@Autowired
private LikesService likesService;

@Autowired
private EntityManager entityManager;

@Nested
@DisplayName("좋아요")
class LikesTest {

@Test
@DisplayName("성공")
@DisplayName("성공: 템플릿 수정 시간은 변경되지 않는다.")
void success() {
Member member = memberRepository.save(MemberFixture.getFirstMember());
Template template = templateRepository.save(TemplateFixture.get(
member,
categoryRepository.save(CategoryFixture.getFirstCategory())
));
LocalDateTime modifiedAtBeforeLike = template.getModifiedAt();

likesService.like(member, template.getId());
entityManager.flush();

assertThat(likesRepository.existsByMemberAndTemplate(member, template)).isTrue();
assertAll(
() -> assertThat(likesRepository.existsByMemberAndTemplate(member, template)).isTrue(),
() -> assertThat(template.getModifiedAt()).isEqualTo(modifiedAtBeforeLike)
);
}

@Test
Expand Down Expand Up @@ -71,10 +80,15 @@ void success() {
Category category = categoryRepository.save(CategoryFixture.getFirstCategory());
Template template = templateRepository.save(TemplateFixture.get(member, category));
likesService.like(member, template.getId());
LocalDateTime modifiedAtBeforeLike = template.getModifiedAt();

likesService.cancelLike(member, template.getId());
entityManager.flush();

assertThat(likesRepository.existsByMemberAndTemplate(member, template)).isFalse();
assertAll(
() -> assertThat(likesRepository.existsByMemberAndTemplate(member, template)).isFalse(),
() -> assertThat(template.getModifiedAt()).isEqualTo(modifiedAtBeforeLike)
);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,43 +178,6 @@ void findSourceCodesByTemplate_WhenSourceCodeNotExist() {
@DisplayName("소스 코드 수정")
class UpdateSourceCodes {

@Test
@DisplayName("성공: 기존 소스 코드 제목, 내용 수정 및 새로운 소스 코드 추가")
void updateSourceCodes() {
// given
Template template = createSavedTemplate();
SourceCode sourceCode1 = sourceCodeRepository.save(SourceCodeFixture.get(template, 1));
SourceCode sourceCode2 = sourceCodeRepository.save(SourceCodeFixture.get(template, 2));
Thumbnail thumbnail = thumbnailRepository.save(new Thumbnail(template, sourceCode1));

UpdateSourceCodeRequest updateRequest1 = getUpdateSourceCodeRequest(sourceCode1);
UpdateSourceCodeRequest updateRequest2 = getUpdateSourceCodeRequest(sourceCode2);
CreateSourceCodeRequest createRequest = new CreateSourceCodeRequest("새로운 제목1", "새로운 내용1", 3);
UpdateTemplateRequest updateTemplateRequest = getUpdateTemplateRequest(
List.of(createRequest),
List.of(updateRequest1, updateRequest2),
Collections.emptyList(),
template.getCategory().getId(),
Collections.emptyList()
);

// when
sourceCodeService.updateSourceCodes(updateTemplateRequest, template, thumbnail);

// then
SourceCode updatedSourceCode1 = sourceCodeRepository.fetchById(sourceCode1.getId());
SourceCode updatedSourceCode2 = sourceCodeRepository.fetchById(sourceCode2.getId());
SourceCode newSourceCode = sourceCodeRepository.fetchByTemplateAndOrdinal(template, 3);

assertAll(
() -> assertThat(sourceCodeRepository.countByTemplate(template)).isEqualTo(3),
() -> assertThat(updatedSourceCode1.getFilename()).isEqualTo("변경된 제목1"),
() -> assertThat(updatedSourceCode1.getOrdinal()).isEqualTo(1),
() -> assertThat(updatedSourceCode2.getFilename()).isEqualTo("변경된 제목2"),
() -> assertThat(updatedSourceCode2.getOrdinal()).isEqualTo(2),
() -> assertThat(newSourceCode.getFilename()).isEqualTo("새로운 제목1"));
}

@Test
@Disabled("애플리케이션 코드에서 로직 변경 필요")
@DisplayName("성공: 일부 소스 코드 삭제 및 새로운 소스 코드 추가 시, 삭제된 코드 순서는 앞당겨지고 새로 추가된 소스 코드의 순서는 가장 마지막 순서")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import java.util.List;

import jakarta.persistence.EntityManager;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -38,6 +40,9 @@ class TemplateServiceTest extends ServiceTest {
@Autowired
private LikesService likesService;

@Autowired
private EntityManager entityManager;

@Nested
@DisplayName("템플릿 생성")
class CreateTemplate {
Expand Down Expand Up @@ -191,7 +196,6 @@ private void likeTemplate(long templateId, long likesCount) {
}
}


@Nested
@DisplayName("좋아요한 템플릿 조회")
class FindAllByMemberId {
Expand All @@ -212,7 +216,8 @@ void findAllByMemberId() {
likesRepository.save(new Likes(template3, member1));

// when
FixedPage<Template> actual = templateRepository.findAllLikedByMemberId(member1.getId(), PageRequest.of(0, 5));
FixedPage<Template> actual = templateRepository.findAllLikedByMemberId(member1.getId(),
PageRequest.of(0, 5));

// then
assertThat(actual.contents()).containsExactlyInAnyOrder(template1, template3);
Expand Down Expand Up @@ -248,6 +253,30 @@ void updateTemplateSuccess() {
);
}

@Test
@DisplayName("템플릿 수정 성공 : 데이터가 수정됐을 경우 modifiedAt 변경")
void updateTemplateSuccessChangeModifiedAt() {
var member = memberRepository.save(MemberFixture.getFirstMember());
var category = categoryRepository.save(CategoryFixture.getFirstCategory());
var template = templateRepository.save(TemplateFixture.get(member, category));
var beforeModifiedAt = template.getModifiedAt();
var updateRequest = new UpdateTemplateRequest(
"update title",
"update description",
List.of(),
List.of(),
List.of(),
category.getId(),
List.of(),
Visibility.PRIVATE
);

sut.update(member, template.getId(), updateRequest, category);
entityManager.flush();

assertThat(template.getModifiedAt()).isNotEqualTo(beforeModifiedAt);
}

@Test
@DisplayName("템플릿 수정 실패: 해당하는 ID의 템플릿이 존재하지 않는 경우")
void updateTemplateFailWithWrongID() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

import jakarta.persistence.EntityManager;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -459,6 +462,35 @@ void update() {
);
}

@Test
@DisplayName("성공: 소스코드만 변경 시에도 수정 시간 변경")
void updateSourceCodesChangeModifiedAt() {
// given
Member member = memberRepository.save(MemberFixture.getFirstMember());
Category category = categoryRepository.save(CategoryFixture.getFirstCategory());
Template template = templateRepository.save(TemplateFixture.get(member, category));
SourceCode sourceCode = sourceCodeRepository.save(SourceCodeFixture.get(template, 1));
thumbnailRepository.save(new Thumbnail(template, sourceCode));
UpdateSourceCodeRequest updateRequest1 = updateSourceCodeRequest(sourceCode);
UpdateTemplateRequest updateTemplateRequest = new UpdateTemplateRequest(
template.getTitle(),
template.getDescription(),
List.of(),
List.of(updateRequest1),
List.of(),
template.getCategory().getId(),
List.of(),
Visibility.PUBLIC
);
LocalDateTime beforeModifiedAt = template.getModifiedAt();

// when
sut.update(member, template.getId(), updateTemplateRequest);

// then
assertThat(template.getModifiedAt()).isNotEqualTo(beforeModifiedAt);
}

@Test
@DisplayName("실패: 카테고리에 대한 권한이 없는 경우")
void updateTemplate_WhenNoAuthorization() {
Expand All @@ -485,7 +517,7 @@ void updateTemplate_WhenNoAuthorization() {
Visibility.PUBLIC);

// when & then
assertThatThrownBy(() -> sut.update(otherMember, template.getId(), request))
assertThatThrownBy(() -> sut.update(member, template.getId(), request))
.isInstanceOf(CodeZapException.class)
.hasMessage("해당 카테고리를 수정 또는 삭제할 권한이 없는 유저입니다.");
}
Expand Down Expand Up @@ -524,7 +556,8 @@ void deleteByMemberAndIds() {
sut.deleteAllByMemberAndTemplateIds(member, deleteIds);

// then
var actualTemplatesLeft = templateRepository.findAll(member.getId(), null, null, null, null, PageRequest.of(0, 10));
var actualTemplatesLeft = templateRepository.findAll(member.getId(), null, null, null, null,
PageRequest.of(0, 10));
var actualSourceCodeLeft = sourceCodeRepository.findAllByTemplate(template1);
actualSourceCodeLeft.addAll(sourceCodeRepository.findAllByTemplate(template2));
actualSourceCodeLeft.addAll(sourceCodeRepository.findAllByTemplate(template3));
Expand Down

0 comments on commit 4d4b164

Please sign in to comment.