diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 398a24e..48256eb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,23 +11,24 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up JDK 17 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: java-version: '17' - distribution: 'adopt' + distribution: 'temurin' - name: Decode application.yml run: | echo "${{ secrets.ENCODED_APPLICATION_YML }}" | base64 --decode > ./src/main/resources/application.yml cat ./src/main/resources/application.yml + - name: Grant execute permission for Gradlew run: chmod +x ./gradlew - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ~/.gradle/caches @@ -43,7 +44,7 @@ jobs: run: docker build -t ${{ secrets.DOCKERHUB_URL }}:${{ github.sha }} . - name: Log in to Docker Hub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -67,15 +68,17 @@ jobs: environment: production steps: - name: Checkout the repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: ${{ secrets.MANIFEST_REPO }} ref: ${{ secrets.MANIFEST_REPO_BRANCH }} token: ${{ secrets.MY_PAT }} + - name: Configure git run: | git config user.email ${{ secrets.GIT_USER_EMAIL }} git config user.name ${{ secrets.GIT_USER_NAME }} + - name: Make changes run: | cd ${{ secrets.MANIFEST_FOLDER_NAME }} @@ -107,6 +110,7 @@ jobs: yq eval -i ".spec.template.spec.containers[0].image = \"$IMAGE_TAG\"" $FILENAME yq eval -i ".spec.replicas = ${{ secrets.POD_REPLICAS }}" $FILENAME fi + - name: Commit and Push run: | SHORT_SHA="${{ github.sha }}" diff --git a/src/main/java/com/syncd/adapter/in/web/ProjectController.java b/src/main/java/com/syncd/adapter/in/web/ProjectController.java index 53eba29..84c391f 100644 --- a/src/main/java/com/syncd/adapter/in/web/ProjectController.java +++ b/src/main/java/com/syncd/adapter/in/web/ProjectController.java @@ -17,6 +17,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; @RestController @RequiredArgsConstructor @@ -79,9 +80,19 @@ public UpdateProjectResponseDto updateProject(HttpServletRequest request, @Valid } @PostMapping("/sync") - public SyncProjectResponseDto syncProject(HttpServletRequest request, @Valid @RequestBody SyncProjectRequestDto requestDto){ + public SyncProjectResponseDto syncProject(HttpServletRequest request, + @Valid @ModelAttribute SyncProjectRequestDto requestDto){ String token = jwtService.resolveToken(request); - return syncProjectUsecase.syncProject(jwtService.getUserIdFromToken(token), requestDto.projectId(), requestDto.projectStage()); + return syncProjectUsecase.syncProject(jwtService.getUserIdFromToken(token), + requestDto.projectId(), + requestDto.projectStage(), + requestDto.problem(), + requestDto.personaImage(), + requestDto.whyWhatHowImage(), + requestDto.coreDetails(), + requestDto.businessModelImage(), + requestDto.epics(), + requestDto.menuTreeImage()); } @PostMapping("/userstory") diff --git a/src/main/java/com/syncd/adapter/out/persistence/repository/project/ProjectEntity.java b/src/main/java/com/syncd/adapter/out/persistence/repository/project/ProjectEntity.java index f25e7e0..6a19ef8 100644 --- a/src/main/java/com/syncd/adapter/out/persistence/repository/project/ProjectEntity.java +++ b/src/main/java/com/syncd/adapter/out/persistence/repository/project/ProjectEntity.java @@ -20,10 +20,42 @@ public class ProjectEntity { private String lastModifiedDate; private int leftChanceForUserstory; + // 추가 필드 + private String problem; + private String personaImage; + private String whyImage; + private String whatImage; + private String howImage; + private CoreDetails coreDetails; + private String businessModelImage; + private List scenarios; + private List epics; + @Data public static class UserInProjectEntity { private String userId; private Role role; } + @Data + public static class CoreDetails { + private String coreTarget; + private String coreProblem; + private String coreCause; + private String solution; + private String coreValue; + } + + @Data + public static class Epic { + private String id; + private String name; + private List userStories; + } + + @Data + public static class UserStory { + private String id; + private String name; + } } \ No newline at end of file diff --git a/src/main/java/com/syncd/application/port/in/GetAllRoomsByUserIdUsecase.java b/src/main/java/com/syncd/application/port/in/GetAllRoomsByUserIdUsecase.java index 52c8ef3..efcaba8 100644 --- a/src/main/java/com/syncd/application/port/in/GetAllRoomsByUserIdUsecase.java +++ b/src/main/java/com/syncd/application/port/in/GetAllRoomsByUserIdUsecase.java @@ -30,7 +30,8 @@ record ProjectForGetAllInfoAboutRoomsByUserIdResponseDto( Role role, List userEmails, int progress, - String lastModifiedDate + String lastModifiedDate, + String projectImg ){} record GetAllRoomsByUserIdRequestDto( diff --git a/src/main/java/com/syncd/application/port/in/SyncProjectUsecase.java b/src/main/java/com/syncd/application/port/in/SyncProjectUsecase.java index 6c09d24..70a6c88 100644 --- a/src/main/java/com/syncd/application/port/in/SyncProjectUsecase.java +++ b/src/main/java/com/syncd/application/port/in/SyncProjectUsecase.java @@ -1,14 +1,27 @@ package com.syncd.application.port.in; +import com.syncd.domain.project.CoreDetails; +import com.syncd.domain.project.Epic; import com.syncd.exceptions.ValidationMessages; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; public interface SyncProjectUsecase { // ====================================== // METHOD // ====================================== - SyncProjectResponseDto syncProject(String userId, String projectId, int projectStage); + SyncProjectResponseDto syncProject(String userId, String projectId, int projectStage, + String problem, + MultipartFile personaImage, + MultipartFile whyWhatHowImage, + String coreDetails, + MultipartFile businessModelImage, + String epics, + MultipartFile menuTreeImage + ); // ====================================== // DTO // ====================================== @@ -17,7 +30,16 @@ record SyncProjectRequestDto( @NotBlank(message = ValidationMessages.PROJECT_ID_NOT_BLANK) String projectId, @NotNull(message = ValidationMessages.PROJECT_PROGRESS_NOT_NULL) - Integer projectStage + Integer projectStage, + // Sync 내용, projectStage 마다 필요한 요소들이 존재 + String problem, + String coreDetails, + String epics, + + MultipartFile personaImage, + MultipartFile whyWhatHowImage, + MultipartFile businessModelImage, + MultipartFile menuTreeImage ){} record SyncProjectResponseDto( diff --git a/src/main/java/com/syncd/application/port/out/s3/S3Port.java b/src/main/java/com/syncd/application/port/out/s3/S3Port.java index fc0fb0d..bc366b6 100644 --- a/src/main/java/com/syncd/application/port/out/s3/S3Port.java +++ b/src/main/java/com/syncd/application/port/out/s3/S3Port.java @@ -2,12 +2,10 @@ import org.springframework.web.multipart.MultipartFile; -import java.io.IOException; -import java.security.NoSuchAlgorithmException; import java.util.Optional; public interface S3Port { - public Optional uploadMultipartFileToS3(MultipartFile multipartFile); - public Optional deleteFileFromS3(String filename); + Optional uploadMultipartFileToS3(MultipartFile multipartFile); + Optional deleteFileFromS3(String filename); } diff --git a/src/main/java/com/syncd/application/service/ProjectService.java b/src/main/java/com/syncd/application/service/ProjectService.java index f0d7a5a..7a90a10 100644 --- a/src/main/java/com/syncd/application/service/ProjectService.java +++ b/src/main/java/com/syncd/application/service/ProjectService.java @@ -1,5 +1,6 @@ package com.syncd.application.service; +import com.fasterxml.jackson.databind.ObjectMapper; import com.syncd.application.port.in.*; import com.syncd.application.port.out.gmail.SendMailPort; import com.syncd.application.port.out.liveblock.LiveblocksPort; @@ -8,6 +9,8 @@ import com.syncd.application.port.out.persistence.project.WriteProjectPort; import com.syncd.application.port.out.persistence.user.ReadUserPort; import com.syncd.application.port.out.s3.S3Port; +import com.syncd.domain.project.CoreDetails; +import com.syncd.domain.project.Epic; import com.syncd.domain.project.Project; import com.syncd.domain.project.UserInProject; import com.syncd.domain.user.User; @@ -27,7 +30,7 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; - +import com.fasterxml.jackson.core.type.TypeReference; @Service @@ -47,12 +50,11 @@ public class ProjectService implements CreateProjectUsecase, GetAllRoomsByUserId @Override public CreateProjectResponseDto createProject(String hostId, String hostName, String projectName, String description, MultipartFile img, List userEmails){ - String imgURL = ""; - System.out.println(hostName); - if (img != null && !img.isEmpty()) { - Optional optionalImgURL = s3Port.uploadMultipartFileToS3(img); - imgURL = optionalImgURL.orElseThrow(() -> new IllegalStateException("Failed to upload image to S3")); + List users = new ArrayList<>(); + if(userEmails!=null){ + users = readUserPort.usersFromEmails(userEmails); } + String imgURL = uploadFileToS3(img); Project project = new Project(); project = project.createProjectDomain(projectName, description, imgURL, hostId); @@ -177,13 +179,65 @@ public WithdrawUserInProjectResponseDto withdrawUserInProject(String userId, Str } @Override - public SyncProjectResponseDto syncProject(String userId, String projectId, int projectStage) { + public SyncProjectResponseDto syncProject(String userId, String projectId, int projectStage, + String problem, + MultipartFile personaImage, + MultipartFile whyWhatHowImage, + String coreDetailsJson, + MultipartFile businessModelImage, + String epicsJson, + MultipartFile menuTreeImage) { + ObjectMapper objectMapper = new ObjectMapper(); + CoreDetails coreDetails; + List epics; + + try { + coreDetails = objectMapper.readValue(coreDetailsJson, CoreDetails.class); + epics = objectMapper.readValue(epicsJson, new TypeReference>() {}); + } catch (Exception e) { + throw new CustomException(ErrorInfo.JSON_PARSE_ERROR, "Failed to parse JSON for coreDetails or epics: " + e.getMessage()); + } + Project project = readProjectPort.findProjectByProjectId(projectId); + switch (projectStage) { + case 1: + case 2: + break; + case 3: + project.setProblem(problem); + break; + case 4: + project.setPersonaImage(uploadFileToS3(personaImage)); + break; + case 5: + case 6: + break; + case 7: + project.setWhyWhatHowImage(uploadFileToS3(whyWhatHowImage)); + break; + case 8: + project.setCoreDetails(coreDetails); + break; + case 9: + project.setBusinessModelImage(uploadFileToS3(businessModelImage)); + break; + case 10: + break; + case 11: + project.setEpics(epics); + break; + case 12: + project.setMenuTreeImage(uploadFileToS3(menuTreeImage)); + break; + default: + throw new IllegalArgumentException("Invalid project stage: " + projectStage); + } writeProjectPort.AddProgress(projectId, projectStage); writeProjectPort.updateLastModifiedDate(projectId); - + writeProjectPort.UpdateProject(project); return new SyncProjectResponseDto(projectId); } + @Override @Transactional public MakeUserStoryResponseDto makeUserstory(String userId, String projectId, List senarios){ @@ -199,6 +253,7 @@ public MakeUserStoryResponseDto makeUserstory(String userId, String projectId, L System.out.println(project); throw new CustomException(ErrorInfo.NOT_INCLUDE_PROJECT, "project id" + projectId); } + project.setScenarios(senarios); project.subLeftChanceForUserstory(); writeProjectPort.UpdateProject(project); System.out.println(senarios); @@ -259,11 +314,20 @@ private ProjectForGetAllInfoAboutRoomsByUserIdResponseDto convertProjectToDto(St userRole, userEmails, project.getProgress(), - project.getLastModifiedDate() + project.getLastModifiedDate(), + project.getImg() ); } private UserRoleDto convertUserToUserRoleDto(String projectId, UserInProject user) { return new UserRoleDto(projectId, user.getUserId(), user.getRole()); } + + private String uploadFileToS3(MultipartFile file) { + if (file != null && !file.isEmpty()) { + Optional optionalFileUrl = s3Port.uploadMultipartFileToS3(file); + return optionalFileUrl.orElseThrow(() -> new IllegalStateException("Failed to upload file to S3")); + } + return ""; + } } diff --git a/src/main/java/com/syncd/domain/project/CoreDetails.java b/src/main/java/com/syncd/domain/project/CoreDetails.java new file mode 100644 index 0000000..1931886 --- /dev/null +++ b/src/main/java/com/syncd/domain/project/CoreDetails.java @@ -0,0 +1,12 @@ +package com.syncd.domain.project; + +import lombok.Data; + +@Data +public class CoreDetails { + private String coreTarget; + private String coreProblem; + private String coreCause; + private String solution; + private String coreValue; +} diff --git a/src/main/java/com/syncd/domain/project/Epic.java b/src/main/java/com/syncd/domain/project/Epic.java new file mode 100644 index 0000000..db2d333 --- /dev/null +++ b/src/main/java/com/syncd/domain/project/Epic.java @@ -0,0 +1,12 @@ +package com.syncd.domain.project; + +import lombok.Data; + +import java.util.List; + +@Data +public class Epic { + private String id; + private String name; + private List userStories; +} diff --git a/src/main/java/com/syncd/domain/project/Project.java b/src/main/java/com/syncd/domain/project/Project.java index 728b8e4..db5214f 100644 --- a/src/main/java/com/syncd/domain/project/Project.java +++ b/src/main/java/com/syncd/domain/project/Project.java @@ -23,6 +23,15 @@ public class Project { private String lastModifiedDate; private int leftChanceForUserstory; + // 싱크된 내용 + private String problem; + private String personaImage; + private String whyWhatHowImage; + private CoreDetails coreDetails; + private String businessModelImage; + private List scenarios; + private List epics; + private String menuTreeImage; public void addUsers(List newUsers) { if (this.users == null) { @@ -40,14 +49,11 @@ public void withdrawUsers(List userIds) { } public String getHost() { - if(this.users != null){ - return this.users.stream() - .filter(user -> user.getRole() == Role.HOST) - .map(UserInProject::getUserId) - .findFirst() - .orElse(null); // Returns null if no host is found - } - return null; + return this.users.stream() + .filter(user -> user.getRole() == Role.HOST) + .map(UserInProject::getUserId) + .findFirst() + .orElse(null); // Returns null if no host is found } public void updateProjectInfo(String projectName, String description, String img){ diff --git a/src/main/java/com/syncd/domain/project/UserStory.java b/src/main/java/com/syncd/domain/project/UserStory.java new file mode 100644 index 0000000..360cca7 --- /dev/null +++ b/src/main/java/com/syncd/domain/project/UserStory.java @@ -0,0 +1,9 @@ +package com.syncd.domain.project; + +import lombok.Data; + +@Data +public class UserStory { + private String id; + private String name; +} diff --git a/src/main/java/com/syncd/exceptions/ErrorInfo.java b/src/main/java/com/syncd/exceptions/ErrorInfo.java index f7e5046..83966bf 100644 --- a/src/main/java/com/syncd/exceptions/ErrorInfo.java +++ b/src/main/java/com/syncd/exceptions/ErrorInfo.java @@ -10,7 +10,8 @@ public enum ErrorInfo { PROJECT_ALREADY_EXISTS(HttpStatus.CONFLICT, "Project already exists", 409001), NOT_LEFT_CHANCE(HttpStatus.FORBIDDEN, "Not Left Chance", 403001), NOT_INCLUDE_PROJECT(HttpStatus.FORBIDDEN, "Not include that project", 403002), - USER_NOT_FOUND(HttpStatus.NOT_FOUND, "User not found", 404002); + USER_NOT_FOUND(HttpStatus.NOT_FOUND, "User not found", 404002), + JSON_PARSE_ERROR(HttpStatus.BAD_REQUEST, "JSON parse error", 400003); private final HttpStatus status; private final String message; diff --git a/src/main/java/com/syncd/mapper/ProjectMapper.java b/src/main/java/com/syncd/mapper/ProjectMapper.java index 8bbdb89..92bf040 100644 --- a/src/main/java/com/syncd/mapper/ProjectMapper.java +++ b/src/main/java/com/syncd/mapper/ProjectMapper.java @@ -62,7 +62,8 @@ default ProjectForGetAllInfoAboutRoomsByUserIdResponseDto convertProjectToProjec role, userEmails, project.getProgress(), - project.getLastModifiedDate() + project.getLastModifiedDate(), + project.getImg() ); } diff --git a/src/test/java/adaptor/in/web/ProjectControllerTest.java b/src/test/java/adaptor/in/web/ProjectControllerTest.java index 5f86184..be08e1f 100644 --- a/src/test/java/adaptor/in/web/ProjectControllerTest.java +++ b/src/test/java/adaptor/in/web/ProjectControllerTest.java @@ -10,6 +10,8 @@ import com.syncd.application.port.in.DeleteProjectUsecase.*; import com.syncd.application.port.in.SyncProjectUsecase.*; import com.syncd.application.service.JwtService; +import com.syncd.domain.project.CoreDetails; +import com.syncd.domain.project.Epic; import com.syncd.dto.MakeUserStoryReauestDto; import com.syncd.dto.MakeUserStoryResponseDto; import jakarta.servlet.http.HttpServletRequest; @@ -22,6 +24,7 @@ import org.mockito.MockitoAnnotations; import org.springframework.http.ResponseEntity; import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; import java.util.Collections; import java.util.List; @@ -220,12 +223,29 @@ void testDeleteProject_ValidRequest() { @DisplayName("Sync Project - Valid Request") void testSyncProject_ValidRequest() { HttpServletRequest request = mock(HttpServletRequest.class); - SyncProjectRequestDto requestDto = new SyncProjectRequestDto("validProjectId", 10); + MultipartFile personaImage = mock(MultipartFile.class); + MultipartFile whyWhatHowImage = mock(MultipartFile.class); + MultipartFile businessModelImage = mock(MultipartFile.class); + MultipartFile menuTreeImage = mock(MultipartFile.class); + + SyncProjectRequestDto requestDto = new SyncProjectRequestDto( + "validProjectId", + 10, + "problem", + "coreDetailsJsonString", + "epicsJsonString", + personaImage, + whyWhatHowImage, + businessModelImage, + menuTreeImage + ); setupMockJwtService(request, "token", "userId", null); SyncProjectResponseDto responseDto = new SyncProjectResponseDto("validProjectId"); - when(syncProjectUsecase.syncProject(anyString(), anyString(), anyInt())).thenReturn(responseDto); + when(syncProjectUsecase.syncProject(anyString(), anyString(), anyInt(), anyString(), + any(MultipartFile.class), any(MultipartFile.class), anyString(), + any(MultipartFile.class), anyString(), any(MultipartFile.class))).thenReturn(responseDto); SyncProjectResponseDto response = projectController.syncProject(request, requestDto); @@ -233,9 +253,12 @@ void testSyncProject_ValidRequest() { assertThat(response.projectId()).isEqualTo("validProjectId"); verifyJwtServiceInteraction(request, "token"); - verifySyncProjectUsecase("userId", "validProjectId", 10); + verifySyncProjectUsecase("userId", "validProjectId", 10, "problem", + personaImage, whyWhatHowImage, "coreDetailsJsonString", + businessModelImage, "epicsJsonString", menuTreeImage); } + // ====================================== // MakeUserStory // ====================================== @@ -352,18 +375,37 @@ private void verifyUpdateProjectUsecase(String expectedUserId, String expectedPr assertThat(imageCaptor.getValue()).isEqualTo(expectedImage); } - private void verifySyncProjectUsecase(String expectedUserId, String expectedProjectId, Integer expectedProjectStage) { + private void verifySyncProjectUsecase(String expectedUserId, String expectedProjectId, int expectedProjectStage, + String expectedProblem, MultipartFile expectedPersonaImage, + MultipartFile expectedWhyWhatHowImage, String expectedCoreDetailsJson, + MultipartFile expectedBusinessModelImage, String expectedEpicsJson, + MultipartFile expectedMenuTreeImage) { ArgumentCaptor userIdCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor projectIdCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor projectStageCaptor = ArgumentCaptor.forClass(Integer.class); - - verify(syncProjectUsecase).syncProject(userIdCaptor.capture(), projectIdCaptor.capture(), projectStageCaptor.capture()); + ArgumentCaptor problemCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor personaImageCaptor = ArgumentCaptor.forClass(MultipartFile.class); + ArgumentCaptor whyWhatHowImageCaptor = ArgumentCaptor.forClass(MultipartFile.class); + ArgumentCaptor coreDetailsJsonCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor businessModelImageCaptor = ArgumentCaptor.forClass(MultipartFile.class); + ArgumentCaptor epicsJsonCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor menuTreeImageCaptor = ArgumentCaptor.forClass(MultipartFile.class); + + verify(syncProjectUsecase).syncProject(userIdCaptor.capture(), projectIdCaptor.capture(), projectStageCaptor.capture(), + problemCaptor.capture(), personaImageCaptor.capture(), whyWhatHowImageCaptor.capture(), coreDetailsJsonCaptor.capture(), + businessModelImageCaptor.capture(), epicsJsonCaptor.capture(), menuTreeImageCaptor.capture()); assertThat(userIdCaptor.getValue()).isEqualTo(expectedUserId); assertThat(projectIdCaptor.getValue()).isEqualTo(expectedProjectId); assertThat(projectStageCaptor.getValue()).isEqualTo(expectedProjectStage); + assertThat(problemCaptor.getValue()).isEqualTo(expectedProblem); + assertThat(personaImageCaptor.getValue()).isEqualTo(expectedPersonaImage); + assertThat(whyWhatHowImageCaptor.getValue()).isEqualTo(expectedWhyWhatHowImage); + assertThat(coreDetailsJsonCaptor.getValue()).isEqualTo(expectedCoreDetailsJson); + assertThat(businessModelImageCaptor.getValue()).isEqualTo(expectedBusinessModelImage); + assertThat(epicsJsonCaptor.getValue()).isEqualTo(expectedEpicsJson); + assertThat(menuTreeImageCaptor.getValue()).isEqualTo(expectedMenuTreeImage); } - private void verifyMakeUserstoryUsecase(String expectedUserId, String expectedProjectId, List expectedScenario) { ArgumentCaptor userIdCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor projectIdCaptor = ArgumentCaptor.forClass(String.class); diff --git a/src/test/java/adaptor/in/web/ProjectControllerValidationTest.java b/src/test/java/adaptor/in/web/ProjectControllerValidationTest.java index 18b457f..6bbbe64 100644 --- a/src/test/java/adaptor/in/web/ProjectControllerValidationTest.java +++ b/src/test/java/adaptor/in/web/ProjectControllerValidationTest.java @@ -7,6 +7,8 @@ import com.syncd.application.port.in.SyncProjectUsecase.*; import com.syncd.application.port.in.UpdateProjectUsecase.*; import com.syncd.application.port.in.WithdrawUserInProjectUsecase.*; +import com.syncd.domain.project.CoreDetails; +import com.syncd.domain.project.Epic; import com.syncd.dto.MakeUserStoryReauestDto; import com.syncd.exceptions.ValidationMessages; import jakarta.validation.ConstraintViolation; @@ -16,6 +18,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; import java.util.*; @@ -251,7 +255,7 @@ void testUpdateProject_ValidRequest() { @Test @DisplayName("Sync Project - Invalid Request - Blank ProjectId") void testSyncProject_InvalidRequest_BlankProjectId() { - SyncProjectRequestDto requestDto = new SyncProjectRequestDto("", 10); + SyncProjectRequestDto requestDto = createSyncProjectRequestDtoWithDefaults("", 10); Set> violations = validator.validate(requestDto); assertThat(violations).hasSize(1); @@ -261,7 +265,7 @@ void testSyncProject_InvalidRequest_BlankProjectId() { @Test @DisplayName("Sync Project - Invalid Request - Null Project Stage") void testSyncProject_InvalidRequest_NullProjectStage() { - SyncProjectRequestDto requestDto = new SyncProjectRequestDto("validProjectId", null); + SyncProjectRequestDto requestDto = createSyncProjectRequestDtoWithDefaults("validProjectId", null); Set> violations = validator.validate(requestDto); assertThat(violations).hasSize(1); @@ -271,7 +275,7 @@ void testSyncProject_InvalidRequest_NullProjectStage() { @Test @DisplayName("Sync Project - Valid Request") void testSyncProject_ValidRequest() { - SyncProjectRequestDto requestDto = new SyncProjectRequestDto("validProjectId", 10); + SyncProjectRequestDto requestDto = createSyncProjectRequestDtoWithDefaults("validProjectId", 10); Set> violations = validator.validate(requestDto); assertThat(violations).isEmpty(); @@ -333,4 +337,37 @@ void testMakeUserStory_ValidRequest() { Set> violations = validator.validate(requestDto); assertThat(violations).isEmpty(); } + + // ====================================== + // Helper Methods + // ====================================== + + private SyncProjectRequestDto createSyncProjectRequestDtoWithDefaults(String projectId, Integer projectStage) { + return createSyncProjectRequestDto( + projectId, projectStage, "problem", + createMockMultipartFile(), createMockMultipartFile(), + "{}", // JSON string for coreDetails + createMockMultipartFile(), + "[]", // JSON string for epics + createMockMultipartFile() + ); + } + + + private SyncProjectRequestDto createSyncProjectRequestDto( + String projectId, Integer projectStage, String problem, + MultipartFile personaImage, MultipartFile whyWhatHowImage, String coreDetails, + MultipartFile businessModelImage, String epics, MultipartFile menuTreeImage) { + return new SyncProjectRequestDto( + projectId, projectStage, problem, + coreDetails, epics, + personaImage, whyWhatHowImage, + businessModelImage, menuTreeImage + ); + } + + private MockMultipartFile createMockMultipartFile() { + return new MockMultipartFile("file", "filename.txt", "text/plain", "content".getBytes()); + } + } \ No newline at end of file diff --git a/src/test/java/application/service/ProjectServiceTest.java b/src/test/java/application/service/ProjectServiceTest.java index e0eeb4e..e675b5b 100644 --- a/src/test/java/application/service/ProjectServiceTest.java +++ b/src/test/java/application/service/ProjectServiceTest.java @@ -18,6 +18,8 @@ import com.syncd.application.port.out.openai.ChatGPTPort; import com.syncd.application.port.out.s3.S3Port; import com.syncd.application.service.ProjectService; +import com.syncd.domain.project.CoreDetails; +import com.syncd.domain.project.Epic; import com.syncd.domain.project.Project; import com.syncd.domain.project.UserInProject; import com.syncd.domain.user.User; @@ -206,10 +208,14 @@ void syncProject() { String userId = Consistent.UserId.getValue(); String projectId = Consistent.ProjectId.getValue(); int projectStage = 1; - + MultipartFile mockFile = mock(MultipartFile.class); // When - SyncProjectUsecase.SyncProjectResponseDto response = projectService.syncProject(userId, projectId, projectStage); - + SyncProjectUsecase.SyncProjectResponseDto response = projectService.syncProject( + userId, projectId, projectStage, + "problem", + mockFile, mockFile, "{}", mockFile, + "[]", mockFile + ); // Then assertNotNull(response); assertEquals(projectId, response.projectId()); diff --git a/src/test/java/application/service/UserServiceTest.java b/src/test/java/application/service/UserServiceTest.java index 6dba461..0fc120e 100644 --- a/src/test/java/application/service/UserServiceTest.java +++ b/src/test/java/application/service/UserServiceTest.java @@ -59,10 +59,10 @@ public void testGetUserInfo() { GetAllRoomsByUserIdUsecase.ProjectForGetAllInfoAboutRoomsByUserIdResponseDto project1 = new GetAllRoomsByUserIdUsecase.ProjectForGetAllInfoAboutRoomsByUserIdResponseDto( - "project1", "1", "description1", Role.HOST, List.of("user1@example.com"), 0, "2024-05-19"); + "project1", "1", "description1", Role.HOST, List.of("user1@example.com"), 0, "2024-05-19","img"); GetAllRoomsByUserIdUsecase.ProjectForGetAllInfoAboutRoomsByUserIdResponseDto project2 = new GetAllRoomsByUserIdUsecase.ProjectForGetAllInfoAboutRoomsByUserIdResponseDto( - "project2", "2", "description2", Role.MEMBER, List.of("user2@example.com"), 50, "2024-05-20"); + "project2", "2", "description2", Role.MEMBER, List.of("user2@example.com"), 50, "2024-05-20","img"); GetAllRoomsByUserIdUsecase.GetAllRoomsByUserIdResponseDto projects = new GetAllRoomsByUserIdUsecase.GetAllRoomsByUserIdResponseDto(userId, List.of(project1, project2));