diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challengegroup/challenge/ChallengeController.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challengegroup/challenge/ChallengeController.java index 8531ac2..9c88ce2 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challengegroup/challenge/ChallengeController.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challengegroup/challenge/ChallengeController.java @@ -4,9 +4,15 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.haedal.zzansuni.controller.PagingRequest; import org.haedal.zzansuni.controller.PagingResponse; import org.haedal.zzansuni.core.api.ApiResponse; +import org.haedal.zzansuni.domain.challengegroup.challenge.ChallengeCommand; +import org.haedal.zzansuni.domain.challengegroup.challenge.ChallengeService; +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallenge; +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallengeCommand; +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallengeService; import org.haedal.zzansuni.global.jwt.JwtUser; import org.springframework.http.HttpStatus; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -16,23 +22,30 @@ @Tag(name = "challenge", description = "챌린지 API") @RequiredArgsConstructor @RestController +@Slf4j public class ChallengeController { + private final ChallengeService challengeService; + private final UserChallengeService userChallengeService; + @Operation(summary = "챌린지 참여", description = "챌린지에 참여한다.") @PostMapping("/api/challenges/{challengeId}/join") public ApiResponse challengeParticipation( - @PathVariable Long challengeId, - @AuthenticationPrincipal JwtUser jwtUser + @PathVariable Long challengeId, + @AuthenticationPrincipal JwtUser jwtUser ) { - throw new RuntimeException("Not implemented"); + UserChallengeCommand.Participate command = new UserChallengeCommand.Participate(challengeId, + jwtUser.getId()); + userChallengeService.participateChallenge(jwtUser.getId(), command); + return ApiResponse.success(null, "챌린지 참여에 성공하였습니다."); } @Operation(summary = "챌린지 인증", description = "챌린지에 인증한다.") @PostMapping("/api/challenges/{challengeId}/verification") public ApiResponse challengeVerification( - @PathVariable Long challengeId, - @RequestPart("body") ChallengeReq.ChallengeVerificationRequest request, - @RequestPart("image") MultipartFile image + @PathVariable Long challengeId, + @RequestPart("body") ChallengeReq.ChallengeVerificationRequest request, + @RequestPart("image") MultipartFile image ) { throw new RuntimeException("Not implemented"); } @@ -41,9 +54,9 @@ public ApiResponse challengeVerifica @Operation(summary = "챌린지 리뷰 작성", description = "챌린지 리뷰를 작성한다.") @PostMapping("/api/challenges/{challengeId}/reviews") public ApiResponse challengeReviewCreate( - @PathVariable Long challengeId, - @AuthenticationPrincipal JwtUser jwtUser, - @RequestBody ChallengeReq.ChallengeReviewCreateRequest request + @PathVariable Long challengeId, + @AuthenticationPrincipal JwtUser jwtUser, + @RequestBody ChallengeReq.ChallengeReviewCreateRequest request ) { throw new RuntimeException("Not implemented"); } @@ -51,8 +64,8 @@ public ApiResponse challengeReviewCreate( @Operation(summary = "챌린지 기록 조회", description = "챌린지 기록을 조회한다.") @GetMapping("/api/challenges/{challengeId}/record") public ApiResponse getChallengeRecord( - @PathVariable Long challengeId, - @AuthenticationPrincipal JwtUser jwtUser + @PathVariable Long challengeId, + @AuthenticationPrincipal JwtUser jwtUser ) { throw new RuntimeException("Not implemented"); } @@ -60,16 +73,17 @@ public ApiResponse getChallengeRecord( @Operation(summary = "챌린지 기록 상세 조회", description = "챌린지 기록 상세를 조회한다.") @GetMapping("/api/challenges/record/{recordId}") public ApiResponse getChallengeRecordDetail( - @PathVariable Long recordId, - @AuthenticationPrincipal JwtUser jwtUser + @PathVariable Long recordId, + @AuthenticationPrincipal JwtUser jwtUser ) { throw new RuntimeException("Not implemented"); } + @Operation(summary = "진행중인 챌린지 조회", description = "진행중인 챌린지 조회한다.") @GetMapping("/api/user/challenges/currents") public ApiResponse> getChallengeCurrentsPaging( - @Valid PagingRequest pagingRequest, - @AuthenticationPrincipal JwtUser jwtUser + @Valid PagingRequest pagingRequest, + @AuthenticationPrincipal JwtUser jwtUser ) { throw new RuntimeException("Not implemented"); } @@ -77,8 +91,8 @@ public ApiResponse> getChalleng @Operation(summary = "완료한 챌린지 조회", description = "완료한 챌린지 페이징 조회한다.") @GetMapping("/api/user/challenges/completes") public ApiResponse> getChallengeCompletesPaging( - @Valid PagingRequest pagingRequest, - @AuthenticationPrincipal JwtUser jwtUser + @Valid PagingRequest pagingRequest, + @AuthenticationPrincipal JwtUser jwtUser ) { throw new RuntimeException("Not implemented"); } diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeReader.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeReader.java new file mode 100644 index 0000000..0ea68ff --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeReader.java @@ -0,0 +1,10 @@ +package org.haedal.zzansuni.domain.challengegroup.challenge; + +import java.util.Optional; + +public interface ChallengeReader { + + Challenge getById(Long id); + + Optional findById(Long id); +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeReview.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeReview.java index 5862a04..d90293c 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeReview.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeReview.java @@ -1,8 +1,6 @@ package org.haedal.zzansuni.domain.challengegroup.challenge; import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -15,8 +13,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.haedal.zzansuni.domain.BaseTimeEntity; -import org.haedal.zzansuni.domain.challengegroup.ChallengeGroup; -import org.haedal.zzansuni.domain.challengegroup.DayType; +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallenge; @Entity @AllArgsConstructor diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeService.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeService.java new file mode 100644 index 0000000..e6727d3 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeService.java @@ -0,0 +1,17 @@ +package org.haedal.zzansuni.domain.challengegroup.challenge; + +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.haedal.zzansuni.domain.user.UserReader; +import org.haedal.zzansuni.domain.user.UserStore; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class ChallengeService { + + private final ChallengeReader challengeReader; + private final ChallengeStore challengeStore; + + +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeStore.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeStore.java new file mode 100644 index 0000000..92d9bb2 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeStore.java @@ -0,0 +1,5 @@ +package org.haedal.zzansuni.domain.challengegroup.challenge; + +public interface ChallengeStore { + +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeVerification.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeVerification.java index 13cf27f..98947fb 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeVerification.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/ChallengeVerification.java @@ -15,8 +15,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.haedal.zzansuni.domain.BaseTimeEntity; -import org.haedal.zzansuni.domain.challengegroup.ChallengeGroup; -import org.haedal.zzansuni.domain.challengegroup.DayType; +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallenge; @Entity @AllArgsConstructor diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/UserChallenge.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallenge.java similarity index 70% rename from zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/UserChallenge.java rename to zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallenge.java index 6544395..3324d7b 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/UserChallenge.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallenge.java @@ -1,4 +1,4 @@ -package org.haedal.zzansuni.domain.challengegroup.challenge; +package org.haedal.zzansuni.domain.challengegroup.userchallenge; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; @@ -15,8 +15,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.haedal.zzansuni.domain.BaseTimeEntity; -import org.haedal.zzansuni.domain.challengegroup.ChallengeGroup; -import org.haedal.zzansuni.domain.challengegroup.DayType; +import org.haedal.zzansuni.domain.challengegroup.challenge.Challenge; +import org.haedal.zzansuni.domain.challengegroup.challenge.ChallengeStatus; import org.haedal.zzansuni.domain.user.User; @Entity @@ -40,4 +40,12 @@ public class UserChallenge extends BaseTimeEntity { @Enumerated(EnumType.STRING) private ChallengeStatus status; + + public static UserChallenge from(Challenge challenge, User user) { + return UserChallenge.builder() + .challenge(challenge) + .user(user) + .status(ChallengeStatus.PROCEEDING) + .build(); + } } diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeCommand.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeCommand.java new file mode 100644 index 0000000..678d3f5 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeCommand.java @@ -0,0 +1,23 @@ +package org.haedal.zzansuni.domain.challengegroup.userchallenge; + +import lombok.Builder; +import lombok.Getter; +import org.haedal.zzansuni.core.utils.SelfValidating; + +public class UserChallengeCommand { + + @Getter + @Builder + public static class Participate extends SelfValidating { + + private Long challengeId; + private Long userId; + + public Participate(Long challengeId, Long userId) { + this.challengeId = challengeId; + this.userId = userId; + this.validateSelf(); + } + } + +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeReader.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeReader.java new file mode 100644 index 0000000..7480d1f --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeReader.java @@ -0,0 +1,10 @@ +package org.haedal.zzansuni.domain.challengegroup.userchallenge; + +import java.util.Optional; + +public interface UserChallengeReader { + + UserChallenge getById(Long id); + + Optional findById(Long id); +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeService.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeService.java new file mode 100644 index 0000000..67dcfc9 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeService.java @@ -0,0 +1,30 @@ +package org.haedal.zzansuni.domain.challengegroup.userchallenge; + +import lombok.RequiredArgsConstructor; +import org.haedal.zzansuni.domain.challengegroup.challenge.Challenge; +import org.haedal.zzansuni.domain.challengegroup.challenge.ChallengeReader; +import org.haedal.zzansuni.domain.user.User; +import org.haedal.zzansuni.domain.user.UserReader; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class UserChallengeService { + + private final UserChallengeStore userChallengeStore; + private final UserChallengeReader userChallengeReader; + private final UserReader userReader; + private final ChallengeReader challengeReader; + + /** + * 챌린지 참여하기 1. 유저와 챌린지 정보를 받아서 UserChallenge 테이블에 데이터 추가 + */ + public void participateChallenge(Long userId, + UserChallengeCommand.Participate participateInfo) { + User user = userReader.getById(userId); + Challenge challenge = challengeReader.getById(participateInfo.getChallengeId()); + UserChallenge userChallenge = UserChallenge.from(challenge, user); + userChallengeStore.store(userChallenge); + } + +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeStore.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeStore.java new file mode 100644 index 0000000..5baf8e8 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/userchallenge/UserChallengeStore.java @@ -0,0 +1,6 @@ +package org.haedal.zzansuni.domain.challengegroup.userchallenge; + +public interface UserChallengeStore { + + UserChallenge store(UserChallenge userChallenge); +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/exception/ResourceNotFoundException.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/exception/ResourceNotFoundException.java new file mode 100644 index 0000000..641034f --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/exception/ResourceNotFoundException.java @@ -0,0 +1,12 @@ +package org.haedal.zzansuni.exception; + +public class ResourceNotFoundException extends RuntimeException { + + public ResourceNotFoundException(String datasource, long id) { + super(datasource + "에서 ID " + id + "를 찾을 수 없습니다."); + } + + public ResourceNotFoundException(String datasource, String id) { + super(datasource + "에서 ID " + id + "를 찾을 수 없습니다."); + } +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/challenge/ChallengeReaderImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/challenge/ChallengeReaderImpl.java new file mode 100644 index 0000000..9cdcf65 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/challenge/ChallengeReaderImpl.java @@ -0,0 +1,30 @@ +package org.haedal.zzansuni.infrastructure.challengegroup.challenge; + +import java.util.NoSuchElementException; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.haedal.zzansuni.domain.challengegroup.challenge.Challenge; +import org.haedal.zzansuni.domain.challengegroup.challenge.ChallengeModel; +import org.haedal.zzansuni.domain.challengegroup.challenge.ChallengeReader; +import org.haedal.zzansuni.exception.ResourceNotFoundException; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class ChallengeReaderImpl implements ChallengeReader { + + private final ChallengeRepository challengeRepository; + + @Override + public Challenge getById(Long id) { + return findById(id).orElseThrow( + () -> new ResourceNotFoundException("Challenge", id)); + } + + @Override + public Optional findById(Long id) { + return challengeRepository.findById(id); + } + + +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/challenge/ChallengeRepository.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/challenge/ChallengeRepository.java new file mode 100644 index 0000000..3569933 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/challenge/ChallengeRepository.java @@ -0,0 +1,8 @@ +package org.haedal.zzansuni.infrastructure.challengegroup.challenge; + +import org.haedal.zzansuni.domain.challengegroup.challenge.Challenge; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ChallengeRepository extends JpaRepository { + +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/challenge/ChallengeStoreImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/challenge/ChallengeStoreImpl.java new file mode 100644 index 0000000..1f86f8b --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/challenge/ChallengeStoreImpl.java @@ -0,0 +1,13 @@ +package org.haedal.zzansuni.infrastructure.challengegroup.challenge; + +import lombok.RequiredArgsConstructor; +import org.haedal.zzansuni.domain.challengegroup.challenge.ChallengeStore; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class ChallengeStoreImpl implements ChallengeStore { + + private final ChallengeRepository challengeRepository; + +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/userchallenge/UserChallengeReaderImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/userchallenge/UserChallengeReaderImpl.java new file mode 100644 index 0000000..687f548 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/userchallenge/UserChallengeReaderImpl.java @@ -0,0 +1,26 @@ +package org.haedal.zzansuni.infrastructure.challengegroup.userchallenge; + +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallenge; +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallengeReader; +import org.haedal.zzansuni.exception.ResourceNotFoundException; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class UserChallengeReaderImpl implements UserChallengeReader { + + private final UserChallengeRepository userChallengeRepository; + + @Override + public UserChallenge getById(Long id) { + return findById(id).orElseThrow( + () -> new ResourceNotFoundException("UserChallenge", id)); + } + + @Override + public Optional findById(Long id) { + return userChallengeRepository.findById(id); + } +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/userchallenge/UserChallengeRepository.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/userchallenge/UserChallengeRepository.java new file mode 100644 index 0000000..0b5a3aa --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/userchallenge/UserChallengeRepository.java @@ -0,0 +1,8 @@ +package org.haedal.zzansuni.infrastructure.challengegroup.userchallenge; + +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallenge; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserChallengeRepository extends JpaRepository { + +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/userchallenge/UserChallengeStoreImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/userchallenge/UserChallengeStoreImpl.java new file mode 100644 index 0000000..9b1ef71 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/userchallenge/UserChallengeStoreImpl.java @@ -0,0 +1,18 @@ +package org.haedal.zzansuni.infrastructure.challengegroup.userchallenge; + +import lombok.RequiredArgsConstructor; +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallenge; +import org.haedal.zzansuni.domain.challengegroup.userchallenge.UserChallengeStore; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class UserChallengeStoreImpl implements UserChallengeStore { + + private final UserChallengeRepository userChallengeRepository; + + @Override + public UserChallenge store(UserChallenge userChallenge) { + return userChallengeRepository.save(userChallenge); + } +}