Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/19 시큐리티 세팅 및 Invitation 관련 로직 추가, 초대장 조회 API 구현 #20

Merged
merged 3 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package treehouse.server.api.invitation.business;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
import treehouse.server.api.invitation.presentation.dto.InvitationResponseDTO;
import treehouse.server.global.entity.Invitation.Invitation;
import treehouse.server.global.entity.User.User;
import treehouse.server.global.entity.User.UserRole;
import treehouse.server.global.entity.User.UserStatus;

import java.util.List;

@Component
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class InvitationMapper {

public InvitationResponseDTO.getInvitation toGetInvitation (Invitation invitation, List<String> treeMemberProfileImages) {
return InvitationResponseDTO.getInvitation.builder()
.invitationId(invitation.getId())
.treehouseName(invitation.getTreeHouse().getName())
.senderName(invitation.getSender().getName())
.senderProfileImageUrl(invitation.getSender().getProfileImageUrl())
.treehouseSize(invitation.getTreeHouse().getMemberList().size())
.treehouseMemberProfileImages(treeMemberProfileImages)
.build();
}
public InvitationResponseDTO.getInvitations toGetInvitations(List<InvitationResponseDTO.getInvitation> invitationDtos) {
return InvitationResponseDTO.getInvitations.builder()
.invitations(invitationDtos)
.build();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package treehouse.server.api.invitation.business;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import treehouse.server.api.invitation.implement.InvitationCommandAdapter;
import treehouse.server.api.invitation.implement.InvitationQueryAdapter;
import treehouse.server.api.invitation.presentation.dto.InvitationRequestDTO;
import treehouse.server.api.invitation.presentation.dto.InvitationResponseDTO;
import treehouse.server.global.entity.Invitation.Invitation;
import treehouse.server.global.entity.User.User;
import treehouse.server.global.entity.member.Member;
import treehouse.server.global.entity.redis.RefreshToken;
import treehouse.server.global.entity.treeHouse.TreeHouse;
import treehouse.server.global.exception.GlobalErrorCode;
import treehouse.server.global.exception.ThrowClass.AuthException;
import treehouse.server.global.exception.ThrowClass.GeneralException;
import treehouse.server.global.redis.service.RedisService;
import treehouse.server.global.security.jwt.dto.TokenDTO;
import treehouse.server.global.security.provider.TokenProvider;

import java.util.List;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
@Slf4j
public class InvitationService {


private final InvitationQueryAdapter invitationQueryAdapter;

private final InvitationCommandAdapter invitationCommandAdapter;
private final InvitationMapper invitationMapper;
private static final Integer treeMemberRandomProfileSize = 3;


@Transactional
public InvitationResponseDTO.getInvitations getInvitations(User user) {

log.error("User name : ", user.getName());
log.error("User id : ", user.getId());
List<Invitation> invitations = invitationQueryAdapter.findAllByPhone(user.getPhone());
log.error("size : ", invitations.size());

List<InvitationResponseDTO.getInvitation> invitationDtos = invitations.stream()
.map(invitation -> {
TreeHouse treeHouse = invitation.getTreeHouse();
List<Member> treeMembers = treeHouse.getMemberList();
List<String> randomProfileImages = treeMembers.stream()
.map(Member::getProfileImageUrl)
.limit(treeMemberRandomProfileSize)
.toList();
return invitationMapper.toGetInvitation(invitation, randomProfileImages);
})
.collect(Collectors.toList());
return invitationMapper.toGetInvitations(invitationDtos);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package treehouse.server.api.invitation.implement;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import treehouse.server.api.invitation.persistence.InvitationRepository;
import treehouse.server.global.annotations.Adapter;
import treehouse.server.global.entity.User.User;
import treehouse.server.global.entity.User.UserRole;
import treehouse.server.global.entity.redis.RefreshToken;
import treehouse.server.global.redis.service.RedisService;
import treehouse.server.global.security.jwt.dto.TokenDTO;
import treehouse.server.global.security.provider.TokenProvider;

import java.util.List;

@Adapter
@Slf4j
@RequiredArgsConstructor
public class InvitationCommandAdapter {

private final InvitationRepository invitationRepository;


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package treehouse.server.api.invitation.implement;

import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import treehouse.server.api.invitation.persistence.InvitationRepository;
import treehouse.server.api.invitation.presentation.dto.InvitationRequestDTO;
import treehouse.server.global.annotations.Adapter;
import treehouse.server.global.entity.Invitation.Invitation;
import treehouse.server.global.entity.User.User;
import treehouse.server.global.exception.GlobalErrorCode;
import treehouse.server.global.exception.ThrowClass.UserException;

import java.util.List;
import java.util.Optional;

@Adapter
@RequiredArgsConstructor
public class InvitationQueryAdapter {

private final InvitationRepository invitationRepository;

public List<Invitation> findAllByPhone(String phone) {
return invitationRepository.findAllByPhone(phone);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package treehouse.server.api.invitation.persistence;

import org.springframework.data.jpa.repository.JpaRepository;
import treehouse.server.global.entity.Invitation.Invitation;
import treehouse.server.global.entity.User.User;
import treehouse.server.global.entity.treeHouse.TreeHouse;

import java.util.List;
import java.util.Optional;

public interface InvitationRepository extends JpaRepository<Invitation, Long> {

List<Invitation> findAllByPhone(String phone);

Invitation findByPhoneAndTreeHouse(String phone, TreeHouse treeHouse);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package treehouse.server.api.invitation.presentation;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import treehouse.server.api.invitation.business.InvitationService;
import treehouse.server.api.invitation.presentation.dto.InvitationRequestDTO;
import treehouse.server.api.invitation.presentation.dto.InvitationResponseDTO;
import treehouse.server.global.common.CommonResponse;
import treehouse.server.global.entity.User.User;
import treehouse.server.global.security.handler.annotation.AuthMember;

@RestController
@RequiredArgsConstructor
@Slf4j
@Validated
@Tag(name = "😎 Invitation API", description = "초대장 관련 API 입니다. 초대장 조회, 전송 등의 API가 포함됩니다.")
@RequestMapping("/invi")
public class InvitationApi {

private final InvitationService invitationService;

@GetMapping("/invitation")
@Operation(summary = "초대장 조회", description = "내가 받은 초대장을 조회합니다.")
public CommonResponse<InvitationResponseDTO.getInvitations> getInvitations(
@AuthMember @Parameter(hidden = true) User user
) {
return CommonResponse.onSuccess(invitationService.getInvitations(user));
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package treehouse.server.api.invitation.presentation.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;


public class InvitationRequestDTO {




}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package treehouse.server.api.invitation.presentation.dto;

import lombok.*;

import java.util.List;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class InvitationResponseDTO {

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class getInvitation {
private Long invitationId;
private String treehouseName;
private String senderName;
private String senderProfileImageUrl;
private Integer treehouseSize;
private List<String> treehouseMemberProfileImages;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class getInvitations {
List<InvitationResponseDTO.getInvitation> invitations;
}

}
16 changes: 15 additions & 1 deletion src/main/java/treehouse/server/api/user/business/UserMapper.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
package treehouse.server.api.user.business;

import jakarta.annotation.PostConstruct;
import lombok.*;
import org.springframework.stereotype.Component;
import treehouse.server.api.user.presentation.dto.UserResponseDTO;
import treehouse.server.global.entity.User.User;
import treehouse.server.global.entity.User.UserRole;
import treehouse.server.global.entity.User.UserStatus;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Component
//@NoArgsConstructor(access = AccessLevel.PRIVATE)
@RequiredArgsConstructor
public class UserMapper {

private final UserService userService;
private static UserService staticUserService;
@PostConstruct
public void init(){
this.staticUserService = this.userService;
}

public static User toUserSecurity(String id){
return staticUserService.findById(Long.valueOf(id));
}

public static UserResponseDTO.checkName toCheckNameDTO(boolean isDuplicated){
return UserResponseDTO.checkName.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public UserResponseDTO.checkName checkName(UserRequestDTO.checkName request){
return UserMapper.toCheckNameDTO(userQueryAdapter.checkName(request));
}

@Transactional(readOnly = true)
public User findById(Long id){
return userQueryAdapter.findById(id);
}

@Transactional
public UserResponseDTO.registerUser register(UserRequestDTO.registerUser request){
User user = UserMapper.toUser(request.getUserName(), request.getPhoneNumber());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ public Optional<User> findByPhoneNumber(String phone){
public User findById(Long id){
return userRepository.findById(id).orElseThrow(()->new UserException(GlobalErrorCode.MEMBER_NOT_FOUND));
}

public Optional<User> optionalUserFindById(Long id){
return userRepository.findById(id);
}
}
27 changes: 27 additions & 0 deletions src/main/java/treehouse/server/global/config/GlobalWebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package treehouse.server.global.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import treehouse.server.global.security.handler.annotation.resolver.AuthMemberArgumentResolver;

import java.util.List;

@Configuration
@RequiredArgsConstructor
public class GlobalWebConfig implements WebMvcConfigurer {

private final AuthMemberArgumentResolver authMemberArgumentResolver;

/**
* 컨트롤러 메서드의 특정 파라미터를 지원하는 커스텀한 ArgumentResolver를 추가
* @param resolverList
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolverList) {
resolverList.add(authMemberArgumentResolver);
}
}
18 changes: 17 additions & 1 deletion src/main/java/treehouse/server/global/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package treehouse.server.global.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -15,8 +18,21 @@ public OpenAPI SpringCodeBaseAPI() {
.description("Treehouse API 명세서")
.version("1.0.0");

String jwtSchemeName = "JWT TOKEN";
// API 요청헤더에 인증정보 포함
SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwtSchemeName);
// SecuritySchemes 등록
Components components = new Components()
.addSecuritySchemes(jwtSchemeName, new SecurityScheme()
.name(jwtSchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT"));

return new OpenAPI()
.addServersItem(new Server().url("/"))
.info(info);
.info(info)
.addSecurityItem(securityRequirement)
.components(components);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import jakarta.persistence.*;
import lombok.*;
import treehouse.server.global.entity.User.User;
import treehouse.server.global.entity.common.BaseDateTimeEntity;
import treehouse.server.global.entity.member.Member;
import treehouse.server.global.entity.treeHouse.TreeHouse;
Expand All @@ -29,6 +30,10 @@ public class Invitation extends BaseDateTimeEntity {
@JoinColumn(name = "senderId")
@ManyToOne(fetch = FetchType.LAZY)
private Member sender;

@JoinColumn(name = "receiverId")
@ManyToOne(fetch = FetchType.LAZY)
private User receiver;
@JoinColumn(name = "treeId")
@ManyToOne(fetch = FetchType.LAZY)
private TreeHouse treeHouse;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
package treehouse.server.global.security.handler.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) // 런타임 중에 어노테이션 정보를 조회하고 처리할 수 있도록 설정
@Target(ElementType.PARAMETER) // 어노테이션을 파라미터에만 적용
public @interface AuthMember {
}
Loading
Loading