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

[CI/CD] dev 브랜치 최신화 반영하여 배포 #57

Merged
merged 5 commits into from
Jan 31, 2025
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 @@ -3,6 +3,8 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

import java.time.LocalDateTime;

@Schema(title = "메모 생성 요청 형식")
public record MemoCreateRequest(

Expand All @@ -11,7 +13,12 @@ public record MemoCreateRequest(

@NotNull(message = "진도율은 필수입니다.")
@Schema(description = "독서 진도율")
int gauge
int gauge,

@NotNull(message = "단말 시간은 필수입니다.")
@Schema(description = "사용자 단말 시간 (ISO-8601 형식)",
example = "2024-01-30T12:34:56")
LocalDateTime deviceTime
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ public record MemoResponse(
@Schema(description = "수정 일시")
LocalDateTime updatedAt,
@Schema(description = "기록 객체 ID")
Long recordId
Long recordId,
@Schema(description = "얻은 경험치")
int acquiredExp
) {
// Memo -> Dto
public static MemoResponse from(Memo memo, Long recordId) {
Expand All @@ -30,7 +32,8 @@ public static MemoResponse from(Memo memo, Long recordId) {
memo.getGauge(),
memo.getCreatedAt(),
memo.getUpdatedAt(),
recordId
recordId,
memo.getAcquiredExp()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.cmc.mercury.domain.memo.entity.Memo;
import com.cmc.mercury.domain.record.entity.RecordDetail;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

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

Expand All @@ -13,6 +15,10 @@ public interface MemoRepository extends JpaRepository<Memo, Long> {

// RecordDetail의 모든 Memo들을 찾아서 업데이트 순으로 정렬 후 최상단 반환
Optional<Memo> findTopByRecordDetailOrderByUpdatedAtDesc(RecordDetail recordDetail);

// RecordDetail의 모든 Memo들을 찾아서 생성 순으로 정렬 후 반환
List<Memo> findAllByRecordDetailOrderByCreatedAtDesc(RecordDetail recordDetail);

int countByRecordDetail_Record_User_TestUserIdAndCreatedAtBetweenAndIsFirstMemoFalse(
Long userTestId, LocalDateTime startOfDay, LocalDateTime deviceTime);
}
44 changes: 44 additions & 0 deletions src/main/java/com/cmc/mercury/domain/memo/service/MemoService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,50 @@
import com.cmc.mercury.domain.record.entity.Record;
import com.cmc.mercury.domain.record.entity.RecordDetail;
import com.cmc.mercury.domain.record.repository.RecordRepository;
import com.cmc.mercury.domain.user.entity.User;
import com.cmc.mercury.domain.user.service.UserTestService;
import com.cmc.mercury.global.exception.CustomException;
import com.cmc.mercury.global.exception.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Service
@RequiredArgsConstructor
@Slf4j
public class MemoService {

private static final int FIRST_EXP = 50;
private static final int NORMAL_EXP = 10;
private static final int MAX_DAILY_COUNT = 5;

private final MemoRepository memoRepository;
private final RecordRepository recordRepository;
private final UserTestService userTestService;

@Transactional
public MemoResponse createMemo(Long testUserId, Long recordId, MemoCreateRequest request) {

User user = userTestService.getOrCreateTestUser(testUserId);

// Record와 RecordDetail을 함께 조회 (Record가 없으면 RecordDetail도 없음)
Record record = recordRepository.findByIdAndUser_TestUserId(recordId, testUserId)
.orElseThrow(() -> new CustomException(ErrorCode.RECORD_NOT_FOUND));

RecordDetail recordDetail = record.getRecordDetail();

// 메모 추가 경험치 계산
int acquiredExp = calculateMemoExp(testUserId, request.deviceTime());

// Memo 생성 (아직 연관관계 설정 전)
Memo memo = Memo.builder()
.content(request.content())
.gauge(request.gauge())
.acquiredExp(acquiredExp)
.isFirstMemo(false)
.build();

// 연관관계 설정
Expand All @@ -50,10 +66,33 @@ public MemoResponse createMemo(Long testUserId, Long recordId, MemoCreateRequest
// 메모의 updatedAt으로 record와 recordDetail 업데이트
record.updateLastModifiedDateWithDetail(savedMemo.getUpdatedAt());

// 사용자 경험치 업데이트
user.updateExp(user.getExp() + acquiredExp);

return MemoResponse.from(savedMemo, recordId);
}

private int calculateMemoExp(Long testUserId, LocalDateTime deviceTime) {

LocalDateTime startOfDay = deviceTime.toLocalDate().atStartOfDay();

// 오늘 추가된 메모 수 계산
int addedMemoCount = memoRepository
.countByRecordDetail_Record_User_TestUserIdAndCreatedAtBetweenAndIsFirstMemoFalse(
testUserId, startOfDay, deviceTime);

if (addedMemoCount == 0) {
return FIRST_EXP;
}

if (addedMemoCount >= MAX_DAILY_COUNT) {
return 0;
}

return NORMAL_EXP;
}


@Transactional
public MemoResponse updateMemo(Long testUserId, Long recordId, Long memoId, MemoUpdateRequest request) {

Expand All @@ -73,8 +112,13 @@ public MemoResponse updateMemo(Long testUserId, Long recordId, Long memoId, Memo
@Transactional
public void deleteMemo(Long testUserId, Long recordId, Long memoId) {

// User user = userTestService.getOrCreateTestUser(testUserId);

Memo memo = validateAndGetMemo(testUserId, recordId, memoId);

// 사용자 경험치 차감
// user.updateExp(user.getExp() - memo.getAcquiredExp());

memo.getRecordDetail().getMemos().remove(memo);

memoRepository.delete(memo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

import java.time.LocalDateTime;

@Schema(title = "신규 기록 객체 생성 요청 형식")
public record RecordRequest (

Expand All @@ -16,7 +18,12 @@ public record RecordRequest (

// @NotNull(message = "진도율은 필수입니다.")
@Schema(description = "독서 진도율")
int gauge
int gauge,

@NotNull(message = "단말 시간은 필수입니다.")
@Schema(description = "사용자 단말 시간 (ISO-8601 형식)",
example = "2024-01-30T12:34:56")
LocalDateTime deviceTime
){

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ public record RecordResponse (
@Schema(description = "수정 일시")
LocalDateTime updatedAt,
@Schema(description = "도서 정보")
BookResponse book
BookResponse book,
@Schema(description = "얻은 경험치")
int acquiredExp
) {
public static RecordResponse of(Record record, RecordDetail detail, String content) {

Expand All @@ -31,7 +33,8 @@ public static RecordResponse of(Record record, RecordDetail detail, String conte
content,
record.getCreatedAt(),
record.getUpdatedAt(),
BookResponse.from(record.getBook())
BookResponse.from(record.getBook()),
record.getAcquiredExp()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

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

Expand Down Expand Up @@ -34,4 +35,10 @@ List<Record> searchRecordsByTitleOrMemoContent(
@Param("sortType") String sortType);

Optional<Record> findByUser_TestUserIdAndBook_Isbn13(Long testUserId, String isbn13);

boolean existsByUser_testUserIdAndCreatedAtBetween(
Long testUserId, LocalDateTime startOfDay, LocalDateTime deviceTime);

int countByUser_testUserIdAndCreatedAtBetween(
Long testUserId, LocalDateTime startOfDay, LocalDateTime deviceTime);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

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

@Service
@RequiredArgsConstructor
@Slf4j
public class RecordService {

private static final int FIRST_EXP = 50;
private static final int NORMAL_EXP = 10;
private static final int MAX_DAILY_COUNT = 5;

private final RecordRepository recordRepository;
private final BookRepository bookRepository;
private final MemoRepository memoRepository;
Expand All @@ -35,6 +40,10 @@ public class RecordService {
public RecordResponse createRecord(Long testUserId, RecordRequest request) {

User user = userTestService.getOrCreateTestUser(testUserId);

// 신규 독서기록 생성 경험치 계산
int acquiredExp = calculateRecordExp(testUserId, request.deviceTime());

// 저장되지 않은 도서면 저장
Book book = bookRepository.findByIsbn13(request.book().isbn13())
.orElseGet(() -> {
Expand All @@ -49,6 +58,7 @@ public RecordResponse createRecord(Long testUserId, RecordRequest request) {
Record record = Record.builder()
.user(user)
.book(book)
.acquiredExp(acquiredExp)
.build();
//* Record savedRecord = recordRepository.save(record);

Expand All @@ -64,6 +74,8 @@ public RecordResponse createRecord(Long testUserId, RecordRequest request) {
.content(request.content())
.gauge(request.gauge())
//* .recordDetail(savedRecordDetail)
.acquiredExp(0) // 신규 생성 시 메모는 경험치 없음
.isFirstMemo(true) // Record 생성 시의 메모는 첫 메모
.build();
//* Memo savedMemo = memoRepository.save(memo);

Expand All @@ -74,10 +86,30 @@ public RecordResponse createRecord(Long testUserId, RecordRequest request) {
// 저장 (cascade로 인해 record를 저장하면 recordDetail과 memo도 함께 저장됨)
Record savedRecord = recordRepository.save(record);

// 사용자 경험치 업데이트
user.updateExp(user.getExp() + acquiredExp);

//* return RecordResponse.of(record, recordDetail, savedMemo.getContent());
return RecordResponse.of(savedRecord, savedRecord.getRecordDetail(), memo.getContent());
}

private int calculateRecordExp(Long testUserId, LocalDateTime deviceTime) {

LocalDateTime startOfDay = deviceTime.toLocalDate().atStartOfDay();

boolean isFirstofDay = !recordRepository.existsByUser_testUserIdAndCreatedAtBetween(testUserId, startOfDay, deviceTime);
if (isFirstofDay) {
return FIRST_EXP;
}

int dailyRecordCount = recordRepository.countByUser_testUserIdAndCreatedAtBetween(testUserId, startOfDay, deviceTime);
if (dailyRecordCount >= MAX_DAILY_COUNT) { // 현재 생성하려는 기록 포함 안됨 => 등호 필요
return 0;
}
return NORMAL_EXP;
}


public RecordListResponse getRecordList(Long testUserId, RecordSortType sortType) {

// 유저의 모든 기록 객체를 정렬해서 조회
Expand Down Expand Up @@ -108,11 +140,19 @@ public RecordListResponse searchRecords(Long testUserId, RecordSortType sortType
@Transactional
public void deleteRecord(Long testUserId, Long recordId) {

// User user = userTestService.getOrCreateTestUser(testUserId)
User user = userTestService.getOrCreateTestUser(testUserId);

Record record = recordRepository.findByIdAndUser_TestUserId(recordId, testUserId)
.orElseThrow(() -> new CustomException(ErrorCode.RESOURCE_NOT_FOUND));

// 차감할 경험치 계산
/* int reduceExp = record.getAcquiredExp();
reduceExp += record.getRecordDetail().getMemos().stream()
.mapToInt(Memo::getAcquiredExp)
.sum();

user.updateExp(user.getExp() - reduceExp);*/

recordRepository.delete(record);
}

Expand Down