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

Feature/세미나 qa 수정사항 #381

Merged
merged 7 commits into from
Oct 8, 2023
4 changes: 2 additions & 2 deletions src/docs/asciidoc/seminar/seminar.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ include::{snippets}/delete-seminar/request-cookies.adoc[]

include::{snippets}/delete-seminar/http-response.adoc[]

== *가장 최근에 마감된 세미나 조회*
== *지난 세미나 중 가장 최근의 세미나 조회*

NOTE: 어제까지의 세미나 중, 가장 현재와 가깝고 마감된 세미나를 조회합니다.
NOTE: 어제까지의 세미나 중, 가장 현재와 가까운 세미나 1개를 조회합니다.

=== 요청

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static com.keeper.homepage.domain.member.entity.embedded.StudentId.MAX_STUDENT_ID_LENGTH;
import static com.keeper.homepage.domain.member.entity.rank.MemberRank.MemberRankType.일반회원;
import static com.keeper.homepage.domain.member.entity.type.MemberType.MemberTypeEnum.정회원;
import static com.keeper.homepage.domain.member.entity.type.MemberType.getMemberTypeBy;
import static jakarta.persistence.CascadeType.ALL;
import static jakarta.persistence.CascadeType.REMOVE;
import static jakarta.persistence.FetchType.LAZY;
Expand Down Expand Up @@ -37,6 +38,7 @@
import com.keeper.homepage.domain.member.entity.post.MemberReadPost;
import com.keeper.homepage.domain.member.entity.rank.MemberRank;
import com.keeper.homepage.domain.member.entity.type.MemberType;
import com.keeper.homepage.domain.member.entity.type.MemberType.MemberTypeEnum;
import com.keeper.homepage.domain.point.entity.PointLog;
import com.keeper.homepage.domain.post.entity.Post;
import com.keeper.homepage.domain.seminar.entity.Seminar;
Expand Down Expand Up @@ -197,7 +199,7 @@ private Member(Profile profile, Integer point, Integer level, Integer totalAtten
this.point = point;
this.level = level;
this.totalAttendance = totalAttendance;
this.memberType = MemberType.getMemberTypeBy(정회원);
this.memberType = getMemberTypeBy(정회원);
this.memberRank = MemberRank.getMemberRankBy(일반회원);
this.assignJob(MemberJobType.ROLE_회원);
}
Expand Down Expand Up @@ -437,4 +439,8 @@ public boolean hasAnyBorrowBooks() {
return this.bookBorrowInfos.stream()
.anyMatch(BookBorrowInfo::isInBorrowing);
}

public boolean isType(MemberTypeEnum memberTypeEnum) {
return this.memberType.getType() == memberTypeEnum;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.keeper.homepage.domain.seminar.application;

import static com.keeper.homepage.domain.member.entity.type.MemberType.MemberTypeEnum.정회원;
import static com.keeper.homepage.domain.seminar.entity.SeminarAttendanceStatus.SeminarAttendanceStatusType.BEFORE_ATTENDANCE;
import static com.keeper.homepage.domain.seminar.entity.SeminarAttendanceStatus.SeminarAttendanceStatusType.LATENESS;
import static com.keeper.homepage.domain.seminar.entity.SeminarAttendanceStatus.SeminarAttendanceStatusType.PERSONAL;
import static com.keeper.homepage.domain.seminar.entity.SeminarAttendanceStatus.getSeminarAttendanceStatusBy;
import static com.keeper.homepage.global.error.ErrorCode.SEMINAR_ATTENDANCE_ATTEMPT_NOT_AVAILABLE;
import static com.keeper.homepage.global.error.ErrorCode.SEMINAR_ATTENDANCE_CODE_NOT_AVAILABLE;
import static com.keeper.homepage.global.error.ErrorCode.SEMINAR_ATTENDANCE_DUPLICATE;
Expand Down Expand Up @@ -47,8 +49,8 @@ public class SeminarAttendanceService {
@Transactional
public SeminarAttendanceResponse attendance(Long seminarId, Member member, String attendanceCode) {
Seminar seminar = validSeminarFindService.findById(seminarId);
SeminarAttendance seminarAttendance = attendanceRepository.findBySeminarAndMember(seminar, member)
.orElseThrow(() -> new BusinessException(member.getRealName(), "member", SEMINAR_ATTENDANCE_UNABLE));

SeminarAttendance seminarAttendance = getSeminarAttendance(seminar, member);

String key = "seminar:" + seminar.getId() + ":memberId:" + member.getId();
checkAttemptNumberLimit(key);
Expand All @@ -60,6 +62,18 @@ public SeminarAttendanceResponse attendance(Long seminarId, Member member, Strin
return SeminarAttendanceResponse.of(seminarAttendance);
}

private SeminarAttendance getSeminarAttendance(Seminar seminar, Member member) {
if (!attendanceRepository.existsBySeminarAndMember(seminar, member) && member.isType(정회원)) {
return attendanceRepository.save(SeminarAttendance.builder()
.seminar(seminar)
.member(member)
.seminarAttendanceStatus(getSeminarAttendanceStatusBy(BEFORE_ATTENDANCE))
.build());
}
return attendanceRepository.findBySeminarAndMember(seminar, member)
.orElseThrow(() -> new BusinessException(member.getRealName(), "member", SEMINAR_ATTENDANCE_UNABLE));
}

private void checkAttemptNumberLimit(String key) {
int attemptNumber = redisUtil.increaseAndGetWithExpire(key, ONE_HOUR).intValue();
if (attemptNumber > MAX_ATTEMPT_COUNT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public SeminarIdResponse save(LocalDate openDate) {
.seminar(seminar)
.member(member)
.seminarAttendanceStatus(getSeminarAttendanceStatusBy(BEFORE_ATTENDANCE))
.attendTime(openDate.atStartOfDay())
.build());
});
return new SeminarIdResponse(seminar.getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public interface SeminarRepository extends JpaRepository<Seminar, Long> {
@Query("SELECT s FROM Seminar s "
+ "WHERE s.id <> 1 " // virtual seminar data 제외
+ "AND DATE(s.openTime) < :localDate "
+ "AND DATE(s.latenessCloseTime) < :localDate "
+ "ORDER BY s.openTime DESC "
+ "LIMIT 1")
Optional<Seminar> findRecentlyDoneSeminar(@Param("localDate") LocalDate localDate);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.keeper.homepage.domain.seminar.application;

import static com.keeper.homepage.domain.member.entity.type.MemberType.MemberTypeEnum.정회원;
import static com.keeper.homepage.domain.member.entity.type.MemberType.MemberTypeEnum.휴면회원;
import static com.keeper.homepage.domain.member.entity.type.MemberType.getMemberTypeBy;
import static com.keeper.homepage.domain.seminar.entity.SeminarAttendanceStatus.SeminarAttendanceStatusType.ABSENCE;
import static com.keeper.homepage.domain.seminar.entity.SeminarAttendanceStatus.SeminarAttendanceStatusType.BEFORE_ATTENDANCE;
import static com.keeper.homepage.domain.seminar.entity.SeminarAttendanceStatus.SeminarAttendanceStatusType.LATENESS;
Expand All @@ -8,13 +11,16 @@
import static com.keeper.homepage.global.error.ErrorCode.SEMINAR_ATTENDANCE_CODE_NOT_AVAILABLE;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

import com.keeper.homepage.IntegrationTest;
import com.keeper.homepage.domain.member.entity.Member;
import com.keeper.homepage.domain.seminar.entity.Seminar;
import com.keeper.homepage.domain.seminar.entity.SeminarAttendance;
import com.keeper.homepage.global.error.BusinessException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -94,4 +100,36 @@ class ChangeAttendanceStatusTest {
assertThat(findSeminarAttendance.getSeminarAttendanceExcuse()).isNull();
}
}

@Nested
@DisplayName("세미나 출석 테스트")
class SeminarAttendanceTest {

private Member admin, member;

@BeforeEach
void setUp() {
admin = memberTestHelper.generate();
member = memberTestHelper.generate();
}

@Test
@DisplayName("세미나 생성 당시 정회원이 아니었던 회원도 세미나 출석을 성공해야 한다.")
public void 세미나_생성_당시_정회원이_아니었던_회원도_세미나_출석을_성공해야_한다() throws Exception {
//given
member.updateType(getMemberTypeBy(휴면회원));
Long seminarId = seminarService.save(LocalDate.now()).id();
String attendanceCode = seminarService.start(admin, seminarId, LocalDateTime.now().plusMinutes(5),
LocalDateTime.now().plusMinutes(10)).attendanceCode();
em.flush();
em.clear();

//when & then
member = memberRepository.findById(member.getId()).orElseThrow();
member.updateType(getMemberTypeBy(정회원));
assertDoesNotThrow(() -> {
seminarAttendanceService.attendance(seminarId, member, attendanceCode);
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,6 @@ public class SeminarServiceTest extends IntegrationTest {
@DisplayName("가장 최근에 마감된 세미나 조회 테스트")
class GetRecentlyDoneSeminarTest {


@Test
@DisplayName("지각 마감시간이 지난 세미나를 불러와야 한다.")
public void 지각_마감시간이_지난_세미나를_불러와야_한다() throws Exception {
//given
Long ongoingSeminarId = seminarTestHelper.builder()
.openTime(LocalDateTime.now().minusDays(2))
.latenessCloseTime(LocalDateTime.now().plusDays(1))
.build()
.getId();
Long doneSeminarId = seminarTestHelper.builder()
.openTime(LocalDateTime.now().minusDays(1))
.latenessCloseTime(LocalDateTime.now().minusDays(1))
.build()
.getId();

//when
Long seminarId = seminarService.getRecentlyDoneSeminar().id();

//then
assertThat(seminarId).isEqualTo(doneSeminarId);
}

@Test
@DisplayName("오늘 날짜의 세미나는 불러오면 안된다.")
public void 오늘_날짜의_세미나는_불러오면_안된다() throws Exception {
Expand All @@ -66,8 +43,8 @@ class GetRecentlyDoneSeminarTest {
}

@Test
@DisplayName("마감된 세미나 중 시작시간 기준으로 현재와 가장 가까운 세미나를 불러와야 한다.")
public void 마감된_세미나_중_시작시간_기준으로_현재와_가장_가까운_세미나를_불러와야_한다() throws Exception {
@DisplayName("openTime 기준으로 현재와 가장 가까운 세미나를 불러와야 한다.")
public void openTime_기준으로_현재와_가장_가까운_세미나를_불러와야_한다() throws Exception {
seminarTestHelper.builder()
.openTime(LocalDateTime.now().minusDays(2))
.latenessCloseTime(LocalDateTime.now().minusDays(2))
Expand Down