From 45401073759582e38f6f24be8923ca2398b1f194 Mon Sep 17 00:00:00 2001 From: miyeon lee Date: Thu, 26 Oct 2023 11:08:45 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B3=B5=EC=9C=A0=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=20=EC=99=B8=EB=B6=80=20=EA=B3=B5=EA=B0=9C=20api=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20=EC=99=84=EB=A3=8C=20(#205)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : ApiStatus에 forbidden 추가 (#204) * feat : IsPublicUpdateRequest DTO 생성 (#204) * refactor : shareURL로 공유페이지 접속하는 url 수정 (#204) * feat : SpaceWall엔티티에 isPublic 컬럼 추가 (#204) - 공유페이지 저장시엔 설정이 안되기 때문에 @ColumnDefault로 디폴트 값 false로 설정 * feat : updateIsPublic 컨트롤러 메서드 생성 및 findByshareURL url 수정 (#204) * feat : shareURL로 공유페이지 접근 시 외부공개 여부 체크하여 예외처리 (#204) * refactor : db에 중복된 shareURL이 있을 경우 예외처리 추가 (#204) * refactor : SpaceWallResponse에 memberId제거 및 isPublic 추가 (#204) * feat : updateIsPublic 서비스 메소드 생성 (#204) * modify : request변수명 수정 (#204) * modify : updateIsPublic컨트롤러 메서드 응답 수정 (#204) * refactor : 파일첨부가 되지 않은 파일블록이 있을 경우 예외처리 (#204) --- .../javajober/core/exception/ApiStatus.java | 3 +- .../core/security/SecurityConfig.java | 42 +++++++++---------- .../controller/SpaceWallController.java | 13 +++++- .../javajober/spaceWall/domain/SpaceWall.java | 15 ++++++- .../dto/request/IsPublicUpdateRequest.java | 20 +++++++++ .../dto/response/SpaceWallResponse.java | 6 +-- .../repository/SpaceWallRepository.java | 9 +++- .../spaceWall/service/FileUploadService.java | 27 ++++++------ .../service/SpaceWallFindService.java | 19 +++++---- .../spaceWall/service/SpaceWallService.java | 11 +++++ 10 files changed, 117 insertions(+), 48 deletions(-) create mode 100644 src/main/java/com/javajober/spaceWall/dto/request/IsPublicUpdateRequest.java diff --git a/src/main/java/com/javajober/core/exception/ApiStatus.java b/src/main/java/com/javajober/core/exception/ApiStatus.java index f97cf7b..ef1d8cc 100644 --- a/src/main/java/com/javajober/core/exception/ApiStatus.java +++ b/src/main/java/com/javajober/core/exception/ApiStatus.java @@ -22,7 +22,8 @@ public enum ApiStatus { INVALID_DATE(HttpStatus.BAD_REQUEST, "invalid date"), NOT_FOUND(HttpStatus.NOT_FOUND, "data not found"), PAYLOAD_TOO_LARGE(HttpStatus.PAYLOAD_TOO_LARGE, "Payload Too Large"), - UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "login token expire"); + UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "login token expire"), + FORBIDDEN(HttpStatus.FORBIDDEN, "forbidden");; private final HttpStatus httpStatus; private final String message; diff --git a/src/main/java/com/javajober/core/security/SecurityConfig.java b/src/main/java/com/javajober/core/security/SecurityConfig.java index b8373c4..2ef6ba9 100644 --- a/src/main/java/com/javajober/core/security/SecurityConfig.java +++ b/src/main/java/com/javajober/core/security/SecurityConfig.java @@ -19,7 +19,7 @@ public class SecurityConfig { private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint; public SecurityConfig(AuthenticationManagerConfig authenticationManagerConfig, - CustomAuthenticationEntryPoint customAuthenticationEntryPoint) { + CustomAuthenticationEntryPoint customAuthenticationEntryPoint) { this.authenticationManagerConfig = authenticationManagerConfig; this.customAuthenticationEntryPoint = customAuthenticationEntryPoint; } @@ -27,26 +27,26 @@ public SecurityConfig(AuthenticationManagerConfig authenticationManagerConfig, @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //세션 사용 x 설정 - .and() - .formLogin().disable() - .csrf().disable() - .cors() - .and() - .apply(authenticationManagerConfig) - .and() - .httpBasic().disable() - .authorizeRequests() - .antMatchers("/api/members/login").permitAll() - .antMatchers("/api/members/signup").permitAll() - .antMatchers("/healthCheck").permitAll() - .antMatchers("/api/wall/shareURL/**").permitAll() - .anyRequest().authenticated() - .and() - .exceptionHandling() - .authenticationEntryPoint(customAuthenticationEntryPoint) - .and() - .build(); + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //세션 사용 x 설정 + .and() + .formLogin().disable() + .csrf().disable() + .cors() + .and() + .apply(authenticationManagerConfig) + .and() + .httpBasic().disable() + .authorizeRequests() + .antMatchers("/api/members/login").permitAll() + .antMatchers("/api/members/signup").permitAll() + .antMatchers("/healthCheck").permitAll() + .antMatchers("/api/wall/{shareURL}").permitAll() + .anyRequest().authenticated() + .and() + .exceptionHandling() + .authenticationEntryPoint(customAuthenticationEntryPoint) + .and() + .build(); } public CorsConfigurationSource corsConfigurationSource() { diff --git a/src/main/java/com/javajober/spaceWall/controller/SpaceWallController.java b/src/main/java/com/javajober/spaceWall/controller/SpaceWallController.java index d9a8cc8..c46b582 100644 --- a/src/main/java/com/javajober/spaceWall/controller/SpaceWallController.java +++ b/src/main/java/com/javajober/spaceWall/controller/SpaceWallController.java @@ -6,6 +6,7 @@ import com.javajober.core.util.ApiUtils; import com.javajober.core.exception.ApiStatus; import com.javajober.spaceWall.domain.FlagType; +import com.javajober.spaceWall.dto.request.IsPublicUpdateRequest; import com.javajober.spaceWall.dto.request.SpaceWallStringRequest; import com.javajober.spaceWall.dto.request.SpaceWallStringUpdateRequest; import com.javajober.spaceWall.dto.response.DuplicateURLResponse; @@ -84,7 +85,7 @@ public ResponseEntity> findPending( return ApiResponse.response(ApiStatus.OK, "공유페이지 임시 저장 조회를 성공했습니다.", data); } - @GetMapping("/wall/shareURL/{shareURL}") + @GetMapping("/wall/{shareURL}") public ResponseEntity> findByShareURL(@PathVariable final String shareURL) { SpaceWallResponse data = spaceWallFindService.findByShareURL(shareURL); @@ -118,4 +119,14 @@ public ResponseEntity deleteTemporary(@PathVariable return ApiResponse.messageResponse(ApiStatus.OK, "공유페이지 임시 저장 삭제를 성공했습니다."); } + + @PutMapping("/wall/public") + public ResponseEntity updateIsPublic(@RequestBody IsPublicUpdateRequest isPublicUpdateRequest, + @RequestHeader("Authorization") String token) { + + Long memberId = jwtTokenizer.getUserIdFromToken(token); + spaceWallService.updateIsPublic(isPublicUpdateRequest, memberId); + + return ApiResponse.messageResponse(ApiStatus.OK, "외부 공개 여부가 업데이트 되었습니다."); + } } \ No newline at end of file diff --git a/src/main/java/com/javajober/spaceWall/domain/SpaceWall.java b/src/main/java/com/javajober/spaceWall/domain/SpaceWall.java index fcd3362..da3ba4e 100644 --- a/src/main/java/com/javajober/spaceWall/domain/SpaceWall.java +++ b/src/main/java/com/javajober/spaceWall/domain/SpaceWall.java @@ -8,6 +8,8 @@ import lombok.Builder; import lombok.Getter; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.DynamicInsert; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @@ -15,6 +17,7 @@ import javax.persistence.*; import java.time.LocalDateTime; +@DynamicInsert @Getter @Table(name = "space_wall") @EntityListeners(AuditingEntityListener.class) @@ -47,6 +50,10 @@ public class SpaceWall { @Column(name = "flag", nullable = false) private FlagType flag; + @ColumnDefault("false") + @Column(name = "is_public") + private Boolean isPublic; + @CreatedDate @Column(name = "created_at") private LocalDateTime createdAt; @@ -64,13 +71,14 @@ protected SpaceWall() { @Builder public SpaceWall(final String blocks, final String shareURL, final AddSpace addSpace, final Member member, - final SpaceWallCategoryType spaceWallCategoryType, final FlagType flag) { + final SpaceWallCategoryType spaceWallCategoryType, final FlagType flag, final Boolean isPublic) { this.blocks = blocks; this.shareURL = shareURL; this.addSpace = addSpace; this.member = member; this.spaceWallCategoryType = spaceWallCategoryType; this.flag = flag; + this.isPublic = isPublic; } public void update(final DataStringUpdateRequest request, final FlagType flag, final String blockInfoArrayAsString){ @@ -78,9 +86,14 @@ public void update(final DataStringUpdateRequest request, final FlagType flag, f this.shareURL = request.getShareURL(); this.flag = flag; } + public void fileUpdate(final DataUpdateRequest request, final FlagType flag, final String blockInfoArrayAsString){ this.blocks = blockInfoArrayAsString; this.shareURL = request.getShareURL(); this.flag = flag; } + + public void updateIsPublic(final Boolean isPublic) { + this.isPublic = isPublic; + } } \ No newline at end of file diff --git a/src/main/java/com/javajober/spaceWall/dto/request/IsPublicUpdateRequest.java b/src/main/java/com/javajober/spaceWall/dto/request/IsPublicUpdateRequest.java new file mode 100644 index 0000000..5285d8c --- /dev/null +++ b/src/main/java/com/javajober/spaceWall/dto/request/IsPublicUpdateRequest.java @@ -0,0 +1,20 @@ +package com.javajober.spaceWall.dto.request; + +import lombok.Getter; + +@Getter +public class IsPublicUpdateRequest { + + private Long spaceId; + private Long spaceWallId; + private Boolean isPublic; + + public IsPublicUpdateRequest() { + } + + public IsPublicUpdateRequest(final Long spaceId, final Long spaceWallId, final Boolean isPublic) { + this.spaceId = spaceId; + this.spaceWallId = spaceWallId; + this.isPublic = isPublic; + } +} diff --git a/src/main/java/com/javajober/spaceWall/dto/response/SpaceWallResponse.java b/src/main/java/com/javajober/spaceWall/dto/response/SpaceWallResponse.java index 3454bb1..ea4d5bc 100644 --- a/src/main/java/com/javajober/spaceWall/dto/response/SpaceWallResponse.java +++ b/src/main/java/com/javajober/spaceWall/dto/response/SpaceWallResponse.java @@ -10,8 +10,8 @@ public class SpaceWallResponse { private String category; - private Long memberId; private Long spaceId; + private Boolean isPublic; private String shareURL; private CommonResponse wallInfoBlock; private List> blocks; @@ -20,12 +20,12 @@ public class SpaceWallResponse { private SpaceWallResponse() {} @Builder - public SpaceWallResponse(final String category, final Long memberId, final Long spaceId, final String shareURL, final CommonResponse wallInfoBlock, + public SpaceWallResponse(final String category, final Long spaceId, final Boolean isPublic, final String shareURL, final CommonResponse wallInfoBlock, final List> blocks, final CommonResponse styleSetting) { this.category = category; - this.memberId = memberId; this.spaceId = spaceId; + this.isPublic = isPublic; this.shareURL = shareURL; this.wallInfoBlock = wallInfoBlock; this.blocks = blocks; diff --git a/src/main/java/com/javajober/spaceWall/repository/SpaceWallRepository.java b/src/main/java/com/javajober/spaceWall/repository/SpaceWallRepository.java index 6509065..89d827a 100644 --- a/src/main/java/com/javajober/spaceWall/repository/SpaceWallRepository.java +++ b/src/main/java/com/javajober/spaceWall/repository/SpaceWallRepository.java @@ -4,6 +4,7 @@ import com.javajober.core.exception.ApplicationException; import com.javajober.spaceWall.domain.FlagType; import com.javajober.spaceWall.domain.SpaceWall; +import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; import org.springframework.data.repository.query.Param; @@ -51,7 +52,11 @@ default SpaceWall findSpaceWall(Long id, Long addSpaceId, Long memberId, FlagTyp } default SpaceWall getByShareURL(final String shareURL) { - return findByShareURL(shareURL) - .orElseThrow(() -> new ApplicationException(ApiStatus.NOT_FOUND, "존재하지 않는 shareURL입니다.")); + try { + return findByShareURL(shareURL) + .orElseThrow(() -> new ApplicationException(ApiStatus.NOT_FOUND, "존재하지 않는 shareURL입니다.")); + } catch (IncorrectResultSizeDataAccessException e) { + throw new ApplicationException(ApiStatus.EXCEPTION, "중복된 shareURL이 존재합니다."); + } } } \ No newline at end of file diff --git a/src/main/java/com/javajober/spaceWall/service/FileUploadService.java b/src/main/java/com/javajober/spaceWall/service/FileUploadService.java index a62a165..ecdbf7a 100644 --- a/src/main/java/com/javajober/spaceWall/service/FileUploadService.java +++ b/src/main/java/com/javajober/spaceWall/service/FileUploadService.java @@ -190,23 +190,26 @@ private void processWallInfoBlock(final MultipartFile backgroundImgURL, final Mu private void processBlocks(final List> blocks, final ArrayNode blockInfoArray, final AtomicLong blocksPositionCounter, final List files) { + try { + AtomicInteger fileIndexCounter = new AtomicInteger(); - AtomicInteger fileIndexCounter = new AtomicInteger(); + blocks.forEach(block -> { - blocks.forEach(block -> { + BlockType blockType = BlockType.findBlockTypeByString(block.getBlockType()); + Long position = blocksPositionCounter.getAndIncrement(); - BlockType blockType = BlockType.findBlockTypeByString(block.getBlockType()); - Long position = blocksPositionCounter.getAndIncrement(); - - String strategyName = blockType.getStrategyName(); - MoveBlockStrategy blockProcessingStrategy = blockStrategyFactory.findMoveBlockStrategy(strategyName); + String strategyName = blockType.getStrategyName(); + MoveBlockStrategy blockProcessingStrategy = blockStrategyFactory.findMoveBlockStrategy(strategyName); - if (BlockStrategyName.FileBlockStrategy.name().equals(blockProcessingStrategy.getStrategyName())) { - blockProcessingStrategy.uploadFile(files.get(fileIndexCounter.getAndIncrement())); - } + if (BlockStrategyName.FileBlockStrategy.name().equals(blockProcessingStrategy.getStrategyName())) { + blockProcessingStrategy.uploadFile(files.get(fileIndexCounter.getAndIncrement())); + } - blockProcessingStrategy.saveBlocks(block, blockInfoArray, position); - }); + blockProcessingStrategy.saveBlocks(block, blockInfoArray, position); + }); + } catch (IndexOutOfBoundsException e) { + throw new ApplicationException(ApiStatus.INVALID_DATA, "파일이 첨부되지 않은 파일블록이 있습니다."); + } } private void processStyleSettingBlock(final MultipartFile styleImgURL, final DataSaveRequest data, final ArrayNode blockInfoArray, diff --git a/src/main/java/com/javajober/spaceWall/service/SpaceWallFindService.java b/src/main/java/com/javajober/spaceWall/service/SpaceWallFindService.java index 91c6d89..2e63d76 100644 --- a/src/main/java/com/javajober/spaceWall/service/SpaceWallFindService.java +++ b/src/main/java/com/javajober/spaceWall/service/SpaceWallFindService.java @@ -49,6 +49,9 @@ public DuplicateURLResponse hasDuplicateShareURL(final String shareURL) { public SpaceWallResponse findByShareURL(final String shareURL) { SpaceWall spaceWall = spaceWallRepository.getByShareURL(shareURL); + if (!spaceWall.getIsPublic()) { + throw new ApplicationException(ApiStatus.FORBIDDEN, "공유페이지에 접근 권한이 없습니다."); + } Long memberId = spaceWall.getMember().getId(); Long spaceId = spaceWall.getAddSpace().getId(); Long spaceWallId = spaceWall.getId(); @@ -67,15 +70,16 @@ public SpaceWallResponse find(final Long memberId, final Long spaceId, final Lon String category = spaceWall.getSpaceWallCategoryType().getEngTitle(); String shareURL = spaceWall.getShareURL(); + Boolean isPublic = spaceWall.getIsPublic(); - return new SpaceWallResponse(category, memberId, spaceId, shareURL, wallInfoBlockResponse, blocks, styleSettingResponse); + return new SpaceWallResponse(category, spaceId, isPublic, shareURL, wallInfoBlockResponse, blocks, styleSettingResponse); } private CommonResponse createWallInfoBlock(Map> groupedBlockByPosition) { List wallInfoBlocks = groupedBlockByPosition.get(INITIAL_POSITION); if (wallInfoBlocks == null || wallInfoBlocks.isEmpty()) { - throw new ApplicationException(ApiStatus.NOT_FOUND, "wallInfoBlock 조회를 실패했습니다."); + throw new ApplicationException(ApiStatus.FAIL, "wallInfoBlock 조회를 실패했습니다."); } FixBlockStrategy blockStrategy = blockStrategyFactory.findFixBlockStrategy(getBlockTypeStrategyName(wallInfoBlocks)); @@ -85,16 +89,17 @@ private CommonResponse createWallInfoBlock(Map> groupedBloc private CommonResponse createStyleSettingBlock(Map> groupedBlockByPosition) { Long endPosition = groupedBlockByPosition.keySet().stream() .max(Long::compareTo) - .orElseThrow(() -> new ApplicationException(ApiStatus.NOT_FOUND, "endPosition이 없습니다.")); + .orElseThrow(() -> new ApplicationException(ApiStatus.FAIL, "endPosition이 없습니다.")); List styleSettingBlocks = groupedBlockByPosition.get(endPosition); String blockTypeString = styleSettingBlocks.get(0).path(BLOCK_TYPE_KEY).asText(); - if (blockTypeString.equals(BlockType.STYLE_SETTING.getEngTitle())) { - FixBlockStrategy blockStrategy = blockStrategyFactory.findFixBlockStrategy(getBlockTypeStrategyName(styleSettingBlocks)); - return blockStrategy.createFixBlockDTO(styleSettingBlocks); + if (!blockTypeString.equals(BlockType.STYLE_SETTING.name())) { + throw new ApplicationException(ApiStatus.FAIL, "styleSetting 조회를 실패하였습니다."); } - return null; + + FixBlockStrategy blockStrategy = blockStrategyFactory.findFixBlockStrategy(getBlockTypeStrategyName(styleSettingBlocks)); + return blockStrategy.createFixBlockDTO(styleSettingBlocks); } private List> createBlockResponses(Map> groupedBlockByPosition) { diff --git a/src/main/java/com/javajober/spaceWall/service/SpaceWallService.java b/src/main/java/com/javajober/spaceWall/service/SpaceWallService.java index c35c44a..74e083a 100644 --- a/src/main/java/com/javajober/spaceWall/service/SpaceWallService.java +++ b/src/main/java/com/javajober/spaceWall/service/SpaceWallService.java @@ -196,6 +196,17 @@ private Long saveSpaceWall(final SpaceWallCategoryType spaceWallCategoryType, fi return spaceWallRepository.save(spaceWall).getId(); } + @Transactional + public void updateIsPublic(IsPublicUpdateRequest publicUpdateRequest, Long memberId) { + Long spaceId = publicUpdateRequest.getSpaceId(); + Long spaceWallId = publicUpdateRequest.getSpaceWallId(); + SpaceWall spaceWall = spaceWallRepository.findSpaceWall(spaceWallId, spaceId, memberId, FlagType.SAVED); + + Boolean isPublic = publicUpdateRequest.getIsPublic(); + spaceWall.updateIsPublic(isPublic); + spaceWallRepository.save(spaceWall); + } + @Transactional public SpaceWallSaveResponse update(final Long memberId, final SpaceWallStringUpdateRequest spaceWallUpdateRequest, final FlagType flagType) {