diff --git a/src/main/java/space/space_spring/argument_resolver/jwtLogin/JwtLoginAuth.java b/src/main/java/space/space_spring/argumentResolver/jwtLogin/JwtLoginAuth.java similarity index 82% rename from src/main/java/space/space_spring/argument_resolver/jwtLogin/JwtLoginAuth.java rename to src/main/java/space/space_spring/argumentResolver/jwtLogin/JwtLoginAuth.java index cd8d2e4b..d0db6f99 100644 --- a/src/main/java/space/space_spring/argument_resolver/jwtLogin/JwtLoginAuth.java +++ b/src/main/java/space/space_spring/argumentResolver/jwtLogin/JwtLoginAuth.java @@ -1,4 +1,4 @@ -package space.space_spring.argument_resolver.jwtLogin; +package space.space_spring.argumentResolver.jwtLogin; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/space/space_spring/argument_resolver/jwtLogin/JwtLoginAuthHandlerArgumentResolver.java b/src/main/java/space/space_spring/argumentResolver/jwtLogin/JwtLoginAuthHandlerArgumentResolver.java similarity index 95% rename from src/main/java/space/space_spring/argument_resolver/jwtLogin/JwtLoginAuthHandlerArgumentResolver.java rename to src/main/java/space/space_spring/argumentResolver/jwtLogin/JwtLoginAuthHandlerArgumentResolver.java index aff96769..d638dea0 100644 --- a/src/main/java/space/space_spring/argument_resolver/jwtLogin/JwtLoginAuthHandlerArgumentResolver.java +++ b/src/main/java/space/space_spring/argumentResolver/jwtLogin/JwtLoginAuthHandlerArgumentResolver.java @@ -1,4 +1,4 @@ -package space.space_spring.argument_resolver.jwtLogin; +package space.space_spring.argumentResolver.jwtLogin; import jakarta.servlet.http.HttpServletRequest; import org.springframework.core.MethodParameter; diff --git a/src/main/java/space/space_spring/argumentResolver/userSpace/CheckUserSpace.java b/src/main/java/space/space_spring/argumentResolver/userSpace/CheckUserSpace.java new file mode 100644 index 00000000..dbaf59be --- /dev/null +++ b/src/main/java/space/space_spring/argumentResolver/userSpace/CheckUserSpace.java @@ -0,0 +1,12 @@ +package space.space_spring.argumentResolver.userSpace; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckUserSpace { + boolean required() default true; +} diff --git a/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceAuth.java b/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceAuth.java new file mode 100644 index 00000000..615c3ac4 --- /dev/null +++ b/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceAuth.java @@ -0,0 +1,11 @@ +package space.space_spring.argumentResolver.userSpace; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface UserSpaceAuth { +} diff --git a/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceAuthHandlerArgumentResolver.java b/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceAuthHandlerArgumentResolver.java new file mode 100644 index 00000000..2f81ca00 --- /dev/null +++ b/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceAuthHandlerArgumentResolver.java @@ -0,0 +1,32 @@ +package space.space_spring.argumentResolver.userSpace; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuth; +import space.space_spring.dao.UserSpaceDao; + +@Component +@RequiredArgsConstructor +public class UserSpaceAuthHandlerArgumentResolver implements HandlerMethodArgumentResolver { + + private final UserSpaceDao userSpaceDao; + @Override + public boolean supportsParameter(MethodParameter parameter) { + // 일단 parameter의 return value type 을 검사하지는 X + return parameter.hasParameterAnnotation(UserSpaceAuth.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); + return + userSpaceDao.findUserSpaceAuthById((Long)request.getAttribute("userSpaceId")); + + } +} diff --git a/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceId.java b/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceId.java new file mode 100644 index 00000000..d36a84df --- /dev/null +++ b/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceId.java @@ -0,0 +1,11 @@ +package space.space_spring.argumentResolver.userSpace; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface UserSpaceId { +} diff --git a/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceIdHandlerArgumentResolver.java b/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceIdHandlerArgumentResolver.java new file mode 100644 index 00000000..79ab77b2 --- /dev/null +++ b/src/main/java/space/space_spring/argumentResolver/userSpace/UserSpaceIdHandlerArgumentResolver.java @@ -0,0 +1,26 @@ +package space.space_spring.argumentResolver.userSpace; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuth; + +@Component +public class UserSpaceIdHandlerArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter parameter) { + // 일단 parameter의 return value type 을 검사하지는 X + return parameter.hasParameterAnnotation(UserSpaceId.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); + return request.getAttribute("userSpaceId"); + } +} diff --git a/src/main/java/space/space_spring/config/InterceptorURL.java b/src/main/java/space/space_spring/config/InterceptorURL.java index 23047cbe..81ff2fef 100644 --- a/src/main/java/space/space_spring/config/InterceptorURL.java +++ b/src/main/java/space/space_spring/config/InterceptorURL.java @@ -7,7 +7,8 @@ public enum InterceptorURL { SPACE("/space/**"), TEST("/test/**"), SPACE_LIST_FOR_USER("/user/space-choice"), - VOICE_ROOM("/voiceRoom/**"); + VOICE_ROOM("/voiceRoom/**"), + USER_PROFILE_LIST("/user/profile"); private final String urlPattern; diff --git a/src/main/java/space/space_spring/config/UserSpaceValidationInterceptorURL.java b/src/main/java/space/space_spring/config/UserSpaceValidationInterceptorURL.java new file mode 100644 index 00000000..18156f8c --- /dev/null +++ b/src/main/java/space/space_spring/config/UserSpaceValidationInterceptorURL.java @@ -0,0 +1,16 @@ +package space.space_spring.config; + +import lombok.Getter; + +@Getter +public enum UserSpaceValidationInterceptorURL { + //SPACE("/space/**"), + TEST("/space/{spaceId}/test/**"), + ; + + private final String urlPattern; + + UserSpaceValidationInterceptorURL(String urlPattern) { + this.urlPattern = urlPattern; + } +} diff --git a/src/main/java/space/space_spring/config/WebConfig.java b/src/main/java/space/space_spring/config/WebConfig.java index 626cd0c5..a9c2df06 100644 --- a/src/main/java/space/space_spring/config/WebConfig.java +++ b/src/main/java/space/space_spring/config/WebConfig.java @@ -7,7 +7,11 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import space.space_spring.argument_resolver.jwtLogin.JwtLoginAuthHandlerArgumentResolver; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuthHandlerArgumentResolver; +import space.space_spring.argumentResolver.userSpace.UserSpaceAuth; +import space.space_spring.argumentResolver.userSpace.UserSpaceAuthHandlerArgumentResolver; +import space.space_spring.argumentResolver.userSpace.UserSpaceIdHandlerArgumentResolver; +import space.space_spring.interceptor.UserSpaceValidationInterceptor; import space.space_spring.interceptor.jwtLogin.JwtLoginAuthInterceptor; import java.util.List; @@ -19,8 +23,10 @@ public class WebConfig implements WebMvcConfigurer { private final JwtLoginAuthInterceptor jwtLoginAuthInterceptor; private final JwtLoginAuthHandlerArgumentResolver jwtLoginAuthHandlerArgumentResolver; + private final UserSpaceIdHandlerArgumentResolver userSpaceIdHandlerArgumentResolver; + private final UserSpaceAuthHandlerArgumentResolver userSpaceAuthHandlerArgumentResolver; + private final UserSpaceValidationInterceptor userSpaceValidationInterceptor; - private static final String DEVELOP_FRONT_ADDRESS = "http://localhost:5173"; @Override public void addInterceptors(InterceptorRegistry registry) { @@ -31,17 +37,30 @@ public void addInterceptors(InterceptorRegistry registry) { for (InterceptorURL interceptorURL : InterceptorURL.values()) { registration.addPathPatterns(interceptorURL.getUrlPattern()); } + + InterceptorRegistration userSpaceRegistration = + registry.addInterceptor(userSpaceValidationInterceptor) + .order(2); + for(UserSpaceValidationInterceptorURL url:UserSpaceValidationInterceptorURL.values()) { + userSpaceRegistration.addPathPatterns(url.getUrlPattern()); + } + + } @Override public void addArgumentResolvers(List argumentResolvers) { argumentResolvers.add(jwtLoginAuthHandlerArgumentResolver); + argumentResolvers.add(userSpaceIdHandlerArgumentResolver); + argumentResolvers.add(userSpaceAuthHandlerArgumentResolver); } @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") - .allowedOriginPatterns(String.valueOf(List.of(DEVELOP_FRONT_ADDRESS, "http://localhost:3000"))) + .allowedOriginPatterns("http://localhost:3000/", "http://localhost:5173/", "https://localhost:5173/", + "http://localhost:5173/KUIT-Space-Front/", "https://localhost:5173/KUIT-Space-Front/", + "https://kuit-space.github.io/KUIT-Space-front/") .allowedMethods("GET", "POST", "PUT", "DELETE") .exposedHeaders("location") .allowedHeaders("*") diff --git a/src/main/java/space/space_spring/controller/ChatRoomController.java b/src/main/java/space/space_spring/controller/ChatRoomController.java index d9b9750c..976f6fb5 100644 --- a/src/main/java/space/space_spring/controller/ChatRoomController.java +++ b/src/main/java/space/space_spring/controller/ChatRoomController.java @@ -4,11 +4,14 @@ import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import space.space_spring.argument_resolver.jwtLogin.JwtLoginAuth; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuth; import space.space_spring.dto.chat.request.CreateChatRoomRequest; +import space.space_spring.dto.chat.request.JoinChatRoomRequest; +import space.space_spring.dto.chat.response.ChatSuccessResponse; import space.space_spring.dto.chat.response.CreateChatRoomResponse; +import space.space_spring.dto.chat.response.ReadChatRoomMemberResponse; import space.space_spring.dto.chat.response.ReadChatRoomResponse; -import space.space_spring.exception.ChatException; +import space.space_spring.exception.CustomException; import space.space_spring.response.BaseResponse; import space.space_spring.service.ChatRoomService; import space.space_spring.service.S3Uploader; @@ -16,8 +19,7 @@ import java.io.IOException; -import static space.space_spring.response.status.BaseExceptionResponseStatus.INVALID_CHATROOM_CREATE; -import static space.space_spring.response.status.BaseExceptionResponseStatus.UNAUTHORIZED_USER; +import static space.space_spring.response.status.BaseExceptionResponseStatus.*; import static space.space_spring.util.bindingResult.BindingResultUtils.getErrorMessage; @RestController @@ -28,11 +30,17 @@ public class ChatRoomController { private final S3Uploader s3Uploader; private final UserSpaceUtils userSpaceUtils; + /** + * 모든 채팅방 정보 조회 + */ @GetMapping("/chatroom") public BaseResponse readChatRooms(@JwtLoginAuth Long userId, @PathVariable Long spaceId) { return new BaseResponse<>(chatRoomService.readChatRooms(userId, spaceId)); } + /** + * 채팅방 생성 + */ @PostMapping("/chatroom") public BaseResponse createChatRoom( @JwtLoginAuth Long userId, @@ -41,11 +49,11 @@ public BaseResponse createChatRoom( BindingResult bindingResult) throws IOException { if (!userSpaceUtils.isUserManager(userId, spaceId)) { - throw new ChatException(UNAUTHORIZED_USER); + throw new CustomException(UNAUTHORIZED_USER); } if (bindingResult.hasErrors()) { - throw new ChatException(INVALID_CHATROOM_CREATE, getErrorMessage(bindingResult)); + throw new CustomException(INVALID_CHATROOM_CREATE, getErrorMessage(bindingResult)); } String chatRoomDirName = "chatRoomImg"; @@ -53,4 +61,83 @@ public BaseResponse createChatRoom( return new BaseResponse<>(chatRoomService.createChatRoom(userId, spaceId, createChatRoomRequest, chatRoomImgUrl)); } + + /** + * 특정 채팅방의 모든 유저 정보 조회 + */ + @GetMapping("/{chatRoomId}/member") + public BaseResponse readChatRoomMembers(@JwtLoginAuth Long userId, @PathVariable Long spaceId, @PathVariable Long chatRoomId) { + + if (!userSpaceUtils.isUserManager(userId, spaceId)) { + throw new CustomException(UNAUTHORIZED_USER); + } + + return new BaseResponse<>(chatRoomService.readChatRoomMembers(spaceId, chatRoomId)); + } + + /** + * 특정 채팅방에 유저 초대 + */ + @PostMapping("/{chatRoomId}/member") + public BaseResponse joinChatRoom( + @JwtLoginAuth Long userId, + @PathVariable Long spaceId, + @PathVariable Long chatRoomId, + @RequestBody JoinChatRoomRequest joinChatRoomRequest, + BindingResult bindingResult) { + + if (!userSpaceUtils.isUserManager(userId, spaceId)) { + throw new CustomException(UNAUTHORIZED_USER); + } + + if(bindingResult.hasErrors()){ + throw new CustomException(INVALID_CHATROOM_JOIN,getErrorMessage(bindingResult)); + } + + return new BaseResponse<>(chatRoomService.joinChatRoom(chatRoomId, joinChatRoomRequest)); + } + + /** + * 특정 채팅방의 이름 수정 + */ + @PostMapping("/{chatRoomId}/setting") + public BaseResponse modifyChatRoomName( + @JwtLoginAuth Long userId, + @PathVariable Long spaceId, + @PathVariable Long chatRoomId, + @RequestParam String name) { + + if (!userSpaceUtils.isUserManager(userId, spaceId)) { + throw new CustomException(UNAUTHORIZED_USER); + } + + return new BaseResponse<>(chatRoomService.modifyChatRoomName(chatRoomId, name)); + } + + /** + * 특정 채팅방에서 나가기 + */ + @PostMapping("/{chatRoomId}/exit") + public BaseResponse exitChatRoom( + @JwtLoginAuth Long userId, + @PathVariable Long spaceId, + @PathVariable Long chatRoomId) { + return new BaseResponse<>(chatRoomService.exitChatRoom(userId, chatRoomId)); + } + + /** + * 특정 채팅방 삭제 + */ + @PostMapping("/{chatRoomId}/delete") + public BaseResponse deleteChatRoom( + @JwtLoginAuth Long userId, + @PathVariable Long spaceId, + @PathVariable Long chatRoomId) { + + if (!userSpaceUtils.isUserManager(userId, spaceId)) { + throw new CustomException(UNAUTHORIZED_USER); + } + + return new BaseResponse<>(chatRoomService.deleteChatRoom(chatRoomId)); + } } diff --git a/src/main/java/space/space_spring/controller/PayController.java b/src/main/java/space/space_spring/controller/PayController.java index efebbfb0..76c337e1 100644 --- a/src/main/java/space/space_spring/controller/PayController.java +++ b/src/main/java/space/space_spring/controller/PayController.java @@ -3,10 +3,9 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; -import space.space_spring.argument_resolver.jwtLogin.JwtLoginAuth; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuth; import space.space_spring.dto.pay.dto.PayReceiveInfoDto; import space.space_spring.dto.pay.dto.PayRequestInfoDto; -import space.space_spring.dto.pay.dto.PayTargetInfoDto; import space.space_spring.dto.pay.dto.TotalPayInfoDto; import space.space_spring.dto.pay.request.PostPayCompleteRequest; import space.space_spring.dto.pay.request.PostPayCreateRequest; diff --git a/src/main/java/space/space_spring/controller/PostController.java b/src/main/java/space/space_spring/controller/PostController.java index ec56825e..5622c16a 100644 --- a/src/main/java/space/space_spring/controller/PostController.java +++ b/src/main/java/space/space_spring/controller/PostController.java @@ -5,22 +5,23 @@ import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; + +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuth; import org.springframework.web.multipart.MultipartFile; -import space.space_spring.argument_resolver.jwtLogin.JwtLoginAuth; + import space.space_spring.dto.post.request.CreatePostRequest; +import space.space_spring.dto.post.response.ReadPostDetailResponse; import space.space_spring.dto.post.response.ReadPostsResponse; + import space.space_spring.entity.UserSpace; -import space.space_spring.exception.PostException; -import space.space_spring.exception.SpaceException; +import space.space_spring.exception.CustomException; import space.space_spring.response.BaseResponse; import space.space_spring.service.PostService; import space.space_spring.util.userSpace.UserSpaceUtils; - -import java.io.IOException; import java.util.List; import java.util.Optional; -import static space.space_spring.util.bindingResult.BindingResultUtils.getErrorMessage; +import static space.space_spring.response.status.BaseExceptionResponseStatus.INVALID_POST_CREATE; @RestController @RequiredArgsConstructor @@ -30,6 +31,7 @@ public class PostController { private final PostService postService; private final UserSpaceUtils userSpaceUtils; + // 게시글 조회 @GetMapping("/board") public BaseResponse> getBoard( @JwtLoginAuth Long userId, @@ -39,20 +41,22 @@ public BaseResponse> getBoard( // TODO 1: 유저가 스페이스에 속하는지 검증 Optional userInSpace = userSpaceUtils.isUserInSpace(userId, spaceId); log.info("UserName = {}, UserSpaceAuth = {}", userInSpace.get().getUserName(), userInSpace.get().getUserSpaceAuth()); + // TODO 2: 게시글 필터링 적용하여 리스트 get - List board = postService.getAllPosts(spaceId, filter); + List board = postService.getAllPosts(spaceId, filter, userId); return new BaseResponse<>(board); } + // 게시글 작성 @PostMapping("/board/post") public BaseResponse createPost( @JwtLoginAuth Long userId, @PathVariable Long spaceId, @ModelAttribute @Validated CreatePostRequest createPostRequest, - BindingResult bindingResult) throws IOException{ + BindingResult bindingResult) { // TODO 1: 예외처리 if (bindingResult.hasErrors()) { -// throw new PostException(, getErrorMessage(bindingResult)); + throw new CustomException(INVALID_POST_CREATE); } // TODO 2: 유저가 스페이스에 속하는 지 검증 Optional userInSpace = userSpaceUtils.isUserInSpace(userId, spaceId); @@ -64,5 +68,20 @@ public BaseResponse createPost( return new BaseResponse<>("새로운 글이 작성되었습니다."); } + // 게시글 상세 조회 + @GetMapping("/board/post/{postId}") + public BaseResponse getPost( + @JwtLoginAuth Long userId, + @PathVariable Long spaceId, + @PathVariable Long postId) { + // TODO 1: 유저가 스페이스에 속하는지 검증 + Optional userInSpace = userSpaceUtils.isUserInSpace(userId, spaceId); + log.info("UserName = {}, UserSpaceAuth = {}", userInSpace.get().getUserName(), userInSpace.get().getUserSpaceAuth()); + + // TODO 2: 게시글 상세 정보 가져오기 + ReadPostDetailResponse readPostDetailResponse = postService.getPostDetail(userId, spaceId, postId); + + return new BaseResponse<>(readPostDetailResponse); + } } diff --git a/src/main/java/space/space_spring/controller/SpaceController.java b/src/main/java/space/space_spring/controller/SpaceController.java index de2994f6..640d3228 100644 --- a/src/main/java/space/space_spring/controller/SpaceController.java +++ b/src/main/java/space/space_spring/controller/SpaceController.java @@ -6,7 +6,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import space.space_spring.argument_resolver.jwtLogin.JwtLoginAuth; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuth; import space.space_spring.dto.space.GetSpaceJoinDto; import space.space_spring.dto.space.PostSpaceJoinDto; import space.space_spring.dto.space.response.GetUserInfoBySpaceResponse; diff --git a/src/main/java/space/space_spring/controller/TestController.java b/src/main/java/space/space_spring/controller/TestController.java index 4f62a6c4..a2e2f6cd 100644 --- a/src/main/java/space/space_spring/controller/TestController.java +++ b/src/main/java/space/space_spring/controller/TestController.java @@ -2,9 +2,13 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import space.space_spring.argument_resolver.jwtLogin.JwtLoginAuth; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuth; +import space.space_spring.argumentResolver.userSpace.CheckUserSpace; +import space.space_spring.argumentResolver.userSpace.UserSpaceAuth; +import space.space_spring.argumentResolver.userSpace.UserSpaceId; import space.space_spring.response.BaseResponse; @RestController @@ -22,4 +26,32 @@ public BaseResponse jwtLoginTest(@JwtLoginAuth Long userId) { return new BaseResponse<>("jwt login test 성공"); } + @GetMapping("/space/{spaceId}/test") + public BaseResponse LoginTest( + @JwtLoginAuth Long userId, + @UserSpaceId Long userSpaceId, + @UserSpaceAuth String userSpaceAuth) { + log.info("userId = {}", userId); + return new BaseResponse<>("{ userId : "+ userId.toString() + +"" + +"userSpaceId : "+userSpaceId + +"" + +"userSpaceAuth : "+userSpaceAuth + + + "}" + ); + } + + @GetMapping("/space/{spaceId}/test/pass") + @CheckUserSpace(required = false) + public BaseResponse LoginPassAnnotaionTest( + @JwtLoginAuth Long userId, + @PathVariable Long spaceId + ){ + return new BaseResponse<>("{ userId : "+ userId.toString() + +""); + } + + + } diff --git a/src/main/java/space/space_spring/controller/UserController.java b/src/main/java/space/space_spring/controller/UserController.java index 0a053a27..9a69f6df 100644 --- a/src/main/java/space/space_spring/controller/UserController.java +++ b/src/main/java/space/space_spring/controller/UserController.java @@ -6,7 +6,8 @@ import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import space.space_spring.argument_resolver.jwtLogin.JwtLoginAuth; +import space.space_spring.dto.user.GetUserProfileListDto; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuth; import space.space_spring.dto.user.request.PostUserLoginRequest; import space.space_spring.dto.user.request.PostUserSignupRequest; import space.space_spring.dto.user.response.GetSpaceInfoForUserResponse; @@ -68,4 +69,14 @@ public BaseResponse showUserSpaceList(@JwtLoginAuth return new BaseResponse<>(userService.getSpaceListForUser(userId, size, lastUserSpaceId)); } + /** + * 스페이스 전체 설정 -> 스페이스 프로필 관리 view + */ + @GetMapping("/profile") + public BaseResponse showUserProfileList(@JwtLoginAuth Long userId) { + + log.info("userId = {}", userId); + + return new BaseResponse<>(userService.getUserProfileList(userId)); + } } diff --git a/src/main/java/space/space_spring/controller/VoiceRoomController.java b/src/main/java/space/space_spring/controller/VoiceRoomController.java index b874453c..281930bd 100644 --- a/src/main/java/space/space_spring/controller/VoiceRoomController.java +++ b/src/main/java/space/space_spring/controller/VoiceRoomController.java @@ -6,7 +6,7 @@ import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import space.space_spring.argument_resolver.jwtLogin.JwtLoginAuth; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuth; import space.space_spring.dao.UserSpaceDao; import space.space_spring.dao.VoiceRoomRepository; import space.space_spring.dto.VoiceRoom.*; diff --git a/src/main/java/space/space_spring/dao/PostDao.java b/src/main/java/space/space_spring/dao/PostDao.java index 8c1e6bc8..82219020 100644 --- a/src/main/java/space/space_spring/dao/PostDao.java +++ b/src/main/java/space/space_spring/dao/PostDao.java @@ -1,6 +1,8 @@ package space.space_spring.dao; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import space.space_spring.entity.Post; import space.space_spring.entity.Space; @@ -14,4 +16,8 @@ public interface PostDao extends JpaRepository { List findBySpaceAndType(Space space, String type); + @Query("SELECT CASE WHEN COUNT(l) > 0 THEN true ELSE false END " + + "FROM PostLike l WHERE l.post.postId = :postId AND l.user.userId = :userId") + boolean isUserLikedPost(@Param("postId") Long postId, @Param("userId") Long userId); + } diff --git a/src/main/java/space/space_spring/dao/UserSpaceDao.java b/src/main/java/space/space_spring/dao/UserSpaceDao.java index 5ea0b8d6..66826e78 100644 --- a/src/main/java/space/space_spring/dao/UserSpaceDao.java +++ b/src/main/java/space/space_spring/dao/UserSpaceDao.java @@ -4,6 +4,7 @@ import jakarta.persistence.PersistenceContext; import jakarta.persistence.TypedQuery; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import space.space_spring.dto.user.dto.SpaceChoiceInfo; import space.space_spring.dto.user.dto.SpaceChoiceViewDto; import space.space_spring.dto.userSpace.UserInfoInSpace; @@ -116,4 +117,21 @@ public int calculateSpaceMemberNum(Space space) { return query.getSingleResult().intValue(); } + + public List findUserSpaceListByUser(User user) { + String jpql = "SELECT us FROM UserSpace us WHERE us.user = :user AND us.status = 'ACTIVE'"; + TypedQuery query = em.createQuery(jpql, UserSpace.class); + query.setParameter("user", user); + + return query.getResultList(); + } + + @Transactional(readOnly = true) + public String findUserSpaceAuthById(Long userSpaceId) { + String jpql = "SELECT us.userSpaceAuth FROM UserSpace us WHERE us.userSpaceId = :userSpaceId"; + return em.createQuery(jpql, String.class) + .setParameter("userSpaceId", userSpaceId) + .getSingleResult(); + + } } diff --git a/src/main/java/space/space_spring/dao/chat/ChatRoomDao.java b/src/main/java/space/space_spring/dao/chat/ChatRoomDao.java index e66f7798..9c6ab523 100644 --- a/src/main/java/space/space_spring/dao/chat/ChatRoomDao.java +++ b/src/main/java/space/space_spring/dao/chat/ChatRoomDao.java @@ -4,7 +4,11 @@ import org.springframework.stereotype.Repository; import space.space_spring.dao.chat.custom.ChatRoomDaoCustom; import space.space_spring.entity.ChatRoom; +import space.space_spring.entity.Space; + +import java.util.List; @Repository public interface ChatRoomDao extends JpaRepository, ChatRoomDaoCustom { + List findBySpace(Space space); } diff --git a/src/main/java/space/space_spring/dao/chat/UserChatRoomDao.java b/src/main/java/space/space_spring/dao/chat/UserChatRoomDao.java index e14531ea..492bc074 100644 --- a/src/main/java/space/space_spring/dao/chat/UserChatRoomDao.java +++ b/src/main/java/space/space_spring/dao/chat/UserChatRoomDao.java @@ -5,7 +5,11 @@ import space.space_spring.entity.User; import space.space_spring.entity.UserChatRoom; +import java.util.List; + public interface UserChatRoomDao extends JpaRepository { UserChatRoom findByUserAndChatRoom(User userByUserId, ChatRoom chatRoomByChatRoomId); + + List findByChatRoom(ChatRoom chatRoom); } diff --git a/src/main/java/space/space_spring/dto/chat/request/JoinChatRoomRequest.java b/src/main/java/space/space_spring/dto/chat/request/JoinChatRoomRequest.java new file mode 100644 index 00000000..5a36190e --- /dev/null +++ b/src/main/java/space/space_spring/dto/chat/request/JoinChatRoomRequest.java @@ -0,0 +1,13 @@ +package space.space_spring.dto.chat.request; + +import jakarta.annotation.Nullable; +import lombok.Getter; + +import java.util.List; + +@Getter +public class JoinChatRoomRequest { + + @Nullable + private List memberList; +} diff --git a/src/main/java/space/space_spring/dto/chat/response/ChatSuccessResponse.java b/src/main/java/space/space_spring/dto/chat/response/ChatSuccessResponse.java new file mode 100644 index 00000000..abe6e481 --- /dev/null +++ b/src/main/java/space/space_spring/dto/chat/response/ChatSuccessResponse.java @@ -0,0 +1,16 @@ +package space.space_spring.dto.chat.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ChatSuccessResponse { + private boolean isSuccess; + + public static ChatSuccessResponse of(boolean isSuccess) { + return ChatSuccessResponse.builder() + .isSuccess(isSuccess) + .build(); + } +} diff --git a/src/main/java/space/space_spring/dto/chat/response/ReadChatRoomMemberResponse.java b/src/main/java/space/space_spring/dto/chat/response/ReadChatRoomMemberResponse.java new file mode 100644 index 00000000..926af0dd --- /dev/null +++ b/src/main/java/space/space_spring/dto/chat/response/ReadChatRoomMemberResponse.java @@ -0,0 +1,22 @@ +package space.space_spring.dto.chat.response; + +import lombok.Builder; +import lombok.Getter; +import space.space_spring.dto.userSpace.UserInfoInSpace; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Builder +public class ReadChatRoomMemberResponse { + + private List userList = new ArrayList<>(); + + public static ReadChatRoomMemberResponse of(List userList) { + return ReadChatRoomMemberResponse.builder() + .userList(userList) + .build(); + } + +} diff --git a/src/main/java/space/space_spring/dto/post/response/ReadPostDetailResponse.java b/src/main/java/space/space_spring/dto/post/response/ReadPostDetailResponse.java new file mode 100644 index 00000000..1526fad4 --- /dev/null +++ b/src/main/java/space/space_spring/dto/post/response/ReadPostDetailResponse.java @@ -0,0 +1,63 @@ +package space.space_spring.dto.post.response; + +import lombok.*; +import space.space_spring.entity.Post; +import space.space_spring.entity.PostComment; +import space.space_spring.entity.PostImage; +import space.space_spring.entity.UserSpace; +import space.space_spring.util.post.ConvertCreatedDate; + +import java.util.List; + +@Builder +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ReadPostDetailResponse { + // 스페이스 관련 + private Long spaceId; + + // 유저 관련 + private Long userId; + private String userProfileImg; + private String userName; + + // 게시글 관련 + private Long postId; + private String title; + private String content; + private List postImage; + private String time; + private String type; + + // 댓글 및 좋아요 + private int commentCount; + private List postComments; + private int likeCount; + private boolean isLike; + + public static ReadPostDetailResponse of(Post post, UserSpace userSpace, boolean isLike) { + List postImageUrls = post.getPostImages().stream() + .map(PostImage::getPostImgUrl) + .toList(); + + return ReadPostDetailResponse.builder() + .postId(post.getPostId()) + .spaceId(post.getSpace().getSpaceId()) + .userId(post.getUser().getUserId()) + .userProfileImg(userSpace != null ? userSpace.getUserProfileImg() : null) + .userName(userSpace != null ? userSpace.getUserName() : null) + .title(post.getTitle()) + .content(post.getContent()) + .time(ConvertCreatedDate.setCreatedDate(post.getCreatedAt())) + .type(post.getType()) + .commentCount(post.getPostComments().size()) + .postComments(post.getPostComments()) + .likeCount(post.getLike()) + .isLike(isLike) + .postImage(postImageUrls) + .build(); + } + +} diff --git a/src/main/java/space/space_spring/dto/post/response/ReadPostsResponse.java b/src/main/java/space/space_spring/dto/post/response/ReadPostsResponse.java index 4b431813..56b48b92 100644 --- a/src/main/java/space/space_spring/dto/post/response/ReadPostsResponse.java +++ b/src/main/java/space/space_spring/dto/post/response/ReadPostsResponse.java @@ -35,8 +35,9 @@ public class ReadPostsResponse { // 댓글 및 좋아요 private int commentCount; private int likeCount; + private boolean isLike; - public static ReadPostsResponse of(Post post, int postCount, UserSpace userSpace) { + public static ReadPostsResponse of(Post post, int postCount, UserSpace userSpace, boolean isLike) { List postImageUrls = post.getPostImages().stream() .map(PostImage::getPostImgUrl) .toList(); @@ -54,6 +55,7 @@ public static ReadPostsResponse of(Post post, int postCount, UserSpace userSpace .postCount(postCount) .commentCount(post.getPostComments().size()) .likeCount(post.getLike()) + .isLike(isLike) .postImage(postImageUrls) .build(); } diff --git a/src/main/java/space/space_spring/dto/user/GetUserProfileListDto.java b/src/main/java/space/space_spring/dto/user/GetUserProfileListDto.java new file mode 100644 index 00000000..39899402 --- /dev/null +++ b/src/main/java/space/space_spring/dto/user/GetUserProfileListDto.java @@ -0,0 +1,34 @@ +package space.space_spring.dto.user; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.checkerframework.checker.units.qual.A; + +import java.util.List; + +@Getter +@AllArgsConstructor +public class GetUserProfileListDto { + + @Getter + @AllArgsConstructor + public static class Response { + + private List userProfileList; + } + + @Getter + @AllArgsConstructor + public static class UserProfile { + + private Long spaceId; + + private String spaceName; + + private String userName; + + private String userProfileImg; + + private String userAuth; + } +} diff --git a/src/main/java/space/space_spring/entity/BaseEntity.java b/src/main/java/space/space_spring/entity/BaseEntity.java index c1130aec..300fed77 100644 --- a/src/main/java/space/space_spring/entity/BaseEntity.java +++ b/src/main/java/space/space_spring/entity/BaseEntity.java @@ -35,4 +35,6 @@ protected void onUpdate() { protected void initializeBaseEntityFields() { onCreate(); } + + public void updateInactive() { this.status = "INACTIVE"; } } diff --git a/src/main/java/space/space_spring/entity/ChatRoom.java b/src/main/java/space/space_spring/entity/ChatRoom.java index f19a7b40..0f3104da 100644 --- a/src/main/java/space/space_spring/entity/ChatRoom.java +++ b/src/main/java/space/space_spring/entity/ChatRoom.java @@ -48,6 +48,10 @@ public static ChatRoom of(Space space, CreateChatRoomRequest createChatRoomReque .build(); } + public void updateName(String name) { + this.name = name; + } + // // 양방향 매핑 // @OneToMany(mappedBy = "chatRoom", cascade = CascadeType.ALL) // private List userChatRooms; diff --git a/src/main/java/space/space_spring/entity/CommentLike.java b/src/main/java/space/space_spring/entity/CommentLike.java new file mode 100644 index 00000000..36d87a77 --- /dev/null +++ b/src/main/java/space/space_spring/entity/CommentLike.java @@ -0,0 +1,24 @@ +package space.space_spring.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Table(name = "Comment_Like") +@Getter +@NoArgsConstructor +public class CommentLike extends BaseEntity{ + @Id + @GeneratedValue + @Column(name = "comment_like_id") + private Long commentLikeId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "space_post_id") + private Post post; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; +} diff --git a/src/main/java/space/space_spring/entity/PostLike.java b/src/main/java/space/space_spring/entity/PostLike.java new file mode 100644 index 00000000..6e8e26ab --- /dev/null +++ b/src/main/java/space/space_spring/entity/PostLike.java @@ -0,0 +1,25 @@ +package space.space_spring.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "Post_Like") +@Getter +@NoArgsConstructor +public class PostLike extends BaseEntity{ + @Id + @GeneratedValue + @Column(name = "post_like_id") + private Long postLikeId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "space_post_id") + private Post post; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; +} diff --git a/src/main/java/space/space_spring/exception/ChatException.java b/src/main/java/space/space_spring/exception/ChatException.java deleted file mode 100644 index 5eb3974e..00000000 --- a/src/main/java/space/space_spring/exception/ChatException.java +++ /dev/null @@ -1,20 +0,0 @@ -package space.space_spring.exception; - -import lombok.Getter; -import space.space_spring.response.status.ResponseStatus; - -@Getter -public class ChatException extends RuntimeException{ - - private final ResponseStatus exceptionStatus; - - public ChatException(ResponseStatus exceptionStatus) { - super(exceptionStatus.getMessage()); - this.exceptionStatus = exceptionStatus; - } - - public ChatException(ResponseStatus exceptionStatus, String message) { - super(message); - this.exceptionStatus = exceptionStatus; - } -} diff --git a/src/main/java/space/space_spring/interceptor/UserSpaceValidationInterceptor.java b/src/main/java/space/space_spring/interceptor/UserSpaceValidationInterceptor.java new file mode 100644 index 00000000..febda0d0 --- /dev/null +++ b/src/main/java/space/space_spring/interceptor/UserSpaceValidationInterceptor.java @@ -0,0 +1,71 @@ +package space.space_spring.interceptor; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.HandlerMapping; +import space.space_spring.argumentResolver.userSpace.CheckUserSpace; +import space.space_spring.dao.SpaceDao; +import space.space_spring.dao.UserDao; +import space.space_spring.dao.UserSpaceDao; +import space.space_spring.entity.Space; +import space.space_spring.entity.User; +import space.space_spring.entity.UserSpace; +import space.space_spring.exception.CustomException; +import space.space_spring.exception.UserSpaceException; + +import java.util.Map; +import java.util.Optional; + +import static space.space_spring.response.status.BaseExceptionResponseStatus.*; + +@Component +@RequiredArgsConstructor +public class UserSpaceValidationInterceptor implements HandlerInterceptor { + + private final UserSpaceDao userSpaceDao; + private final UserDao userDao; + private final SpaceDao spaceDao; + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception{ + + // @CheckUserSpace(require=false)인 경우 검증하지 않음 + HandlerMethod handlerMethod = (HandlerMethod) handler; + CheckUserSpace methodAnnotation= handlerMethod.getMethodAnnotation(CheckUserSpace.class); + if(methodAnnotation!=null && !methodAnnotation.required()){ + System.out.print("[DeBug]Interceptor pass By Annotation"); + return true; + } + Long userId = (Long) request.getAttribute("userId"); + + // URL에서 spaceId 추출 + Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + Long spaceId = Long.parseLong((String) pathVariables.get("spaceId")); + + request.setAttribute("userSpaceId",getUserSpace(spaceId,userId)); + System.out.print("userSpaceID:"+getUserSpace(spaceId,userId)); + return true; + + } + + private Long getUserSpace(long spaceId,long userId){ + // userSpaceDao에서 검증 + User userByUserId = userDao.findUserByUserId(userId); + if(userByUserId==null){ + throw new CustomException(CANNOT_FIND_USER_ID); + } + Space spaceBySpaceId = spaceDao.findSpaceBySpaceId(spaceId); + if(spaceBySpaceId==null){ + throw new CustomException(SPACE_NOT_FOUND); + } + Optional userSpace = userSpaceDao.findUserSpaceByUserAndSpace(userByUserId, spaceBySpaceId); + Optional.ofNullable(userSpace + .orElseThrow(() -> new UserSpaceException(USER_IS_NOT_IN_SPACE))); + return userSpace.get().getUserSpaceId(); + } + + +} 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 be91df8b..a0da73fa 100644 --- a/src/main/java/space/space_spring/response/status/BaseExceptionResponseStatus.java +++ b/src/main/java/space/space_spring/response/status/BaseExceptionResponseStatus.java @@ -36,6 +36,7 @@ public enum BaseExceptionResponseStatus implements ResponseStatus { MALFORMED_TOKEN(4004, HttpStatus.UNAUTHORIZED, "토큰이 올바르게 구성되지 않았습니다."), EXPIRED_TOKEN(4005, HttpStatus.UNAUTHORIZED, "만료된 토큰입니다."), TOKEN_MISMATCH(4006, HttpStatus.UNAUTHORIZED, "로그인 정보가 토큰 정보와 일치하지 않습니다."), + CANNOT_FIND_USER_ID(4007, HttpStatus.UNAUTHORIZED,"토큰의 userId정보를 찾을 수 없습니다."), /** * 5000: User 오류 @@ -53,9 +54,11 @@ public enum BaseExceptionResponseStatus implements ResponseStatus { * 6000: Space 오류 */ INVALID_SPACE_CREATE(6000, HttpStatus.BAD_REQUEST, "스페이스 생성 요청에서 잘못된 값이 존재합니다."), + SPACE_NOT_FOUND(6001, HttpStatus.BAD_REQUEST, "존재하지 않는 스페이스입니다."), INVALID_USER_SPACE_PROFILE(6002, HttpStatus.BAD_REQUEST, "스페이스 별 유저 프로필 정보 수정 요청에서 잘못된 값이 존재합니다."), INVALID_SPACE_JOIN_REQUEST(6003, HttpStatus.BAD_REQUEST, "스페이스 가입 요청에서 잘못된 값이 존재합니다."), + nff(6004, HttpStatus.BAD_REQUEST, "비밀번호가 일치하지 않습니다."), gnf(6005, HttpStatus.BAD_REQUEST, "잘못된 회원 status 값입니다."), fb(6006, HttpStatus.BAD_REQUEST, "존재하지 않는 이메일입니다."), @@ -75,6 +78,8 @@ public enum BaseExceptionResponseStatus implements ResponseStatus { * 8000: Chat 오류 */ INVALID_CHATROOM_CREATE(8000, HttpStatus.BAD_REQUEST, "채팅방 생성 요청에서 잘못된 값이 존재합니다."), + CHATROOM_NOT_EXIST(8001, HttpStatus.BAD_REQUEST, "존재하지 않는 채팅방입니다."), + INVALID_CHATROOM_JOIN(8001, HttpStatus.BAD_REQUEST, "채팅방 멤버 초대 요청에서 잘못된 값이 존재합니다."), /** * 9000 : MultipartFile 오류 @@ -82,7 +87,8 @@ public enum BaseExceptionResponseStatus implements ResponseStatus { IS_NOT_IMAGE_FILE(9000, HttpStatus.BAD_REQUEST, "지원되는 이미지 파일의 형식이 아닙니다."), MULTIPARTFILE_CONVERT_FAILE_IN_MEMORY(9001,HttpStatus.INTERNAL_SERVER_ERROR,"multipartFile memory 변환 과정에서 문제가 생겼습니다."), - /* + + /** * 10000: voice room 오류 */ VOICEROOM_NOT_EXIST(10001, HttpStatus.BAD_REQUEST,"존재하지 않는 보이스룸 id입니다."), @@ -90,9 +96,14 @@ public enum BaseExceptionResponseStatus implements ResponseStatus { VOICEROOM_NAME_ALREADY_EXIST(10003, HttpStatus.BAD_REQUEST,"이미 존재하는 VoiceRoom 이름 입니다."), VOICEROOM_NOT_IN_SPACE(10004, HttpStatus.BAD_REQUEST,"이미 존재하는 VoiceRoom 이름 입니다."), - VOICEROOM_DO_NOT_HAVE_PERMISSION(10005,HttpStatus.FORBIDDEN,"해당 작업은 관리자 권한이 필요합니다." ); - + VOICEROOM_DO_NOT_HAVE_PERMISSION(10005,HttpStatus.FORBIDDEN,"해당 작업은 관리자 권한이 필요합니다." ), + /** + * 11000: Post 오류 + */ + INVALID_POST_CREATE(11000, HttpStatus.BAD_REQUEST, "게시글 생성 요청에서 잘못된 값이 존재합니다."), + POST_NOT_EXIST(11001, HttpStatus.BAD_REQUEST, "존재하지 않는 게시글 id입니다."), + POST_IS_NOT_IN_SPACE(11002, HttpStatus.BAD_REQUEST, "해당 게시글은 이 스페이스에 속하지 않습니다."); private final int code; private final HttpStatus status; diff --git a/src/main/java/space/space_spring/service/ChatRoomService.java b/src/main/java/space/space_spring/service/ChatRoomService.java index 10d7df7c..6b9e2234 100644 --- a/src/main/java/space/space_spring/service/ChatRoomService.java +++ b/src/main/java/space/space_spring/service/ChatRoomService.java @@ -4,34 +4,36 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import space.space_spring.dao.UserDao; +import space.space_spring.dao.UserSpaceDao; import space.space_spring.dao.chat.ChatRoomDao; import space.space_spring.dao.chat.ChattingDao; import space.space_spring.dao.chat.UserChatRoomDao; -import space.space_spring.dto.chat.response.ChatRoomResponse; +import space.space_spring.dto.chat.request.JoinChatRoomRequest; +import space.space_spring.dto.chat.response.*; import space.space_spring.dto.chat.request.CreateChatRoomRequest; -import space.space_spring.dto.chat.response.CreateChatRoomResponse; -import space.space_spring.dto.chat.response.ReadChatRoomResponse; -import space.space_spring.entity.ChatRoom; -import space.space_spring.entity.Space; -import space.space_spring.entity.User; -import space.space_spring.entity.UserChatRoom; +import space.space_spring.dto.userSpace.UserInfoInSpace; +import space.space_spring.entity.*; import space.space_spring.entity.document.ChatMessage; -import space.space_spring.entity.enumStatus.ChatMessageType; +import static space.space_spring.response.status.BaseExceptionResponseStatus.CHATROOM_NOT_EXIST; +import static space.space_spring.response.status.BaseExceptionResponseStatus.USER_IS_NOT_IN_SPACE; + +import space.space_spring.exception.CustomException; import space.space_spring.util.space.SpaceUtils; import space.space_spring.util.user.UserUtils; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; @Service @Slf4j @RequiredArgsConstructor public class ChatRoomService { - private final UserDao userDao; private final UserUtils userUtils; private final SpaceUtils spaceUtils; + private final UserSpaceDao userSpaceDao; private final ChattingDao chattingDao; private final ChatRoomDao chatRoomDao; private final UserChatRoomDao userChatRoomDao; @@ -96,4 +98,95 @@ public CreateChatRoomResponse createChatRoom(Long userId, Long spaceId, CreateCh // TODO 5: chatroom id 반환 return CreateChatRoomResponse.of(chatRoom.getId()); } + + @Transactional + public ReadChatRoomMemberResponse readChatRoomMembers(Long spaceId, Long chatRoomId) { + List userList = new ArrayList<>(); + + // TODO 1: spaceId에 해당하는 space find + Space spaceById = spaceUtils.findSpaceBySpaceId(spaceId); + + // TODO 2: chatRoomId에 해당하는 chatRoom find + ChatRoom chatRoomById = chatRoomDao.findById(chatRoomId) + .orElseThrow(() -> new CustomException(CHATROOM_NOT_EXIST)); + + // TODO 3: 해당 chatRoom의 userChatRoom 리스트 find + List userChatRoomList = userChatRoomDao.findByChatRoom(chatRoomById); + + userChatRoomList.forEach(userChatRoom -> { + User user = userChatRoom.getUser(); + + // TODO 4: 스페이스 프로필 이미지 get 위해 userSpace find + UserSpace userSpace = userSpaceDao.findUserSpaceByUserAndSpace(user, spaceById) + .orElseThrow(() -> new CustomException(USER_IS_NOT_IN_SPACE)); + + userList.add(new UserInfoInSpace(user.getUserId(), user.getUserName(), userSpace.getUserProfileImg(), user.getSignupType())); + }); + + return ReadChatRoomMemberResponse.of(userList); + } + + @Transactional + public ChatSuccessResponse joinChatRoom(Long chatRoomId, JoinChatRoomRequest joinChatRoomRequest) { + List memberIdList = joinChatRoomRequest.getMemberList(); + ChatRoom chatRoomByChatRoomId = chatRoomDao.findById(chatRoomId) + .orElseThrow(() -> new CustomException(CHATROOM_NOT_EXIST)); + + for (Long memberId : Objects.requireNonNull(memberIdList)) { + // TODO 1: 초대한 유저 조회 + User userByUserId = userUtils.findUserByUserId(memberId); + + // TODO 2: 유저가 이미 채팅방에 초대되어있는지 검증 + if (isUserInChatRoom(userByUserId, chatRoomByChatRoomId)) { + return ChatSuccessResponse.of(false); + } + + // TODO 3: 초대한 유저에 대한 userChatRoom 테이블 생성 + userChatRoomDao.save(UserChatRoom.of(chatRoomByChatRoomId, userByUserId, LocalDateTime.now())); + } + + return ChatSuccessResponse.of(true); + } + + public ChatSuccessResponse modifyChatRoomName(Long chatRoomId, String name) { + // TODO 1: 해당 채팅방 find + ChatRoom chatRoomByChatRoomId = chatRoomDao.findById(chatRoomId) + .orElseThrow(() -> new CustomException(CHATROOM_NOT_EXIST)); + + // TODO 2: 채팅방 이름 변경 + chatRoomByChatRoomId.updateName(name); + chatRoomDao.save(chatRoomByChatRoomId); + + return ChatSuccessResponse.of(true); + } + + public ChatSuccessResponse exitChatRoom(Long userId, Long chatRoomId) { + User userByUserId = userUtils.findUserByUserId(userId); + ChatRoom chatRoomByChatRoomId = chatRoomDao.findById(chatRoomId) + .orElseThrow(() -> new CustomException(CHATROOM_NOT_EXIST)); + + // TODO 1: 해당 userChatRoom find + UserChatRoom userChatRoom = userChatRoomDao.findByUserAndChatRoom(userByUserId, chatRoomByChatRoomId); + + // TODO 2: 해당 userChatRoom inactive로 변경 + userChatRoom.updateInactive(); + + return ChatSuccessResponse.of(true); + } + + public ChatSuccessResponse deleteChatRoom(Long chatRoomId) { + // TODO 1: 해당 chatRoom find + ChatRoom chatRoomByChatRoomId = chatRoomDao.findById(chatRoomId) + .orElseThrow(() -> new CustomException(CHATROOM_NOT_EXIST)); + + chatRoomByChatRoomId.updateInactive(); + + return ChatSuccessResponse.of(true); + } + + private boolean isUserInChatRoom(User userByUserId, ChatRoom chatRoomByChatRoomId) { + List chatRoomList = userChatRoomDao.findByChatRoom(chatRoomByChatRoomId); + return chatRoomList.stream().anyMatch(userChatRoom -> userChatRoom.getUser().equals(userByUserId)); + } + } diff --git a/src/main/java/space/space_spring/service/ChattingService.java b/src/main/java/space/space_spring/service/ChattingService.java index 60c52c12..87bc8c0c 100644 --- a/src/main/java/space/space_spring/service/ChattingService.java +++ b/src/main/java/space/space_spring/service/ChattingService.java @@ -9,14 +9,14 @@ import space.space_spring.dto.chat.response.ChatMessageResponse; import space.space_spring.entity.UserSpace; import space.space_spring.entity.document.ChatMessage; +import space.space_spring.exception.CustomException; import space.space_spring.util.userSpace.UserSpaceUtils; -import java.time.LocalDateTime; -import java.time.ZoneId; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; +import static space.space_spring.response.status.BaseExceptionResponseStatus.USER_IS_NOT_IN_SPACE; + @Service @RequiredArgsConstructor @@ -29,15 +29,12 @@ public class ChattingService { public ChatMessageResponse sendChatMessage(Long senderId, ChatMessageRequest chatMessageRequest, Long chatRoomId) { // TODO 1: 메시지 메타데이터 저장 위해 전송자 찾기 - Optional senderInSpace = userSpaceUtils.isUserInSpace(senderId, chatMessageRequest.getSpaceId()); + UserSpace senderInSpace = userSpaceUtils.isUserInSpace(senderId, chatMessageRequest.getSpaceId()) + .orElseThrow(() -> new CustomException(USER_IS_NOT_IN_SPACE)); // TODO 2: validation 후 전송자 이름 및 프로필 사진 get - String senderName = ""; - String senderProfileImg = ""; - if (senderInSpace.isPresent()) { - senderName = senderInSpace.get().getUserName(); - senderProfileImg = senderInSpace.get().getUserProfileImg(); - } + String senderName = senderInSpace.getUserName(); + String senderProfileImg = senderInSpace.getUserProfileImg(); // TODO 3: DB에 메시지 저장 ChatMessage message = chattingDao.insert(ChatMessage.of( diff --git a/src/main/java/space/space_spring/service/PostService.java b/src/main/java/space/space_spring/service/PostService.java index dfa8b328..1ea116a4 100644 --- a/src/main/java/space/space_spring/service/PostService.java +++ b/src/main/java/space/space_spring/service/PostService.java @@ -6,8 +6,10 @@ import org.springframework.stereotype.Service; import space.space_spring.dao.PostDao; import space.space_spring.dto.post.request.CreatePostRequest; +import space.space_spring.dto.post.response.ReadPostDetailResponse; import space.space_spring.dto.post.response.ReadPostsResponse; import space.space_spring.entity.*; +import space.space_spring.exception.CustomException; import space.space_spring.util.space.SpaceUtils; import space.space_spring.util.user.UserUtils; import space.space_spring.util.userSpace.UserSpaceUtils; @@ -18,6 +20,9 @@ import java.util.Optional; import java.util.stream.Collectors; +import static space.space_spring.response.status.BaseExceptionResponseStatus.POST_IS_NOT_IN_SPACE; +import static space.space_spring.response.status.BaseExceptionResponseStatus.POST_NOT_EXIST; + @Service @Slf4j @RequiredArgsConstructor @@ -30,7 +35,7 @@ public class PostService { private final S3Uploader s3Uploader; @Transactional - public List getAllPosts(Long spaceId, String filter) { + public List getAllPosts(Long spaceId, String filter, Long userId) { // TODO 1: spaceId에 해당하는 space find Space spaceBySpaceId = spaceUtils.findSpaceBySpaceId(spaceId); @@ -51,7 +56,8 @@ public List getAllPosts(Long spaceId, String filter) { return posts.stream() .map(post ->{ Optional userSpace = userSpaceUtils.isUserInSpace(post.getUser().getUserId(), spaceId); - return ReadPostsResponse.of(post, postCount, userSpace.orElse(null)); + boolean isLike = postDao.isUserLikedPost(post.getPostId(), userId); + return ReadPostsResponse.of(post, postCount, userSpace.orElse(null), isLike); }) .collect(Collectors.toList()); } @@ -88,4 +94,27 @@ public Long save(Long userId, Long spaceId, CreatePostRequest createPostRequest) return postDao.save(post).getPostId(); } + + @Transactional + public ReadPostDetailResponse getPostDetail(Long userId, Long spaceId, Long postId) { + // TODO 1: spaceId에 해당하는 space find + Space space = spaceUtils.findSpaceBySpaceId(spaceId); + + // TODO 2: postId에 해당하는 post find + Post post = postDao.findById(postId).orElseThrow(() -> new CustomException(POST_NOT_EXIST)); + + // TODO 3: 게시글이 해당 스페이스에 속하는지 검증 + if (!post.getSpace().getSpaceId().equals(spaceId)) { + throw new CustomException(POST_IS_NOT_IN_SPACE); + } + + // TODO 4: userId와 spaceId에 해당하는 UserSpace find + Optional userSpace = userSpaceUtils.isUserInSpace(post.getUser().getUserId(), spaceId); + + // TODO 5: 유저가 해당 게시글에 좋아요를 눌렀는지 여부 확인 + boolean isLike = postDao.isUserLikedPost(post.getPostId(), userId); + + // TODO 6: ReadPostDetailResponse 객체로 변환 + return ReadPostDetailResponse.of(post, userSpace.orElse(null), isLike); + } } diff --git a/src/main/java/space/space_spring/service/UserService.java b/src/main/java/space/space_spring/service/UserService.java index aa869b89..25d8036a 100644 --- a/src/main/java/space/space_spring/service/UserService.java +++ b/src/main/java/space/space_spring/service/UserService.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import space.space_spring.dao.UserSpaceDao; +import space.space_spring.dto.user.GetUserProfileListDto; import space.space_spring.dto.user.dto.SpaceChoiceViewDto; import space.space_spring.dto.user.request.PostUserLoginRequest; import space.space_spring.dto.user.request.PostUserSignupRequest; @@ -20,6 +21,8 @@ import space.space_spring.util.user.UserUtils; import space.space_spring.util.userSpace.UserSpaceUtils; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import static space.space_spring.entity.enumStatus.UserSignupType.LOCAL; @@ -96,4 +99,36 @@ public GetSpaceInfoForUserResponse getSpaceListForUser(Long userId, int size, Lo return new GetSpaceInfoForUserResponse(userName, spaceChoiceViewDto.getLastUserSpaceId(), spaceChoiceViewDto.getSpaceChoiceInfoList()); } + @Transactional + public GetUserProfileListDto.Response getUserProfileList(Long userId) { + // TODO 1. userId로 User find + User userByUserId = userUtils.findUserByUserId(userId); + + // TODO 2. 유저가 속해있는 UserSpace list get + List userSpaceListByUser = userSpaceDao.findUserSpaceListByUser(userByUserId); + + // TODO 3. return + List userProfileList = createUserProfileList(userSpaceListByUser); + + return new GetUserProfileListDto.Response(userProfileList); + } + + private List createUserProfileList(List userSpaceList) { + List userProfileList = new ArrayList<>(); + + for (UserSpace userSpace : userSpaceList) { + GetUserProfileListDto.UserProfile userProfile = new GetUserProfileListDto.UserProfile( + userSpace.getSpace().getSpaceId(), + userSpace.getSpace().getSpaceName(), + userSpace.getUserName(), + userSpace.getUserProfileImg(), + userSpace.getUserSpaceAuth() + ); + + userProfileList.add(userProfile); + } + + return userProfileList; + } + } diff --git a/src/main/java/space/space_spring/validator/AllowedImageFileExtensions.java b/src/main/java/space/space_spring/validator/AllowedImageFileExtensions.java index b863798d..57b39739 100644 --- a/src/main/java/space/space_spring/validator/AllowedImageFileExtensions.java +++ b/src/main/java/space/space_spring/validator/AllowedImageFileExtensions.java @@ -25,6 +25,8 @@ public enum AllowedImageFileExtensions { } public static boolean contains(String extension) { + extension = extension.toLowerCase(); // 입력된 확장자를 소문자로 변환 + for (AllowedImageFileExtensions allowedImageFileExtensions : AllowedImageFileExtensions.values()) { if (allowedImageFileExtensions.getExtension().equals(extension)) { return true;