diff --git a/src/main/java/com/haedal/haedalweb/config/SecurityConfig.java b/src/main/java/com/haedal/haedalweb/config/SecurityConfig.java index 830f623..b172f67 100644 --- a/src/main/java/com/haedal/haedalweb/config/SecurityConfig.java +++ b/src/main/java/com/haedal/haedalweb/config/SecurityConfig.java @@ -78,6 +78,7 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .requestMatchers("/boards/generate-presigned-url").hasAnyRole("WEB_MASTER", "ADMIN", "TEAM_LEADER") .requestMatchers(HttpMethod.POST, "/activities/{activityId}/boards").hasAnyRole("WEB_MASTER", "ADMIN", "TEAM_LEADER") .requestMatchers(HttpMethod.DELETE, "/activities/{activityId}/boards/{boardId}").hasAnyRole("WEB_MASTER", "ADMIN", "TEAM_LEADER") + .requestMatchers(HttpMethod.PATCH, "/activities/{activityId}/boards/{boardId}/**").hasAnyRole("WEB_MASTER", "ADMIN", "TEAM_LEADER") .requestMatchers("/activities/{activityId}/boards","/activities/{activityId}/boards/{boardId}","/login", "/", "/join/**", "/reissue", "/swagger-ui/**", "/v3/api-docs/**", "/users/**","/semesters/**").permitAll() .anyRequest().authenticated()); diff --git a/src/main/java/com/haedal/haedalweb/constants/ErrorCode.java b/src/main/java/com/haedal/haedalweb/constants/ErrorCode.java index 4c26794..07649da 100644 --- a/src/main/java/com/haedal/haedalweb/constants/ErrorCode.java +++ b/src/main/java/com/haedal/haedalweb/constants/ErrorCode.java @@ -25,7 +25,7 @@ public enum ErrorCode implements ResponseCode{ EXIST_ACTIVITY(HttpStatus.CONFLICT, "016", "해당 학기에 활동이 존재하는 경우 삭제할 수 없습니다."), EXIST_BOARD(HttpStatus.CONFLICT, "017", "해당 활동에 게시판이 존재하는 경우 삭제할 수 없습니다."), NOT_FOUND_BOARD_ID(HttpStatus.NOT_FOUND, "018", "해당 게시판을 찾을 수 없습니다."), - FORBIDDEN_DELETE(HttpStatus.FORBIDDEN, "019", "삭제 권한이 없습니다."); + FORBIDDEN_UPDATE(HttpStatus.FORBIDDEN, "019", "삭제 권한이 없습니다."); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/com/haedal/haedalweb/constants/SuccessCode.java b/src/main/java/com/haedal/haedalweb/constants/SuccessCode.java index e2e49d1..500a22e 100644 --- a/src/main/java/com/haedal/haedalweb/constants/SuccessCode.java +++ b/src/main/java/com/haedal/haedalweb/constants/SuccessCode.java @@ -24,7 +24,8 @@ public enum SuccessCode implements ResponseCode{ ADD_ACTIVITY_SUCCESS(HttpStatus.CREATED, true, "활동을 추가했습니다."), DELETE_ACTIVITY_SUCCESS(HttpStatus.OK, true, "활동을 삭제했습니다."), ADD_BOARD_SUCCESS(HttpStatus.CREATED, true, "게시판을 생성했습니다."), - DELETE_BOARD_SUCCESS(HttpStatus.OK, true, "게시판을 삭제했습니다."); + DELETE_BOARD_SUCCESS(HttpStatus.OK, true, "게시판을 삭제했습니다."), + UPDATE_BOARD_SUCCESS(HttpStatus.OK, true, "게시판을 수정했습니다."); private final HttpStatus httpStatus; diff --git a/src/main/java/com/haedal/haedalweb/controller/BoardController.java b/src/main/java/com/haedal/haedalweb/controller/BoardController.java index ec707cd..1ab5f9b 100644 --- a/src/main/java/com/haedal/haedalweb/controller/BoardController.java +++ b/src/main/java/com/haedal/haedalweb/controller/BoardController.java @@ -3,6 +3,7 @@ import com.haedal.haedalweb.constants.ErrorCode; import com.haedal.haedalweb.constants.SuccessCode; import com.haedal.haedalweb.dto.request.CreateBoardDTO; +import com.haedal.haedalweb.dto.request.UpdateBoardDTO; import com.haedal.haedalweb.dto.response.BoardDTO; import com.haedal.haedalweb.dto.response.PreSignedUrlDTO; import com.haedal.haedalweb.dto.response.common.SuccessResponse; @@ -14,6 +15,8 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -23,6 +26,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -88,7 +92,7 @@ public ResponseEntity getBoard(@PathVariable Long activityId, @PathVar @Operation(summary = "게시판 삭제") @ApiSuccessCodeExample(SuccessCode.DELETE_BOARD_SUCCESS) - @ApiErrorCodeExamples({ErrorCode.NOT_FOUND_BOARD_ID, ErrorCode.FORBIDDEN_DELETE}) + @ApiErrorCodeExamples({ErrorCode.NOT_FOUND_BOARD_ID, ErrorCode.FORBIDDEN_UPDATE}) @Parameters({ @Parameter(name = "activityId", description = "게시판 삭제할 활동 ID"), @Parameter(name = "boardId", description = "해당 게시판 ID") @@ -99,4 +103,32 @@ public ResponseEntity deleteBoard(@PathVariable Long activityId return ResponseUtil.buildSuccessResponseEntity(SuccessCode.DELETE_BOARD_SUCCESS); } + + @Operation(summary = "게시판 이미지 수정") + @ApiSuccessCodeExample(SuccessCode.UPDATE_BOARD_SUCCESS) + @ApiErrorCodeExamples({ErrorCode.NOT_FOUND_BOARD_ID, ErrorCode.FORBIDDEN_UPDATE}) + @Parameters({ + @Parameter(name = "activityId", description = "게시판 삭제할 활동 ID"), + @Parameter(name = "boardId", description = "해당 게시판 ID") + }) + @PatchMapping("/activities/{activityId}/boards/{boardId}/image") + public ResponseEntity updateBoardImage(@PathVariable Long activityId, @PathVariable Long boardId, @RequestBody String boardImageUrl) { + boardService.updateBoardImage(activityId, boardId, boardImageUrl); + + return ResponseUtil.buildSuccessResponseEntity(SuccessCode.UPDATE_BOARD_SUCCESS); + } + + @Operation(summary = "게시판 메타 데이터 수정") + @ApiSuccessCodeExample(SuccessCode.UPDATE_BOARD_SUCCESS) + @ApiErrorCodeExamples({ErrorCode.NOT_FOUND_BOARD_ID, ErrorCode.FORBIDDEN_UPDATE, ErrorCode.NOT_FOUND_USER_ID}) + @Parameters({ + @Parameter(name = "activityId", description = "게시판 수정할 활동 ID"), + @Parameter(name = "boardId", description = "해당 게시판 ID") + }) + @PatchMapping("/activities/{activityId}/boards/{boardId}") + public ResponseEntity updateBoard(@PathVariable Long activityId, @PathVariable Long boardId, @RequestBody @Valid UpdateBoardDTO updateBoardDTO) { + boardService.updateBoard(activityId, boardId, updateBoardDTO); + + return ResponseUtil.buildSuccessResponseEntity(SuccessCode.UPDATE_BOARD_SUCCESS); + } } diff --git a/src/main/java/com/haedal/haedalweb/dto/request/UpdateBoardDTO.java b/src/main/java/com/haedal/haedalweb/dto/request/UpdateBoardDTO.java new file mode 100644 index 0000000..a248da8 --- /dev/null +++ b/src/main/java/com/haedal/haedalweb/dto/request/UpdateBoardDTO.java @@ -0,0 +1,26 @@ +package com.haedal.haedalweb.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.Set; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class UpdateBoardDTO { + @Schema(description = "게시판 이름", example = "게시판1") + @Pattern(regexp = "^[가-힣a-zA-Z0-9]*$", message = "영어, 숫자, 한글만 입력가능합니다.") + @Size(min = 1, max = 15, message = "게시판 이름은 1자 이상 15자 이하여야 합니다.") + private String boardName; + + @Schema(description = "게시판 소개", example = "이 게시판에 대한 소개글") + @Size(max = 50, message = "게시판 소개는 50자 이하여야 합니다.") + private String boardIntro; + + @Schema(description = "참여 인원 ID", allowableValues = {"haedal1234", "good1234"}) + private Set participants; +} diff --git a/src/main/java/com/haedal/haedalweb/service/BoardService.java b/src/main/java/com/haedal/haedalweb/service/BoardService.java index f4bf2f1..bbfef76 100644 --- a/src/main/java/com/haedal/haedalweb/service/BoardService.java +++ b/src/main/java/com/haedal/haedalweb/service/BoardService.java @@ -8,6 +8,7 @@ import com.haedal.haedalweb.domain.User; import com.haedal.haedalweb.domain.UserStatus; import com.haedal.haedalweb.dto.request.CreateBoardDTO; +import com.haedal.haedalweb.dto.request.UpdateBoardDTO; import com.haedal.haedalweb.dto.response.BoardDTO; import com.haedal.haedalweb.dto.response.ParticipantDTO; import com.haedal.haedalweb.exception.BusinessException; @@ -79,13 +80,51 @@ public void deleteBoard(Long activityId, Long boardId) { User loggedInUser = userService.getLoggedInUser(); User creator = board.getUser(); - validateAuthorityOfBoardDelete(loggedInUser, creator); + validateAuthorityOfBoardManagement(loggedInUser, creator); // 게시글 존재 시 삭제 불가 로직 추가 예정 s3Service.deleteObject(board.getImageUrl()); boardRepository.delete(board); } + @Transactional + public void updateBoardImage(Long activityId, Long boardId, String newImageUrl) { + Board board = boardRepository.findByActivityIdAndId(activityId, boardId) + .orElseThrow(() -> new BusinessException(ErrorCode.NOT_FOUND_BOARD_ID)); + + User loggedInUser = userService.getLoggedInUser(); + User creator = board.getUser(); + + validateAuthorityOfBoardManagement(loggedInUser, creator); + + s3Service.deleteObject(board.getImageUrl()); + board.setImageUrl(newImageUrl); + boardRepository.save(board); + } + + @Transactional + public void updateBoard(Long activityId, Long boardId, UpdateBoardDTO updateBoardDTO) { + Board board = boardRepository.findByActivityIdAndId(activityId, boardId) + .orElseThrow(() -> new BusinessException(ErrorCode.NOT_FOUND_BOARD_ID)); + + User loggedInUser = userService.getLoggedInUser(); + User creator = board.getUser(); + + validateAuthorityOfBoardManagement(loggedInUser, creator); + + List participantIds = new ArrayList<>(updateBoardDTO.getParticipants()); + List participants = userService.findUserByIds(participantIds); + + validateParticipants(participants, participantIds); + + board.setName(updateBoardDTO.getBoardName()); + board.setIntro(updateBoardDTO.getBoardIntro()); + board.setParticipants(new ArrayList<>()); + addParticipantsToBoard(board, participants); + + boardRepository.save(board); + } + private void addParticipantsToBoard(Board board, List participants) { for (User user : participants) { Participant participant = Participant.builder() @@ -134,9 +173,9 @@ private ParticipantDTO convertToParticipantDTO(Participant participant) { .build(); } - private void validateAuthorityOfBoardDelete(User loggedInUser, User creator) { + private void validateAuthorityOfBoardManagement(User loggedInUser, User creator) { if (loggedInUser.getRole() == Role.ROLE_TEAM_LEADER && !loggedInUser.getId().equals(creator.getId())) { - throw new BusinessException(ErrorCode.FORBIDDEN_DELETE); + throw new BusinessException(ErrorCode.FORBIDDEN_UPDATE); } } }