Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] 인사이트 작성 시 챌린지 기록 #133

Merged
merged 5 commits into from
Oct 14, 2022
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -9,6 +9,7 @@
import javax.persistence.*;

import java.time.LocalDate;
import java.time.Period;

import static javax.persistence.FetchType.LAZY;
import static lombok.AccessLevel.PROTECTED;
Expand Down Expand Up @@ -72,4 +73,13 @@ private void initEndDate() {
LocalDate createdDate = getCreatedAt().toLocalDate();
this.endDate = createdDate.minusDays(1).plusWeeks(duration);
}

// 현재가 몇 주차인지
public long getCurrentWeeks() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

weeks 하니까 먼가 여려 주의 정보를 가져올거 같아여 ㅋㅋ 중요한건 아니긴 합니당

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

요거만 바꾸고 머지할게요~

LocalDate createdAt = getCreatedAt().toLocalDate();
LocalDate today = LocalDate.now();
Period between = Period.between(today, createdAt);

return between.getDays() / 7 + 1; // 1주차부터 시작
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public class Insight extends BaseTimeEntity {
@Embedded
private Link link;

@Column(name = "valid", nullable = false)
private boolean valid = false;

@Column(name = "deleted", nullable = false)
private boolean deleted = false;

Expand All @@ -59,13 +62,14 @@ public class Insight extends BaseTimeEntity {
@Column(name = "view")
private Long view = 0L;

public static Insight of(User writer, ChallengeParticipation challengeParticipation, Drawer drawer, String contents, Link link) {
public static Insight of(User writer, ChallengeParticipation participation, Drawer drawer, String contents, Link link, boolean valid) {
Insight insight = new Insight();
insight.writer = writer;
insight.challengeParticipation = challengeParticipation;
insight.challengeParticipation = participation;
insight.drawer = drawer;
insight.contents = contents;
insight.link = link;
insight.valid = valid;

return insight;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import ccc.keewedomain.persistence.domain.challenge.ChallengeParticipation;
import ccc.keewedomain.persistence.domain.challenge.enums.ChallengeParticipationStatus;
import ccc.keewedomain.persistence.domain.user.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface ChallengeParticipationRepository extends
JpaRepository<ChallengeParticipation, Long>,
ChallengeParticipationQueryRepository {
Optional<ChallengeParticipation> findByChallengerIdAndStatus(Long userId, ChallengeParticipationStatus status);

Optional<ChallengeParticipation> findByChallengerAndStatusAndDeletedFalse(User challenger, ChallengeParticipationStatus status);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public interface DrawerRepository extends JpaRepository<Drawer, Long>, DrawerQue
List<Drawer> findAllByUserIdAndDeletedFalse(Long userId);

default Drawer findByIdOrElseThrow(Long id) {
return findByIdAndDeletedFalse(id).orElseThrow(() -> new KeeweException(KeeweRtnConsts.ERR442));
return findByIdAndDeletedFalse(id).orElseThrow(() -> new KeeweException(KeeweRtnConsts.ERR440));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ccc.keewedomain.persistence.repository.insight;

import ccc.keewedomain.persistence.domain.challenge.ChallengeParticipation;
import ccc.keewedomain.persistence.domain.insight.Insight;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
Expand All @@ -25,4 +26,13 @@ public Insight findByIdWithWriter(Long insightId) {
.fetchOne();

}

public Long countValidForParticipation(ChallengeParticipation participation) {
return queryFactory.select(insight.id.count())
.from(insight)
.where(insight.challengeParticipation.id.eq(participation.getId())
.and(insight.deleted.isFalse())
.and(insight.valid.isTrue()))
.fetchFirst();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public Challenge save(ChallengeCreateDto dto) {

public ChallengeParticipation participate(ChallengeParticipateDto dto) {
User challenger = userDomainService.getUserByIdOrElseThrow(dto.getChallengerId());
exitCurrentChallengeIfExist(dto.getChallengerId());
exitCurrentChallengeIfExist(challenger);
Challenge challenge = getByIdOrElseThrow(dto.getChallengeId());
return challenge.participate(challenger, dto.getMyTopic(), dto.getInsightPerWeek(), dto.getDuration());
}
Expand All @@ -45,15 +45,15 @@ public boolean checkParticipation(Long userId) {
return challengeParticipationRepository.existsByChallengerIdAndStatus(userId, CHALLENGING);
}

public ChallengeParticipation getCurrentChallengeParticipation(Long userId) {
return findCurrentChallengeParticipation(userId).orElseThrow(() -> new KeeweException(KeeweRtnConsts.ERR432));
public ChallengeParticipation getCurrentChallengeParticipation(User challenger) {
return findCurrentChallengeParticipation(challenger).orElseThrow(() -> new KeeweException(KeeweRtnConsts.ERR432));
}

private void exitCurrentChallengeIfExist(Long userId) {
findCurrentChallengeParticipation(userId).ifPresent(ChallengeParticipation::cancel);
private void exitCurrentChallengeIfExist(User challenger) {
findCurrentChallengeParticipation(challenger).ifPresent(ChallengeParticipation::cancel);
}

public Optional<ChallengeParticipation> findCurrentChallengeParticipation(Long userId) {
return challengeParticipationRepository.findByChallengerIdAndStatus(userId, CHALLENGING);
public Optional<ChallengeParticipation> findCurrentChallengeParticipation(User challenger) {
return challengeParticipationRepository.findByChallengerAndStatusAndDeletedFalse(challenger, CHALLENGING);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public Comment create(CommentCreateDto dto) {

Optional<Comment> optParent = findByIdAndInsightId(dto.getParentId(), dto.getInsightId());
optParent.ifPresent(this::validateHasNoParent);
Comment parent = optParent.get();
Comment parent = optParent.orElse(null);

Comment comment = Comment.of(insight, writer, parent, dto.getContent());
return commentRepository.save(comment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.Arrays;

@Service
Expand All @@ -45,10 +48,14 @@ public class InsightDomainService {
public Insight create(InsightCreateDto dto) {
User writer = userDomainService.getUserByIdOrElseThrow(dto.getWriterId());
Drawer drawer = drawerDomainService.getDrawerIfOwner(dto.getDrawerId(), writer);
ChallengeParticipation participation = challengeDomainService.findCurrentChallengeParticipation(dto.getWriterId())
.orElse(null);

Insight insight = Insight.of(writer, participation, drawer, dto.getContents(), Link.of(dto.getLink()));
ChallengeParticipation participation = null;
boolean valid = false;
if (dto.isParticipate()) {
participation = challengeDomainService.getCurrentChallengeParticipation(writer);
valid = isRecordable(participation);
}

Insight insight = Insight.of(writer, participation, drawer, dto.getContents(), Link.of(dto.getLink()), valid);
insightRepository.save(insight);
createReactionAggregations(insight);
return insight;
Expand Down Expand Up @@ -110,4 +117,11 @@ public Insight getById(Long id) {
return insightRepository.findById(id).orElseThrow(() -> new KeeweException(KeeweRtnConsts.ERR445));
}

private boolean isRecordable(ChallengeParticipation participation) {
Long count = insightQueryRepository.countValidForParticipation(participation);
long weeks = participation.getCurrentWeeks();
log.info("[IDS:isRecordable] count={} weeks={}", count, weeks);
return count < weeks * participation.getInsightPerWeek();
}

}
3 changes: 2 additions & 1 deletion keewe-domain/src/main/resources/ddl/ddl.sql
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ CREATE TABLE IF NOT EXISTS `insight`
contents VARCHAR(300) NOT NULL,
url VARCHAR(2000) NOT NULL,
deleted BIT NOT NULL,
valid BIT NOT NULL,
view BIGINT NOT NULL DEFAULT 0,
created_at DATETIME(6) NOT NULL,
updated_at DATETIME(6) NOT NULL,
Expand All @@ -141,7 +142,7 @@ CREATE TABLE IF NOT EXISTS `reaction`
created_at DATETIME(6) NOT NULL,
updated_at DATETIME(6) NOT NULL,

PRIMARY KEY (reacition_id)
PRIMARY KEY (reaction_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE IF NOT EXISTS `reaction_aggregation`
Expand Down
2 changes: 2 additions & 0 deletions keewe-domain/src/main/resources/dml/issue-126_dml.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE insight
ADD COLUMN valid BIT NOT NULL
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ public class CommentDomainServiceTest {
DatabaseCleaner databaseCleaner;

User user = User.from(UserSignUpDto.of("vendorId", VendorType.NAVER, "[email protected]", null, null));;
Insight insight = Insight.of(user, null, null, "인사이트 내용", Link.of("https://naver.com"));;
Comment comment = Comment.of(insight, user, null, "댓글 내용");;
Insight insight = Insight.of(user, null, null, "인사이트 내용", Link.of("https://naver.com"), false);;
Comment comment = Comment.of(insight, user, null, "댓글 내용");

@BeforeEach
void setup() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package ccc.keewedomain.service.insight;

import ccc.keewecore.consts.KeeweRtnConsts;
import ccc.keewecore.exception.KeeweException;
import ccc.keewedomain.KeeweDomainApplication;
import ccc.keewedomain.dto.insight.InsightCreateDto;
import ccc.keewedomain.dto.user.UserSignUpDto;
import ccc.keewedomain.persistence.domain.challenge.Challenge;
import ccc.keewedomain.persistence.domain.challenge.ChallengeParticipation;
import ccc.keewedomain.persistence.domain.common.Link;
import ccc.keewedomain.persistence.domain.insight.Drawer;
import ccc.keewedomain.persistence.domain.insight.Insight;
import ccc.keewedomain.persistence.domain.user.User;
import ccc.keewedomain.persistence.domain.user.enums.VendorType;
import ccc.keewedomain.persistence.repository.challenge.ChallengeParticipationRepository;
import ccc.keewedomain.persistence.repository.challenge.ChallengeRepository;
import ccc.keewedomain.persistence.repository.insight.DrawerRepository;
import ccc.keewedomain.persistence.repository.insight.InsightQueryRepository;
import ccc.keewedomain.persistence.repository.insight.InsightRepository;
import ccc.keewedomain.persistence.repository.insight.ReactionAggregationRepository;
import ccc.keewedomain.persistence.repository.user.UserRepository;
import ccc.keewedomain.utils.DatabaseCleaner;
import ccc.keeweinfra.KeeweInfraApplication;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;

import java.util.List;
import java.util.stream.Collectors;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertAll;

@SpringBootTest(classes = {KeeweDomainApplication.class, KeeweInfraApplication.class})
@TestPropertySource(properties = {"spring.config.location = classpath:application-domain.yml"})
@ActiveProfiles("test")
public class InsightDomainServiceTest {

@Autowired
InsightDomainService insightDomainService;

@Autowired
UserRepository userRepository;

@Autowired
InsightRepository insightRepository;

@Autowired
InsightQueryRepository insightQueryRepository;

@Autowired
ChallengeRepository challengeRepository;

@Autowired
ChallengeParticipationRepository challengeParticipationRepository;

@Autowired
ReactionAggregationRepository reactionAggregationRepository;

@Autowired
DrawerRepository drawerRepository;

@Autowired
DatabaseCleaner databaseCleaner;

User user = User.from(UserSignUpDto.of("vendorId", VendorType.NAVER, "[email protected]", null, null));
Insight insight = Insight.of(user, null, null, "인사이트 내용", Link.of("https://naver.com"), false);
Challenge challenge = Challenge.of(user, "챌린지", "개발", "챌린지의 소개입니다.");
ChallengeParticipation challengeParticipation = challenge.participate(user, "참가자 토픽", 2, 3);

@BeforeEach
void setup() {
userRepository.save(user);
insightRepository.save(insight);
challengeRepository.save(challenge);
}

@AfterEach
void clean() {
databaseCleaner.execute();
}

@Test
@DisplayName("챌린지 기록 없이 인사이트 생성")
void create_without_participate() {
//given
InsightCreateDto dto = InsightCreateDto.of(user.getId(), "인사이트 내용", "https://comic.naver.com", false, null);
//when
Insight insight = insightDomainService.create(dto);

//then
assertAll(
() -> assertThat(insight.isValid()).isFalse(),
() -> assertThat(insightRepository.findById(insight.getId())).isPresent()
);
}

@Test
@DisplayName("챌린지 기록하면서 인사이트 생성")
void create_with_participate() {
//given
InsightCreateDto dto = InsightCreateDto.of(user.getId(), "인사이트 내용", "https://comic.naver.com", true, null);
//when
Insight newInsight = insightDomainService.create(dto);

//then
assertAll(
() -> assertThat(newInsight.isValid()).isTrue(),
() -> assertThat(insightRepository.findById(newInsight.getId())).isPresent(),
() -> assertThat(insightQueryRepository.countValidForParticipation(newInsight.getChallengeParticipation()))
.isEqualTo(1L)
);
}

@Test
@DisplayName("이번 주 목표 기록 완료 시 기록 불가능")
void valid_false_if_completed() {
//given
List<InsightCreateDto> dtos = List.of(
InsightCreateDto.of(user.getId(), "인사이트 내용1", "https://comic.naver.com", true, null),
InsightCreateDto.of(user.getId(), "인사이트 내용2", "https://comic.naver.com", true, null),
InsightCreateDto.of(user.getId(), "인사이트 내용3", "https://comic.naver.com", true, null)
);

//when
List<Insight> insights = dtos.stream()
.map(dto -> insightDomainService.create(dto))
.collect(Collectors.toList());

Insight insight1 = insights.get(0);
Insight insight2 = insights.get(1);
Insight insight3 = insights.get(2);

//then
assertAll(
() -> assertThat(insight1.isValid()).isTrue(),
() -> assertThat(insight2.isValid()).isTrue(),
() -> assertThat(insight3.isValid()).isFalse(),
() -> assertThat(insightQueryRepository.countValidForParticipation(insight3.getChallengeParticipation()))
.isEqualTo(2L)
);
}

@Test
@DisplayName("서랍이 존재하지 않으면 실패")
void throw_if_drawer_not_exist() {
//given
InsightCreateDto dto = InsightCreateDto.of(user.getId(), "인사이트 내용", "https://comic.naver.com", true, 9999L);

//when, then
assertThatThrownBy(() -> insightDomainService.create(dto))
.isExactlyInstanceOf(KeeweException.class)
.hasMessage(KeeweRtnConsts.ERR440.getDescription());
}

@Test
@DisplayName("자신의 서랍이 아니면 실패")
void throw_if_not_owner_of_drawer() {
//given
User other = User.from(UserSignUpDto.of("vendorId222", VendorType.NAVER, "[email protected]", null, null));
userRepository.save(other);
Drawer drawer = drawerRepository.save(Drawer.of(other, "서랍"));
InsightCreateDto dto = InsightCreateDto.of(user.getId(), "인사이트 내용", "https://comic.naver.com", true, drawer.getId());

//when, then
assertThatThrownBy(() -> insightDomainService.create(dto))
.isExactlyInstanceOf(KeeweException.class)
.hasMessage(KeeweRtnConsts.ERR444.getDescription());
}
}