Skip to content

Commit

Permalink
v0.1.2
Browse files Browse the repository at this point in the history
v0.1.2
  • Loading branch information
char-yb authored Aug 27, 2024
2 parents e80c6de + a8f8680 commit 6012ee1
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public MemberInfoResponse findMemberInfo(Long memberId) {

@Transactional(readOnly = true)
public void checkNickname(NicknameCheckRequest request) {
memberUtil.checkNickname(request);
final Member currentMember = memberUtil.getCurrentMember();
memberUtil.checkNickname(request, currentMember);
}

public void modifyMemberProfile(MemberProfileUpdateRequest request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public interface MemberRepositoryCustom {

boolean existsByProfileNickname(String nickname);
boolean existsByProfileNickname(String nickname, String currentNickname);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ public class MemberRepositoryImpl implements MemberRepositoryCustom {
private final JPAQueryFactory jpaQueryFactory;

@Override
public boolean existsByProfileNickname(String nickname) {
public boolean existsByProfileNickname(String nickname, String currentNickname) {
// 존재하는 경우의 쿼리
return jpaQueryFactory
.selectOne()
.from(member)
.where(isProfileNickname(nickname).and(isNotEmptyProfileNickname()))
.where(
isProfileNickname(nickname)
.and(isNotEmptyProfileNickname())
.and(isMyNickname(currentNickname)))
.fetchFirst()
!= null;
}
Expand All @@ -30,4 +33,8 @@ private BooleanExpression isProfileNickname(String nickname) {
private BooleanExpression isNotEmptyProfileNickname() {
return member.profile.nickname.ne("");
}

private BooleanExpression isMyNickname(String currentNickname) {
return member.profile.nickname.ne(currentNickname);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.depromeet.stonebed.domain.missionRecord.application.MissionRecordService;
import com.depromeet.stonebed.domain.missionRecord.dto.request.MissionRecordBoostRequest;
import com.depromeet.stonebed.domain.missionRecord.dto.request.MissionRecordCalendarRequest;
import com.depromeet.stonebed.domain.missionRecord.dto.request.MissionRecordSaveRequest;
import com.depromeet.stonebed.domain.missionRecord.dto.request.MissionRecordStartRequest;
import com.depromeet.stonebed.domain.missionRecord.dto.response.MissionRecordCalendarResponse;
Expand All @@ -12,8 +13,6 @@
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -57,22 +56,9 @@ public void deleteMissionRecord(@PathVariable Long recordId) {
@Operation(summary = "캘린더 형식의 미션 기록 조회", description = "회원의 미션 기록을 페이징하여 조회한다.")
@GetMapping("/calendar")
public MissionRecordCalendarResponse getMissionRecordsForCalendar(
@Parameter(description = "커서 위치", example = "2024-01-01")
@Valid
@RequestParam(required = false)
String cursor,
@Parameter(description = "페이지 당 항목 수", example = "30")
@Valid
@RequestParam
@NotNull
@Min(1)
int limit,
@Parameter(description = "조회할 memberId", example = "1")
@Valid
@RequestParam(required = false)
Long memberId) {
@Valid MissionRecordCalendarRequest request) {

return missionRecordService.getMissionRecordsForCalendar(cursor, limit, memberId);
return missionRecordService.getMissionRecordsForCalendar(request);
}

@Operation(summary = "수행한 총 미션 기록 수", description = "회원이 수행한 총 미션 기록 수를 조회한다.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord;
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecordBoost;
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecordStatus;
import com.depromeet.stonebed.domain.missionRecord.dto.request.MissionRecordCalendarRequest;
import com.depromeet.stonebed.domain.missionRecord.dto.response.MissionRecordCalendarDto;
import com.depromeet.stonebed.domain.missionRecord.dto.response.MissionRecordCalendarResponse;
import com.depromeet.stonebed.domain.missionRecord.dto.response.MissionRecordCompleteTotal;
Expand Down Expand Up @@ -84,6 +85,19 @@ public void saveMission(Long missionId, String content) {
MissionHistory missionHistory =
findMissionHistoryByIdAndRaisePet(missionId, mission.getRaisePet());

LocalDate today = LocalDate.now();
boolean recordExists =
missionRecordRepository.existsByMemberAndMissionHistoryAndStatusAndCreatedAtBetween(
member,
missionHistory,
MissionRecordStatus.COMPLETED,
today.atStartOfDay(),
today.plusDays(1).atStartOfDay());

if (recordExists) {
throw new CustomException(ErrorCode.DUPLICATE_MISSION_RECORD);
}

MissionRecord missionRecord =
missionRecordRepository
.findByMemberAndMissionHistory(member, missionHistory)
Expand Down Expand Up @@ -130,15 +144,15 @@ private MissionHistory findMissionHistoryByIdAndRaisePet(Long missionId, RaisePe

@Transactional(readOnly = true)
public MissionRecordCalendarResponse getMissionRecordsForCalendar(
String cursor, int limit, Long memberId) {
MissionRecordCalendarRequest request) {
Long findMemberId =
Optional.ofNullable(memberId)
Optional.ofNullable(request.memberId())
.orElseGet(() -> memberUtil.getCurrentMember().getId());

Pageable pageable = createPageable(limit);
List<MissionRecord> records = getMissionRecords(cursor, findMemberId, pageable);
Pageable pageable = createPageable(request.limit());
List<MissionRecord> records = getMissionRecords(request.cursor(), findMemberId, pageable);
List<MissionRecordCalendarDto> calendarData = convertToCalendarDto(records);
String nextCursor = getNextCursor(records);
String nextCursor = getNextCursor(records, request.limit());

return MissionRecordCalendarResponse.from(calendarData, nextCursor);
}
Expand Down Expand Up @@ -167,14 +181,19 @@ private List<MissionRecord> getMissionRecords(String cursor, Long memberId, Page
}
}

private String getNextCursor(List<MissionRecord> records) {
private String getNextCursor(List<MissionRecord> records, int limit) {
if (records.size() < limit) {
return null;
}
return String.valueOf(getLastRecordId(records));
}

private Long getLastRecordId(List<MissionRecord> records) {
if (records.isEmpty()) {
return null;
}

MissionRecord lastRecord = records.get(records.size() - 1);
LocalDate nextCursorDate = lastRecord.getCreatedAt().toLocalDate().plusDays(1);
return nextCursorDate.format(DATE_FORMATTER);
return records.get(records.size() - 1).getId();
}

@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ List<MissionRecord> findAllByCreatedAtBetweenAndStatusNot(

List<MissionRecord> findByIdIn(List<Long> ids);

boolean existsByMemberAndMissionHistoryAndStatusAndCreatedAtBetween(
Member member,
MissionHistory missionHistory,
MissionRecordStatus status,
LocalDateTime startDateTime,
LocalDateTime endDateTime);

@Modifying
@Query(
"UPDATE MissionRecord mr SET mr.deletedAt = CURRENT_TIMESTAMP WHERE mr.member.id = :memberId")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public List<MissionRecord> findByMemberIdAndCreatedAtFromWithPagination(
Long memberId, LocalDateTime createdAt, Pageable pageable) {
return queryFactory
.selectFrom(missionRecord)
.where(missionRecord.member.id.eq(memberId).and(createdAtFrom(createdAt)))
.where(isMemberId(memberId).and(createdAtFrom(createdAt)).and(isCompleted()))
.orderBy(missionRecord.createdAt.asc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
Expand Down Expand Up @@ -62,4 +62,8 @@ private BooleanExpression isMemberId(Long memberId) {
private BooleanExpression createdAtFrom(LocalDateTime createdAt) {
return missionRecord.createdAt.goe(createdAt);
}

private BooleanExpression isCompleted() {
return missionRecord.status.eq(MissionRecordStatus.COMPLETED);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.depromeet.stonebed.domain.missionRecord.dto.request;

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

public record MissionRecordCalendarRequest(
@Schema(description = "커서 위치", example = "2024-01-01") String cursor,
@Schema(description = "페이지 당 항목 수", example = "30") @NotNull @Min(1) int limit,
@Schema(description = "조회할 memberId", example = "1") Long memberId) {}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public enum ErrorCode {
MISSION_HISTORY_NOT_FOUNT(HttpStatus.NOT_FOUND, "해당 일별 미션 정보를 찾을 수 없습니다."),
MISSION_RECORD_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 미션 기록을 찾을 수 없습니다."),
NO_AVAILABLE_TODAY_MISSION(HttpStatus.INTERNAL_SERVER_ERROR, "할당 가능한 오늘의 미션이 없습니다."),
DUPLICATE_MISSION_RECORD(HttpStatus.BAD_REQUEST, "오늘 완료한 미션이 존재합니다."),

// image
IMAGE_KEY_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 이미지를 찾을 수 없습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public String getMemberRole() {
}

@Transactional(readOnly = true)
public void checkNickname(NicknameCheckRequest request) {
validateNicknameNotDuplicate(request.nickname());
public void checkNickname(NicknameCheckRequest request, Member currentMember) {
validateNicknameNotDuplicate(request.nickname(), currentMember.getProfile().getNickname());
if (validateNicknameText(request.nickname())) {
throw new CustomException(ErrorCode.MEMBER_INVALID_NICKNAME);
}
Expand All @@ -50,8 +50,8 @@ private boolean validateNicknameText(String nickname) {
return nickname == null || nickname.length() < 2 || nickname.length() > 14;
}

private void validateNicknameNotDuplicate(String nickname) {
if (memberRepository.existsByProfileNickname(nickname)) {
private void validateNicknameNotDuplicate(String nickname, String currentNickname) {
if (memberRepository.existsByProfileNickname(nickname, currentNickname)) {
throw new CustomException(ErrorCode.MEMBER_ALREADY_NICKNAME);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ class MemberServiceTest extends FixtureMonkeySetUp {
@Test
void 닉네임을_검증한다() {
// given
Member member = fixtureMonkey.giveMeOne(Member.class);
when(memberUtil.getCurrentMember()).thenReturn(member);
NicknameCheckRequest request = fixtureMonkey.giveMeOne(NicknameCheckRequest.class);

// when
memberService.checkNickname(request);

// then
verify(memberUtil).checkNickname(request);
verify(memberUtil).checkNickname(request, member);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord;
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecordBoost;
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecordStatus;
import com.depromeet.stonebed.domain.missionRecord.dto.request.MissionRecordCalendarRequest;
import com.depromeet.stonebed.domain.missionRecord.dto.response.MissionRecordCalendarResponse;
import com.depromeet.stonebed.domain.missionRecord.dto.response.MissionRecordCompleteTotal;
import com.depromeet.stonebed.domain.missionRecord.dto.response.MissionTabResponse;
Expand Down Expand Up @@ -132,10 +133,13 @@ class MissionRecordServiceTest extends FixtureMonkeySetUp {
String cursor = null;
int limit = 5;

MissionRecordCalendarRequest request =
new MissionRecordCalendarRequest(cursor, limit, null);

// when
MissionRecordCalendarResponse response =
missionRecordService.getMissionRecordsForCalendar(
cursor, limit, null); // Pass null for memberId
request); // Pass null for memberId

// then
then(response).isNotNull();
Expand All @@ -160,9 +164,12 @@ class MissionRecordServiceTest extends FixtureMonkeySetUp {
String cursor = null;
int limit = 5;

MissionRecordCalendarRequest request =
new MissionRecordCalendarRequest(cursor, limit, member.getId());

// when
MissionRecordCalendarResponse response =
missionRecordService.getMissionRecordsForCalendar(cursor, limit, member.getId());
missionRecordService.getMissionRecordsForCalendar(request);

// then
then(response).isNotNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,50 +98,61 @@ class MemberUtilTest extends FixtureMonkeySetUp {
@Test
void checkNickname_성공() {
// given
Member member = fixtureMonkey.giveMeOne(Member.class);
String nickname = "validNickname";
NicknameCheckRequest request = new NicknameCheckRequest(nickname);
when(memberRepository.existsByProfileNickname(nickname)).thenReturn(false);
when(memberRepository.existsByProfileNickname(nickname, member.getProfile().getNickname()))
.thenReturn(false);

// when & then
assertDoesNotThrow(() -> memberUtil.checkNickname(request));
assertDoesNotThrow(() -> memberUtil.checkNickname(request, member));
}

@Test
void checkNickname_실패_MEMBER_ALREADY_NICKNAME() {
// given
Member member = fixtureMonkey.giveMeOne(Member.class);
String nickname = "duplicateNickname";
NicknameCheckRequest request = new NicknameCheckRequest(nickname);
when(memberRepository.existsByProfileNickname(nickname)).thenReturn(true);
when(memberRepository.existsByProfileNickname(nickname, member.getProfile().getNickname()))
.thenReturn(true);

// when & then
CustomException exception =
assertThrows(CustomException.class, () -> memberUtil.checkNickname(request));
assertThrows(
CustomException.class, () -> memberUtil.checkNickname(request, member));
assertEquals(ErrorCode.MEMBER_ALREADY_NICKNAME, exception.getErrorCode());
}

@Test
void checkNickname_실패_MEMBER_INVALID_NICKNAME_길이_1() {
// given
Member member = fixtureMonkey.giveMeOne(Member.class);
String nickname = "a";
NicknameCheckRequest request = new NicknameCheckRequest(nickname);
when(memberRepository.existsByProfileNickname(nickname)).thenReturn(false);
when(memberRepository.existsByProfileNickname(nickname, member.getProfile().getNickname()))
.thenReturn(false);

// when & then
CustomException exception =
assertThrows(CustomException.class, () -> memberUtil.checkNickname(request));
assertThrows(
CustomException.class, () -> memberUtil.checkNickname(request, member));
assertEquals(ErrorCode.MEMBER_INVALID_NICKNAME, exception.getErrorCode());
}

@Test
void checkNickname_실패_MEMBER_INVALID_NICKNAME_길이_15() {
// given
Member member = fixtureMonkey.giveMeOne(Member.class);
String nickname = "a".repeat(15);
NicknameCheckRequest request = new NicknameCheckRequest(nickname);
when(memberRepository.existsByProfileNickname(nickname)).thenReturn(false);
when(memberRepository.existsByProfileNickname(nickname, member.getProfile().getNickname()))
.thenReturn(false);

// when & then
CustomException exception =
assertThrows(CustomException.class, () -> memberUtil.checkNickname(request));
assertThrows(
CustomException.class, () -> memberUtil.checkNickname(request, member));
assertEquals(ErrorCode.MEMBER_INVALID_NICKNAME, exception.getErrorCode());
}
}

0 comments on commit 6012ee1

Please sign in to comment.