diff --git a/src/main/java/space/space_spring/controller/ImageS3Controller.java b/src/main/java/space/space_spring/controller/ImageS3Controller.java index 4e5a7148..41be0232 100644 --- a/src/main/java/space/space_spring/controller/ImageS3Controller.java +++ b/src/main/java/space/space_spring/controller/ImageS3Controller.java @@ -20,7 +20,7 @@ public class ImageS3Controller { @PostMapping("") public ResponseEntity uploadImage(@RequestParam("file") MultipartFile file) { try { - String uploadedFileUrl = s3Uploader.upload(file, "test-image"); + String uploadedFileUrl = s3Uploader.upload(file, "test-image1"); return ResponseEntity.ok(uploadedFileUrl); } catch (IOException e) { return ResponseEntity.badRequest().body("Failed to upload image: " + e.getMessage()); diff --git a/src/main/java/space/space_spring/controller/VoiceRoomController.java b/src/main/java/space/space_spring/controller/VoiceRoomController.java index eb5d8f72..c2aad928 100644 --- a/src/main/java/space/space_spring/controller/VoiceRoomController.java +++ b/src/main/java/space/space_spring/controller/VoiceRoomController.java @@ -161,8 +161,11 @@ public BaseResponse updateVoiceRoom( } //해당 유저가 현재 space에 대해 관리자 권한을 갖고 있는지 확인 validateManagerPermission(userSpaceAuth); - //해당 voiceRoom이 해당 space에 속한것이 맞는지 확인 + for(PatchVoiceRoom.UpdateRoom updateRoom : patchVoiceRoom.getUpdateRoomList()) { + //해당 voiceRoomId가 존재하는지 확인 + validateVoiceRoom(updateRoom.getRoomId()); + //해당 voiceRoom이 해당 space에 속한것이 맞는지 확인 validateVoiceRoomInSpace(spaceId, updateRoom.getRoomId()); } @@ -181,6 +184,8 @@ public BaseResponse deleteVoiceRoom( //해당 유저가 현재 space에 대해 관리자 권한을 갖고 있는지 확인 validateManagerPermission(userSpaceAuth); + //해당 보이스룸이 존재하는지 확인 + validateVoiceRoom(voiceRoomId); //해당 voiceRoom이 해당 space에 속한것이 맞는지 확인 validateVoiceRoomInSpace(spaceId, voiceRoomId); diff --git a/src/main/java/space/space_spring/dao/VoiceRoomRepository.java b/src/main/java/space/space_spring/dao/VoiceRoomRepository.java index 7287e431..d3cea243 100644 --- a/src/main/java/space/space_spring/dao/VoiceRoomRepository.java +++ b/src/main/java/space/space_spring/dao/VoiceRoomRepository.java @@ -11,12 +11,15 @@ @Repository public interface VoiceRoomRepository extends JpaRepository { - //Todo limit 개수 만큼 가져오도록 기능과 파라미터 수정 - List findBySpace(Space space); - @Query("SELECT MAX(r.order) FROM VoiceRoom r WHERE r.space = :space") - Integer findMaxOrderBySpace(@Param("space") Space space); - boolean existsByVoiceRoomId(long voiceRoomId); - boolean existsByName(String voiceRoomName); - VoiceRoom findById(long Id); + @Query("SELECT v FROM VoiceRoom v WHERE v.space = :space AND v.status = 'ACTIVE'") + List findBySpace(@Param("space")Space space); + @Query("SELECT MAX(r.order) FROM VoiceRoom r WHERE r.space = :space AND r.status = 'ACTIVE'") + Integer findMaxOrderBySpace(@Param("space") Space space); + @Query("SELECT CASE WHEN COUNT(v) > 0 THEN true ELSE false END FROM VoiceRoom v WHERE v.voiceRoomId = :id AND v.status = 'ACTIVE'") + boolean existsByVoiceRoomId(@Param("id")long voiceRoomId); + @Query("SELECT CASE WHEN COUNT(v) > 0 THEN true ELSE false END FROM VoiceRoom v WHERE v.name = :voiceRoomName AND v.status = 'ACTIVE'") + boolean existsByName(@Param("voiceRoomName") String voiceRoomName); + @Query("SELECT v FROM VoiceRoom v WHERE v.voiceRoomId = :id AND v.status = 'ACTIVE'") + VoiceRoom findById(@Param("id") long Id); } diff --git a/src/main/java/space/space_spring/entity/BaseEntity.java b/src/main/java/space/space_spring/entity/BaseEntity.java index 300fed77..4019b8fb 100644 --- a/src/main/java/space/space_spring/entity/BaseEntity.java +++ b/src/main/java/space/space_spring/entity/BaseEntity.java @@ -36,5 +36,8 @@ protected void initializeBaseEntityFields() { onCreate(); } + public void updateActive() { this.status = "ACTIVE"; } + + public void updateInactive() { this.status = "INACTIVE"; } } diff --git a/src/main/java/space/space_spring/interceptor/UserSpaceValidationInterceptor.java b/src/main/java/space/space_spring/interceptor/UserSpaceValidationInterceptor.java index 062cd029..80031af8 100644 --- a/src/main/java/space/space_spring/interceptor/UserSpaceValidationInterceptor.java +++ b/src/main/java/space/space_spring/interceptor/UserSpaceValidationInterceptor.java @@ -42,11 +42,22 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons // URL에서 spaceId 추출 Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); - Long spaceId = Long.parseLong((String) pathVariables.get("spaceId")); + //Long spaceId; + try { + Long spaceId = Long.parseLong((String) pathVariables.get("spaceId")); + + if(spaceId==null){ + throw new CustomException(SPACE_ID_PATHVARIABLE_NULL); + } + request.setAttribute("userSpaceId",getUserSpace(spaceId,userId)); + System.out.print("userSpaceID:"+getUserSpace(spaceId,userId)); + return true; + + }catch (NumberFormatException e){ + throw new CustomException(SPACE_ID_PATHVARIABLE_ERROR); + + } - request.setAttribute("userSpaceId",getUserSpace(spaceId,userId)); - System.out.print("userSpaceID:"+getUserSpace(spaceId,userId)); - return true; } diff --git a/src/main/java/space/space_spring/response/status/BaseExceptionResponseStatus.java b/src/main/java/space/space_spring/response/status/BaseExceptionResponseStatus.java index 29e07c52..7fdf826c 100644 --- a/src/main/java/space/space_spring/response/status/BaseExceptionResponseStatus.java +++ b/src/main/java/space/space_spring/response/status/BaseExceptionResponseStatus.java @@ -19,6 +19,9 @@ public enum BaseExceptionResponseStatus implements ResponseStatus { URL_NOT_FOUND(2001, HttpStatus.BAD_REQUEST, "유효하지 않은 URL 입니다."), METHOD_NOT_ALLOWED(2002, HttpStatus.METHOD_NOT_ALLOWED, "해당 URL에서는 지원하지 않는 HTTP Method 입니다."), HTTP_MESSAGE_NOT_READABLE(2003, HttpStatus.BAD_REQUEST,"request body 양식에 문제가 있습니다"), + SPACE_ID_PATHVARIABLE_ERROR(2004,HttpStatus.BAD_REQUEST,"URL에 포함된 SPACE_ID 값이 잘못되었습니다."), + SPACE_ID_PATHVARIABLE_NULL(2005,HttpStatus.BAD_REQUEST,"URL에 포함된 SPACE_ID 값이 없습니다"), + /** * 3000: Server, Database 오류 (INTERNAL_SERVER_ERROR) diff --git a/src/main/java/space/space_spring/service/ChatRoomService.java b/src/main/java/space/space_spring/service/ChatRoomService.java index 3c732665..3b3ccebc 100644 --- a/src/main/java/space/space_spring/service/ChatRoomService.java +++ b/src/main/java/space/space_spring/service/ChatRoomService.java @@ -67,7 +67,10 @@ public ReadChatRoomResponse readChatRooms(Long userId, Long spaceId) { // TODO 6: 각 채팅방의 마지막으로 업데이트된 메시지 정보 find ChatMessage lastMsg = chattingDao.findTopByChatRoomIdOrderByCreatedAtDesc(cr.getId()); - LocalDateTime lastUpdateTime = cr.getCreatedAt().atZone(ZoneId.of("Asia/Seoul")).toLocalDateTime(); + LocalDateTime lastUpdateTime = cr.getCreatedAt() + .atZone(ZoneId.of("UTC")) // UTC로 해석 + .withZoneSameInstant(ZoneId.of("Asia/Seoul")) // 서울 시간대로 변환 + .toLocalDateTime(); // LocalDateTime으로 변환 HashMap lastContent = new HashMap<>(); lastContent.put("text", "메시지를 전송해보세요"); @@ -78,7 +81,11 @@ public ReadChatRoomResponse readChatRooms(Long userId, Long spaceId) { } // TODO 7: 각 채팅방의 안읽은 메시지 개수 계산 - LocalDateTime lastReadTime = userChatRoom.getLastReadTime().atZone(ZoneId.of("Asia/Seoul")).toLocalDateTime(); + LocalDateTime lastReadTime = userChatRoom.getLastReadTime() + .atZone(ZoneId.of("UTC")) // UTC로 해석 + .withZoneSameInstant(ZoneId.of("Asia/Seoul")) // 서울 시간대로 변환 + .toLocalDateTime(); // LocalDateTime으로 변환 + log.info("마지막으로 읽은 시간: " + lastReadTime); int unreadMsgCount = chattingDao.countByChatRoomIdAndCreatedAtBetween( cr.getId(), @@ -170,10 +177,20 @@ public ChatSuccessResponse joinChatRoom(Long chatRoomId, JoinChatRoomRequest joi // TODO 2: 유저가 이미 채팅방에 초대되어있는지 검증 if (isUserInChatRoom(userByUserId, chatRoomByChatRoomId)) { - throw new CustomException(USER_IS_ALREADY_IN_CHAT_ROOM); + // TODO 3: 유저가 채팅방에 초대된 이력이 있다면 userChatRoom의 status 변경 + if (userByUserId.getStatus().equals("INACTIVE")) { + UserChatRoom userChatRoom = userChatRoomDao.findByUserAndChatRoom(userByUserId, chatRoomByChatRoomId); + userChatRoom.setLastReadTime(LocalDateTime.now()); + userChatRoom.updateActive(); + userChatRoomDao.save(userChatRoom); + return ChatSuccessResponse.of(true); + } else { + // TODO 4: 유저가 채팅방에 초대되어있고 ACTIVE이므로 예외 발생 + throw new CustomException(USER_IS_ALREADY_IN_CHAT_ROOM); + } } - // TODO 3: 초대한 유저에 대한 userChatRoom 테이블 생성 + // TODO 5: 초대한 유저에 대한 userChatRoom 테이블 생성 userChatRoomDao.save(UserChatRoom.of(chatRoomByChatRoomId, userByUserId, LocalDateTime.now())); } diff --git a/src/main/java/space/space_spring/service/S3Uploader.java b/src/main/java/space/space_spring/service/S3Uploader.java index 7e720f6a..dc023658 100644 --- a/src/main/java/space/space_spring/service/S3Uploader.java +++ b/src/main/java/space/space_spring/service/S3Uploader.java @@ -44,21 +44,29 @@ public class S3Uploader { // File에 저장하지 않고 Memory에서 변환 시행 public String upload(MultipartFile file, String dirName) throws IOException{ - String fileName = dirName + "/" + file.getOriginalFilename(); + String originFileName = file.getOriginalFilename(); + String fileExtension = getFileExtension(originFileName); + String uniqueFilename = generateUniqueFileName(dirName,fileExtension); + + //String fileName = dirName + "/" + file.getOriginalFilename(); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentType(file.getContentType()); metadata.setContentLength(file.getSize()); try (InputStream inputStream = file.getInputStream()) { - amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, inputStream, metadata)); - log.info("File uploaded successfully: {}", fileName); - return amazonS3Client.getUrl(bucket, fileName).toString(); + //amazonS3Client.putObject(new PutObjectRequest(bucket, uniqueFilename, inputStream, metadata)); + putS3( uniqueFilename, inputStream, metadata); + log.info("File uploaded successfully: {}", uniqueFilename); + return amazonS3Client.getUrl(bucket, uniqueFilename).toString(); } catch (IOException e) { - log.error("Error uploading file: {}", fileName, e); + log.error("Error uploading file: {}", uniqueFilename, e); throw new CustomException(MULTIPARTFILE_CONVERT_FAIL_IN_MEMORY,"Failed to upload file"); } } + private String generateUniqueFileName(String dirName ,String fileExtension){ + return dirName + "/" +UUID.randomUUID().toString() + fileExtension; + } // public String upload(File uploadFile, String dirName){ // String fileName = dirName+"/"+uploadFile.getName(); @@ -73,7 +81,12 @@ private String putS3(File uploadFile, String fileName){ .withCannedAcl(CannedAccessControlList.PublicRead)); return amazonS3Client.getUrl(bucket, fileName).toString(); } - // 이미지 지우기 + private String putS3(String fileName,InputStream uploadFile, ObjectMetadata metadata) { + amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, uploadFile,metadata) + .withCannedAcl(CannedAccessControlList.PublicRead)); + return amazonS3Client.getUrl(bucket, fileName).toString(); + } + // 이미지 지우기 private void removeNewFile(File targetFile) { if (targetFile.delete()) { log.info("File delete success"); @@ -161,4 +174,15 @@ private String getFileExtension(String[] base64Components) { } }; } + + private String getFileExtension(String fileName){ + if(fileName==null){ + return ""; + } + int lastIndexOf = fileName.lastIndexOf("."); + if(lastIndexOf==-1){ + return ""; + } + return fileName.substring(lastIndexOf); + } } diff --git a/src/main/java/space/space_spring/service/VoiceRoomService.java b/src/main/java/space/space_spring/service/VoiceRoomService.java index a94bb638..7c9b709f 100644 --- a/src/main/java/space/space_spring/service/VoiceRoomService.java +++ b/src/main/java/space/space_spring/service/VoiceRoomService.java @@ -237,6 +237,11 @@ public boolean updateVoiceRoom(List updateRoomList){ public void deleteVoiceRoom(long voiceRoomId){ //Todo Base Entity에 일괄적으로 soft Delete를 적용하는 방법을 다같이 정하는 것이 좋아보임 + VoiceRoom voiceRoom = voiceRoomRepository.findById(voiceRoomId); + voiceRoom.updateInactive(); + voiceRoomRepository.save(voiceRoom); + + } private String findProfileImageByUserId(Long userSpaceId){