diff --git a/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultCreateRequestDto.java b/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultCreateRequestDto.java index be596769..42242692 100644 --- a/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultCreateRequestDto.java +++ b/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultCreateRequestDto.java @@ -4,6 +4,7 @@ import jakarta.validation.constraints.Size; import java.time.LocalDateTime; import org.hibernate.validator.constraints.Range; +import org.moonshot.server.global.common.model.validator.ValidLimitValue; import org.moonshot.server.global.common.model.validator.ValidTargetNumber; import org.springframework.format.annotation.DateTimeFormat; @@ -23,7 +24,8 @@ public record KeyResultCreateRequestDto( Short idx, @NotNull(message = "KR 목표 수치를 입력해주세요.") @ValidTargetNumber - Integer target, + @ValidLimitValue + Long target, @NotNull(message = "KR 목표 수치의 단위를 입력해주세요.") String metric, @NotNull(message = "KR 목표의 이전 수식을 입력해주세요.") diff --git a/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultCreateRequestInfoDto.java b/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultCreateRequestInfoDto.java index 45d23baf..aa856964 100644 --- a/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultCreateRequestInfoDto.java +++ b/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultCreateRequestInfoDto.java @@ -7,6 +7,7 @@ import java.util.List; import org.moonshot.server.domain.task.dto.request.TaskCreateRequestDto; import org.hibernate.validator.constraints.Range; +import org.moonshot.server.global.common.model.validator.ValidLimitValue; import org.moonshot.server.global.common.model.validator.ValidTargetNumber; import org.springframework.format.annotation.DateTimeFormat; @@ -24,7 +25,8 @@ public record KeyResultCreateRequestInfoDto( Short idx, @NotNull(message = "KR 목표 수치를 입력해주세요.") @ValidTargetNumber - Integer target, + @ValidLimitValue + Long target, @NotNull(message = "KR 목표 수치의 단위를 입력해주세요.") String metric, @NotNull(message = "KR 목표의 이전 수식을 입력해주세요.") diff --git a/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultModifyRequestDto.java b/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultModifyRequestDto.java index d1a818f9..3de56691 100644 --- a/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultModifyRequestDto.java +++ b/src/main/java/org/moonshot/server/domain/keyresult/dto/request/KeyResultModifyRequestDto.java @@ -4,6 +4,7 @@ import jakarta.validation.constraints.Size; import java.time.LocalDateTime; import org.moonshot.server.domain.keyresult.model.KRState; +import org.moonshot.server.global.common.model.validator.ValidLimitValue; import org.moonshot.server.global.common.model.validator.ValidTargetNumber; import org.springframework.format.annotation.DateTimeFormat; @@ -17,7 +18,10 @@ public record KeyResultModifyRequestDto( @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") LocalDateTime expireAt, @ValidTargetNumber - Integer target, - KRState state + @ValidLimitValue + Long target, + KRState state, + @Size(min = 1, max = 100, message = "본문은 100자 이하여야 합니다.") + String logContent ) { } diff --git a/src/main/java/org/moonshot/server/domain/keyresult/model/KeyResult.java b/src/main/java/org/moonshot/server/domain/keyresult/model/KeyResult.java index 682b3036..76e1e5ad 100644 --- a/src/main/java/org/moonshot/server/domain/keyresult/model/KeyResult.java +++ b/src/main/java/org/moonshot/server/domain/keyresult/model/KeyResult.java @@ -26,7 +26,7 @@ public class KeyResult { private Period period; @Column(nullable = false) - private Integer target; + private Long target; @Column(nullable = false) private Short idx; @@ -64,7 +64,7 @@ public void modifyIdx(Short idx) { this.idx = idx; } - public void modifyTarget(Integer target) { + public void modifyTarget(Long target) { this.target = target; } diff --git a/src/main/java/org/moonshot/server/domain/keyresult/service/KeyResultService.java b/src/main/java/org/moonshot/server/domain/keyresult/service/KeyResultService.java index 339f72cf..bf65e6e9 100644 --- a/src/main/java/org/moonshot/server/domain/keyresult/service/KeyResultService.java +++ b/src/main/java/org/moonshot/server/domain/keyresult/service/KeyResultService.java @@ -11,10 +11,13 @@ import org.moonshot.server.domain.keyresult.exception.KeyResultNumberExceededException; import org.moonshot.server.domain.keyresult.model.KeyResult; import org.moonshot.server.domain.keyresult.repository.KeyResultRepository; +import org.moonshot.server.domain.log.repository.LogRepository; +import org.moonshot.server.domain.log.service.LogService; import org.moonshot.server.domain.objective.exception.ObjectiveNotFoundException; import org.moonshot.server.domain.objective.model.Objective; import org.moonshot.server.domain.objective.repository.ObjectiveRepository; import org.moonshot.server.domain.task.dto.request.TaskCreateRequestDto; +import org.moonshot.server.domain.task.model.Task; import org.moonshot.server.domain.task.repository.TaskRepository; import org.moonshot.server.domain.task.service.TaskService; import org.moonshot.server.domain.user.service.UserService; @@ -34,6 +37,8 @@ public class KeyResultService { private final TaskRepository taskRepository; private final TaskService taskService; private final UserService userService; + private final LogService logService; + private final LogRepository logRepository; //TODO // 여기 모든 로직에 User 관련 기능이 추가된 이후 @@ -52,8 +57,16 @@ public void createInitKRWithObjective(Objective objective, List Task.builder() + .title(task.title()) + .idx(task.idx()) + .keyResult(keyResult) + .build()).toList()); + for (TaskCreateRequestDto taskDto : dto.taskList()) { + taskService.saveTask(keyResult, taskDto); + } } } } @@ -75,7 +88,7 @@ public void createKeyResult(KeyResultCreateRequestDto request, Long userId) { for (short i = request.idx(); i < krList.size(); i++) { krList.get(i).incrementIdx(); } - keyResultRepository.save(KeyResult.builder() + KeyResult keyResult = keyResultRepository.save(KeyResult.builder() .objective(objective) .title(request.title()) .period(Period.of(request.startAt(), request.expireAt())) @@ -84,6 +97,7 @@ public void createKeyResult(KeyResultCreateRequestDto request, Long userId) { .metric(request.metric()) .descriptionBefore(request.descriptionBefore()) .descriptionAfter(request.descriptionAfter()).build()); + logService.createKRLog(request, keyResult.getId()); } @Transactional @@ -92,6 +106,7 @@ public void deleteKeyResult(Long keyResultId, Long userId) { .orElseThrow(KeyResultNotFoundException::new); userService.validateUserAuthorization(keyResult.getObjective().getUser(), userId); + logRepository.deleteAllInBatch(logRepository.findAllByKeyResult(keyResult)); taskRepository.deleteAllInBatch(taskRepository.findAllByKeyResult(keyResult)); keyResultRepository.delete(keyResult); } @@ -121,11 +136,15 @@ public void modifyKeyResult(KeyResultModifyRequestDto request, Long userId) { keyResult.modifyPeriod(Period.of(newStartAt, newExpireAt)); } if (request.target() != null) { + if (request.logContent() != null) { + logService.createUpdateLog(request, keyResult.getId()); + } keyResult.modifyTarget(request.target()); } if (request.state() != null) { keyResult.modifyState(request.state()); } + } } diff --git a/src/main/java/org/moonshot/server/domain/log/controller/LogController.java b/src/main/java/org/moonshot/server/domain/log/controller/LogController.java new file mode 100644 index 00000000..51b067b0 --- /dev/null +++ b/src/main/java/org/moonshot/server/domain/log/controller/LogController.java @@ -0,0 +1,29 @@ +package org.moonshot.server.domain.log.controller; + +import lombok.RequiredArgsConstructor; +import org.moonshot.server.domain.log.dto.request.LogCreateRequestDto; +import org.moonshot.server.domain.log.service.LogService; +import org.moonshot.server.global.auth.jwt.JwtTokenProvider; +import org.moonshot.server.global.common.response.ApiResponse; +import org.moonshot.server.global.common.response.SuccessType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.security.Principal; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/v1/log") +public class LogController { + + private final LogService logService; + + @PostMapping + public ApiResponse create(Principal principal, @RequestBody LogCreateRequestDto logCreateRequestDto) { + logService.createRecordLog(JwtTokenProvider.getUserIdFromPrincipal(principal), logCreateRequestDto); + return ApiResponse.success(SuccessType.POST_LOG_SUCCESS); + } + +} diff --git a/src/main/java/org/moonshot/server/domain/log/dto/request/LogCreateRequestDto.java b/src/main/java/org/moonshot/server/domain/log/dto/request/LogCreateRequestDto.java new file mode 100644 index 00000000..b00466ca --- /dev/null +++ b/src/main/java/org/moonshot/server/domain/log/dto/request/LogCreateRequestDto.java @@ -0,0 +1,18 @@ +package org.moonshot.server.domain.log.dto.request; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import org.moonshot.server.global.common.model.validator.ValidLimitValue; + +public record LogCreateRequestDto( + Long keyResultId, + + @NotNull(message = "Log의 수치를 입력해주세요.") + @ValidLimitValue + long logNum, + + @NotNull(message = "Log의 체크인 본문을 입력해주세요.") + @Size(min = 1, max = 100, message = "본문은 100자 이하여야 합니다.") + String logContent +) { +} diff --git a/src/main/java/org/moonshot/server/domain/log/model/Log.java b/src/main/java/org/moonshot/server/domain/log/model/Log.java index fdfed39c..b163dc4e 100644 --- a/src/main/java/org/moonshot/server/domain/log/model/Log.java +++ b/src/main/java/org/moonshot/server/domain/log/model/Log.java @@ -3,13 +3,17 @@ import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.DynamicInsert; import org.moonshot.server.domain.keyresult.model.KeyResult; +import org.moonshot.server.domain.user.model.SocialPlatform; +import org.moonshot.server.domain.user.model.User; import java.time.LocalDateTime; @Entity @Getter @Builder +@DynamicInsert @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PROTECTED) public class Log { @@ -26,11 +30,12 @@ public class Log { @Column(nullable = false) private LogState state; - @ColumnDefault("-1") - private int prevNum; + @Builder.Default + @Column(columnDefinition = "bigint default -1") + private long prevNum = -1; @Column(nullable = false) - private int currNum; + private long currNum; @Column(nullable = false) private String content; @@ -39,4 +44,14 @@ public class Log { @JoinColumn(name = "key_result_id") private KeyResult keyResult; + public static Log of(LocalDateTime date, LogState state, int prevNum, int currNum, String content, KeyResult keyResult) { + return Log.builder() + .date(date) + .state(state) + .prevNum(prevNum) + .currNum(currNum) + .keyResult(keyResult) + .build(); + } + } diff --git a/src/main/java/org/moonshot/server/domain/log/repository/LogRepository.java b/src/main/java/org/moonshot/server/domain/log/repository/LogRepository.java new file mode 100644 index 00000000..2651b2e8 --- /dev/null +++ b/src/main/java/org/moonshot/server/domain/log/repository/LogRepository.java @@ -0,0 +1,18 @@ +package org.moonshot.server.domain.log.repository; + +import org.moonshot.server.domain.keyresult.model.KeyResult; +import org.moonshot.server.domain.log.model.Log; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface LogRepository extends JpaRepository { + + List findAllByKeyResult(KeyResult keyResult); + + @Query("select l FROM Log l JOIN FETCH l.keyResult k WHERE l.keyResult.id = :keyResultId ORDER BY l.id DESC LIMIT 1") + List findLatestLogByKeyResultId(@Param("keyResultId") Long keyResultId); + +} diff --git a/src/main/java/org/moonshot/server/domain/log/service/LogService.java b/src/main/java/org/moonshot/server/domain/log/service/LogService.java new file mode 100644 index 00000000..5de8800f --- /dev/null +++ b/src/main/java/org/moonshot/server/domain/log/service/LogService.java @@ -0,0 +1,99 @@ +package org.moonshot.server.domain.log.service; + +import lombok.RequiredArgsConstructor; +import org.moonshot.server.domain.keyresult.dto.request.KeyResultCreateRequestDto; +import org.moonshot.server.domain.keyresult.dto.request.KeyResultCreateRequestInfoDto; +import org.moonshot.server.domain.keyresult.dto.request.KeyResultModifyRequestDto; +import org.moonshot.server.domain.keyresult.exception.KeyResultNotFoundException; +import org.moonshot.server.domain.keyresult.model.KeyResult; +import org.moonshot.server.domain.keyresult.repository.KeyResultRepository; +import org.moonshot.server.domain.log.dto.request.LogCreateRequestDto; +import org.moonshot.server.domain.log.model.Log; +import org.moonshot.server.domain.log.model.LogState; +import org.moonshot.server.domain.log.repository.LogRepository; +import org.moonshot.server.domain.user.exception.UserNotFoundException; +import org.moonshot.server.domain.user.model.User; +import org.moonshot.server.domain.user.repository.UserRepository; +import org.moonshot.server.global.auth.exception.AccessDeniedException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class LogService { + + private final UserRepository userRepository; + private final KeyResultRepository keyResultRepository; + private final LogRepository logRepository; + + @Transactional + public void createRecordLog(Long userId, LogCreateRequestDto request) { + User user = userRepository.findById(userId) + .orElseThrow(UserNotFoundException::new); + KeyResult keyResult = keyResultRepository.findById(request.keyResultId()) + .orElseThrow(KeyResultNotFoundException::new); + if (!keyResult.getObjective().getUser().getId().equals(userId)) { + throw new AccessDeniedException(); + } + List prevLog = logRepository.findLatestLogByKeyResultId(request.keyResultId()); + long prevNum = -1; + if (!prevLog.isEmpty()) { + prevNum = prevLog.get(0).getCurrNum(); + } + logRepository.save(Log.builder() + .date(LocalDateTime.now()) + .state(LogState.RECORD) + .currNum(request.logNum()) + .prevNum(prevNum) + .content(request.logContent()) + .keyResult(keyResult) + .build()); + } + + @Transactional + public void createUpdateLog(KeyResultModifyRequestDto request, Long keyResultId) { + KeyResult keyResult = keyResultRepository.findById(keyResultId) + .orElseThrow(KeyResultNotFoundException::new); + + logRepository.save(Log.builder() + .date(LocalDateTime.now()) + .state(LogState.UPDATE) + .currNum(request.target()) + .prevNum(keyResult.getTarget()) + .content(request.logContent()) + .keyResult(keyResult) + .build()); + } + + @Transactional + public void createKRLog(Object request, Long keyResultId) { + KeyResult keyResult = keyResultRepository.findById(keyResultId) + .orElseThrow(KeyResultNotFoundException::new); + + if (request instanceof KeyResultCreateRequestInfoDto) { + KeyResultCreateRequestInfoDto dto = (KeyResultCreateRequestInfoDto) request; + logRepository.save(Log.builder() + .date(LocalDateTime.now()) + .state(LogState.CREATE) + .currNum(dto.target()) + .content("") + .keyResult(keyResult) + .build()); + } + if (request instanceof KeyResultCreateRequestDto) { + KeyResultCreateRequestDto dto = (KeyResultCreateRequestDto) request; + logRepository.save(Log.builder() + .date(LocalDateTime.now()) + .state(LogState.CREATE) + .currNum(dto.target()) + .content("") + .keyResult(keyResult) + .build()); + } + } + +} diff --git a/src/main/java/org/moonshot/server/domain/objective/controller/ObjectiveController.java b/src/main/java/org/moonshot/server/domain/objective/controller/ObjectiveController.java index 2f282b15..85a458cb 100644 --- a/src/main/java/org/moonshot/server/domain/objective/controller/ObjectiveController.java +++ b/src/main/java/org/moonshot/server/domain/objective/controller/ObjectiveController.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import org.moonshot.server.domain.objective.dto.request.OKRCreateRequestDto; import org.moonshot.server.domain.objective.service.ObjectiveService; +import org.moonshot.server.global.auth.jwt.JwtTokenProvider; import org.moonshot.server.global.common.response.ApiResponse; import org.moonshot.server.global.common.response.SuccessType; import org.springframework.web.bind.annotation.PostMapping; @@ -12,6 +13,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.security.Principal; + @Slf4j @RestController @RequiredArgsConstructor @@ -19,11 +22,10 @@ public class ObjectiveController { private final ObjectiveService objectiveService; - private final String TEST_USER_NICKNAME = "tester"; @PostMapping - public ApiResponse createObjective(@RequestBody @Valid OKRCreateRequestDto request) { - objectiveService.createObjective(request, TEST_USER_NICKNAME); + public ApiResponse createObjective(Principal principal, @RequestBody @Valid OKRCreateRequestDto request) { + objectiveService.createObjective(JwtTokenProvider.getUserIdFromPrincipal(principal), request); return ApiResponse.success(SuccessType.POST_OKR_SUCCESS); } diff --git a/src/main/java/org/moonshot/server/domain/objective/service/ObjectiveService.java b/src/main/java/org/moonshot/server/domain/objective/service/ObjectiveService.java index 00cc463a..0c915f4b 100644 --- a/src/main/java/org/moonshot/server/domain/objective/service/ObjectiveService.java +++ b/src/main/java/org/moonshot/server/domain/objective/service/ObjectiveService.java @@ -25,11 +25,11 @@ public class ObjectiveService { private final ObjectiveRepository objectiveRepository; @Transactional - public void createObjective(OKRCreateRequestDto request, String nickname) { - User findUser = userRepository.findUserByNickname(nickname) + public void createObjective(Long userId, OKRCreateRequestDto request) { + User user = userRepository.findById(userId) .orElseThrow(UserNotFoundException::new); - if (objectiveRepository.countAllByUserAndIsClosed(findUser, false) >= ACTIVE_OBJECTIVE_NUMBER) { + if (objectiveRepository.countAllByUserAndIsClosed(user, false) >= ACTIVE_OBJECTIVE_NUMBER) { throw new ObjectiveNumberExceededException(); } @@ -38,7 +38,7 @@ public void createObjective(OKRCreateRequestDto request, String nickname) { .category(request.objCategory()) .content(request.objContent()) .period(Period.of(request.objStartAt(), request.objExpireAt())) - .user(findUser).build()); + .user(user).build()); keyResultService.createInitKRWithObjective(newObjective, request.krList()); } diff --git a/src/main/java/org/moonshot/server/global/common/model/validator/LimitValueValidator.java b/src/main/java/org/moonshot/server/global/common/model/validator/LimitValueValidator.java new file mode 100644 index 00000000..6b4f20bc --- /dev/null +++ b/src/main/java/org/moonshot/server/global/common/model/validator/LimitValueValidator.java @@ -0,0 +1,19 @@ +package org.moonshot.server.global.common.model.validator; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class LimitValueValidator implements ConstraintValidator { + + private final long MAX_LIMIT = 99999999999L; + + @Override + public boolean isValid(Long value, ConstraintValidatorContext context) { + if (value == null) { + return true; + } else { + return value <= MAX_LIMIT; + } + } + +} \ No newline at end of file diff --git a/src/main/java/org/moonshot/server/global/common/model/validator/TargetNumberValidator.java b/src/main/java/org/moonshot/server/global/common/model/validator/TargetNumberValidator.java index 9284dff7..44f5680b 100644 --- a/src/main/java/org/moonshot/server/global/common/model/validator/TargetNumberValidator.java +++ b/src/main/java/org/moonshot/server/global/common/model/validator/TargetNumberValidator.java @@ -4,10 +4,10 @@ import jakarta.validation.ConstraintValidatorContext; import lombok.extern.slf4j.Slf4j; -public class TargetNumberValidator implements ConstraintValidator { +public class TargetNumberValidator implements ConstraintValidator { @Override - public boolean isValid(Integer value, ConstraintValidatorContext context) { + public boolean isValid(Long value, ConstraintValidatorContext context) { if (value == null) { return true; } else { diff --git a/src/main/java/org/moonshot/server/global/common/model/validator/ValidLimitValue.java b/src/main/java/org/moonshot/server/global/common/model/validator/ValidLimitValue.java new file mode 100644 index 00000000..08e13373 --- /dev/null +++ b/src/main/java/org/moonshot/server/global/common/model/validator/ValidLimitValue.java @@ -0,0 +1,21 @@ +package org.moonshot.server.global.common.model.validator; + +import jakarta.validation.Constraint; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = TargetNumberValidator.class) +public @interface ValidLimitValue { + + String message() default "수치는 99,999,999,999까지만 가능합니다."; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/src/main/java/org/moonshot/server/global/common/response/SuccessType.java b/src/main/java/org/moonshot/server/global/common/response/SuccessType.java index e5d6fbca..aa611b4e 100644 --- a/src/main/java/org/moonshot/server/global/common/response/SuccessType.java +++ b/src/main/java/org/moonshot/server/global/common/response/SuccessType.java @@ -26,6 +26,7 @@ public enum SuccessType { POST_OKR_SUCCESS(HttpStatus.CREATED, "O-KR을 생성을 성공하였습니다."), POST_KEY_RESULT_SUCCESS(HttpStatus.CREATED, "KeyResult 생성을 성공하였습니다."), POST_TASK_SUCCESS(HttpStatus.CREATED, "Task 생성을 성공하였습니다."), + POST_LOG_SUCCESS(HttpStatus.CREATED, "체크인 Log 생성을 성공하였습니다."), /** * 204 NO CONTENT