diff --git a/.github/workflows/cd_dev.yml b/.github/workflows/cd_dev.yml index 6b04f311..9f3d8964 100644 --- a/.github/workflows/cd_dev.yml +++ b/.github/workflows/cd_dev.yml @@ -36,8 +36,8 @@ jobs: echo "APPLE_TEAM_ID=${{ secrets.APPLE_TEAM_ID }}" >> .env echo "APPLE_KEY_ID=${{ secrets.APPLE_KEY_ID }}" >> .env echo "APPLE_PRIVATE_KEY=${{ secrets.APPLE_PRIVATE_KEY }}" >> .env - echo "NEED_UPDATE_VERSION=${{ secrets.NEED_UPDATE_VERSION }}" >> .env - echo "RECOMMEND_UPDATE=${{ secrets.RECOMMEND_UPDATE }}" >> .env + echo "LATEST_VERSION=${{ secrets.LATEST_VERSION }}" >> .env + echo "FORCE_UPDATE_VERSION=${{ secrets.FORCE_UPDATE_VERSION }}" >> .env echo "SPRING_PROFILES_ACTIVE=dev" >> .env diff --git a/.github/workflows/cd_prod.yml b/.github/workflows/cd_prod.yml index 2c73f61c..e3566f3c 100644 --- a/.github/workflows/cd_prod.yml +++ b/.github/workflows/cd_prod.yml @@ -36,8 +36,8 @@ jobs: echo "APPLE_TEAM_ID=${{ secrets.APPLE_TEAM_ID }}" >> .env echo "APPLE_KEY_ID=${{ secrets.APPLE_KEY_ID }}" >> .env echo "APPLE_PRIVATE_KEY=${{ secrets.APPLE_PRIVATE_KEY }}" >> .env - echo "NEED_UPDATE_VERSION=${{ secrets.NEED_UPDATE_VERSION_PROD }}" >> .env - echo "RECOMMEND_UPDATE=${{ secrets.RECOMMEND_UPDATE_VERSION_PROD }}" >> .env + echo "LATEST_VERSION=${{ secrets.LATEST_VERSION_PROD }}" >> .env + echo "FORCE_UPDATE_VERSION=${{ secrets.FORCE_UPDATE_VERSION_PROD }}" >> .env - name: gradlew에 실행 권한 부여 run: chmod +x ./gradlew diff --git a/src/main/java/com/m3pro/groundflip/controller/CommunityController.java b/src/main/java/com/m3pro/groundflip/controller/CommunityController.java index 8ded36ac..fb9f7a32 100644 --- a/src/main/java/com/m3pro/groundflip/controller/CommunityController.java +++ b/src/main/java/com/m3pro/groundflip/controller/CommunityController.java @@ -4,12 +4,15 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +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.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.m3pro.groundflip.domain.dto.Response; import com.m3pro.groundflip.domain.dto.community.CommunityInfoResponse; +import com.m3pro.groundflip.domain.dto.community.CommunityJoinRequest; import com.m3pro.groundflip.domain.dto.community.CommunitySearchResponse; import com.m3pro.groundflip.service.CommunityService; @@ -45,4 +48,15 @@ public Response getCommunityInfo( ) { return Response.createSuccess(communityService.findCommunityById(communityId)); } + + @Operation(summary = "그룹 가입 api", description = "유저를 특정 그룹에 가입시킨다") + @PostMapping("/{communityId}") + public Response joinCommunity( + @Parameter(description = "가입하고자 하는 groupId", required = true) + @PathVariable("communityId") Long communityId, + @RequestBody CommunityJoinRequest communityJoinRequest + ) { + communityService.joinCommunity(communityId, communityJoinRequest); + return Response.createSuccessWithNoData(); + } } diff --git a/src/main/java/com/m3pro/groundflip/domain/dto/community/CommunityJoinRequest.java b/src/main/java/com/m3pro/groundflip/domain/dto/community/CommunityJoinRequest.java new file mode 100644 index 00000000..6ba927eb --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/domain/dto/community/CommunityJoinRequest.java @@ -0,0 +1,18 @@ +package com.m3pro.groundflip.domain.dto.community; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +@Schema(title = "그룹 가입 정보") +public class CommunityJoinRequest { + + @Schema(description = "가입 유저 id", example = "1") + private Long userId; +} diff --git a/src/main/java/com/m3pro/groundflip/exception/ErrorCode.java b/src/main/java/com/m3pro/groundflip/exception/ErrorCode.java index 692c3d3e..fb8b35ed 100644 --- a/src/main/java/com/m3pro/groundflip/exception/ErrorCode.java +++ b/src/main/java/com/m3pro/groundflip/exception/ErrorCode.java @@ -9,6 +9,7 @@ @Getter public enum ErrorCode { DUPLICATED_NICKNAME(HttpStatus.BAD_REQUEST, "중복된 닉네임입니다."), + ALREADY_JOINED(HttpStatus.BAD_REQUEST, "이미 가입된 유저입니다."), USER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 사용자입니다."), GROUP_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 그룹입니다."), PIXEL_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 픽셀입니다."), @@ -16,6 +17,7 @@ public enum ErrorCode { PLACE_NOT_FOUND(HttpStatus.NOT_FOUND, "장소가 등록되어 있지 않습니다."), INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 에러 입니다"), VERSION_NOT_FOUND(HttpStatus.NOT_FOUND, "버전이 존재하지 않습니다."), + COMMUNITY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 그룹입니다."), // 권한 관련 에러 UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "권한이 없습니다"), diff --git a/src/main/java/com/m3pro/groundflip/repository/UserCommunityRepository.java b/src/main/java/com/m3pro/groundflip/repository/UserCommunityRepository.java index 2c30c272..e5fc94e5 100644 --- a/src/main/java/com/m3pro/groundflip/repository/UserCommunityRepository.java +++ b/src/main/java/com/m3pro/groundflip/repository/UserCommunityRepository.java @@ -6,6 +6,8 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import com.m3pro.groundflip.domain.entity.Community; +import com.m3pro.groundflip.domain.entity.User; import com.m3pro.groundflip.domain.entity.UserCommunity; public interface UserCommunityRepository extends JpaRepository { @@ -14,4 +16,6 @@ public interface UserCommunityRepository extends JpaRepository new AppException(ErrorCode.USER_NOT_FOUND)); + + Community community = communityRepository.findById(communityId) + .orElseThrow(() -> new AppException(ErrorCode.COMMUNITY_NOT_FOUND)); + + Boolean isJoined = userCommunityRepository.existsByUserAndCommunityAndDeletedAtIsNull(user, community); + + if (isJoined) { + throw new AppException(ErrorCode.ALREADY_JOINED); + } + + UserCommunity userCommunity = UserCommunity.builder() + .user(user) + .community(community) + .build(); + + userCommunityRepository.save(userCommunity); + } + private Long getMemberCount(Community community) { return userCommunityRepository.countByCommunityId(community.getId()); } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 26561bd2..1d4db9b7 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -86,8 +86,8 @@ cloud: bucket: ${AWS_S3_BUCKET} version: - update: ${NEED_UPDATE_VERSION} - recommend: ${RECOMMEND_UPDATE} + update: ${LATEST_VERSION} + recommend: ${FORCE_UPDATE_VERSION} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 025a91f1..9990c76a 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -86,6 +86,6 @@ cloud: bucket: ${AWS_S3_BUCKET} version: - update: ${NEED_UPDATE_VERSION} - recommend: ${RECOMMEND_UPDATE} + update: ${LATEST_VERSION} + recommend: ${FORCE_UPDATE_VERSION} diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 7750a4f0..0464dce7 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -84,7 +84,7 @@ cloud: bucket: ${AWS_S3_BUCKET} version: - update: ${NEED_UPDATE_VERSION} - recommend: ${RECOMMEND_UPDATE} + update: ${LATEST_VERSION} + recommend: ${FORCE_UPDATE_VERSION} diff --git a/src/test/java/com/m3pro/groundflip/service/CommunityServiceTest.java b/src/test/java/com/m3pro/groundflip/service/CommunityServiceTest.java index 922f5215..ba68fad3 100644 --- a/src/test/java/com/m3pro/groundflip/service/CommunityServiceTest.java +++ b/src/test/java/com/m3pro/groundflip/service/CommunityServiceTest.java @@ -15,12 +15,16 @@ import org.mockito.MockitoAnnotations; import com.m3pro.groundflip.domain.dto.community.CommunityInfoResponse; +import com.m3pro.groundflip.domain.dto.community.CommunityJoinRequest; import com.m3pro.groundflip.domain.dto.community.CommunitySearchResponse; import com.m3pro.groundflip.domain.entity.Community; +import com.m3pro.groundflip.domain.entity.User; +import com.m3pro.groundflip.domain.entity.UserCommunity; import com.m3pro.groundflip.exception.AppException; import com.m3pro.groundflip.exception.ErrorCode; import com.m3pro.groundflip.repository.CommunityRepository; import com.m3pro.groundflip.repository.UserCommunityRepository; +import com.m3pro.groundflip.repository.UserRepository; class CommunityServiceTest { @InjectMocks @@ -32,8 +36,17 @@ class CommunityServiceTest { @Mock private UserCommunityRepository userCommunityRepository; + @Mock + private UserRepository userRepository; + private Community community; + private User user; + + private UserCommunity userCommunity; + + private CommunityJoinRequest communityJoinRequest; + @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); @@ -47,6 +60,16 @@ void setUp() { .maxPixelCount(54) .backgroundImageUrl("www.test.com") .build(); + + user = User.builder() + .id(1L) + .nickname("Test User") + .build(); + + userCommunity = UserCommunity.builder() + .community(community) + .user(user) + .build(); } @Test @@ -98,4 +121,84 @@ void findCommunityById_shouldThrowExceptionWhenCommunityNotFound() { () -> communityService.findCommunityById(communityId)); assertEquals(ErrorCode.GROUP_NOT_FOUND, exception.getErrorCode()); } + + @Test + @DisplayName("[joinCommunity] 그룹 가입 테스트") + void testJoinCommunity() { + //Given + Long communityId = 1L; + Long userId = 1L; + + when(communityRepository.findById(communityId)).thenReturn(Optional.of(community)); + when(userRepository.findById(userId)).thenReturn(Optional.of(user)); + + communityJoinRequest = CommunityJoinRequest.builder() + .userId(userId) + .build(); + + //When + communityService.joinCommunity(communityId, communityJoinRequest); + + //Then + verify(userCommunityRepository).save(any(UserCommunity.class)); + } + + @Test + @DisplayName("[joinCommunity] 유저가 없을때 에러 테스트") + void testJoinCommunity_userNotFound() { + // Given + CommunityJoinRequest communityJoinRequest2 = CommunityJoinRequest.builder() + .userId(2L) + .build(); + + // when + AppException thrown = assertThrows(AppException.class, () -> { + communityService.joinCommunity(2L, communityJoinRequest2); + }); + + // Then + assertEquals(ErrorCode.USER_NOT_FOUND, thrown.getErrorCode()); + } + + @Test + @DisplayName("[joinCommunity] 그룹이 없을때 에러 테스트") + void testJoinCommunity_communityNotFound() { + // Given + when(communityRepository.findById(2L)).thenReturn(Optional.empty()); + when(userRepository.findById(1L)).thenReturn(Optional.of(user)); + + communityJoinRequest = CommunityJoinRequest.builder() + .userId(1L) + .build(); + + // when + AppException thrown = assertThrows(AppException.class, () -> { + communityService.joinCommunity(2L, communityJoinRequest); + }); + + // Then + assertEquals(ErrorCode.COMMUNITY_NOT_FOUND, thrown.getErrorCode()); + } + + @Test + @DisplayName("[joinCommunity] 가입된 그룹이 이미 있을때 테스트") + void testJoinCommunity_alreadyJoined() { + // Given + when(communityRepository.findById(1L)).thenReturn(Optional.of(community)); + when(userRepository.findById(1L)).thenReturn(Optional.of(user)); + when(userCommunityRepository.existsByUserAndCommunityAndDeletedAtIsNull(user, community)).thenReturn(true); + + communityJoinRequest = CommunityJoinRequest.builder() + .userId(1L) + .build(); + + // when + AppException thrown = assertThrows(AppException.class, () -> { + communityService.joinCommunity(1L, communityJoinRequest); + }); + + // Then + assertEquals(ErrorCode.ALREADY_JOINED, thrown.getErrorCode()); + } + } \ No newline at end of file