Skip to content

Commit

Permalink
Merge pull request #157 from swm-nodriversomabus/BUS-203-Authority-check
Browse files Browse the repository at this point in the history
feat(BE): 사용자/매칭 생성 및 삭제 권한 제어 BUS-203-Authority-check #156
  • Loading branch information
namhyo01 authored Oct 25, 2023
2 parents 708c160 + f829608 commit 3100a2c
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public ResponseEntity<?> exceptionHandler(CustomException e) {
return ResponseEntity.status(e.getErrorCodeEnum().getHttpStatus())
.body(new ExceptionDto(e.getErrorCodeEnum()));
}

@ExceptionHandler(value = MethodArgumentNotValidException.class)
public ResponseEntity<?> methodArgumentNotValidException(MethodArgumentNotValidException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
Expand All @@ -32,7 +32,7 @@ public ResponseEntity<?> constraintViolationException(ConstraintViolationExcepti
log.error(e.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}

@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String runtimeExceptionHandler(RuntimeException e) {
Expand Down
20 changes: 15 additions & 5 deletions src/main/java/com/example/api/common/type/ErrorCodeEnum.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,22 @@
@Getter
@AllArgsConstructor
public enum ErrorCodeEnum {
LOGIN_IS_NOT_DONE(HttpStatus.UNAUTHORIZED, "로그인 정보가 없습니다"),
INVALID_PERMISSION(HttpStatus.UNAUTHORIZED, "권한이 없습니다"),
DATABASE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "데이터베이스 오류"),
CODE_IS_NOT_VALID(HttpStatus.BAD_REQUEST, "잘못된 인증번호입니다"),
// 200 OK
SUCCESS(HttpStatus.OK, "정상 처리되었습니다"),
// 201 Created
CREATED(HttpStatus.CREATED, "생성되었습니다"),
// 400 Bad Request
USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "유저 정보가 없습니다"),
CODE_IS_EXPIRED(HttpStatus.BAD_REQUEST, "휴대전화를 인증해주세요");
CODE_IS_EXPIRED(HttpStatus.BAD_REQUEST, "휴대전화를 인증해주세요"),
CODE_IS_NOT_VALID(HttpStatus.BAD_REQUEST, "잘못된 인증번호입니다"),
MATCHING_NOT_FOUND(HttpStatus.BAD_REQUEST, "매칭 정보가 없습니다"),
// 401 Unauthorized
LOGIN_IS_NOT_DONE(HttpStatus.UNAUTHORIZED, "로그인 정보가 없습니다"),
// 403 Forbidden
INVALID_PERMISSION(HttpStatus.FORBIDDEN, "권한이 없습니다"),
// 500 Internal Server Error
DATABASE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "데이터베이스 오류");

private final HttpStatus httpStatus;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package com.example.api.matching.adapter.in.rest;

import com.example.api.auth.domain.SecurityUser;
import com.example.api.chatroom.domain.ChatRoom;
import com.example.api.common.exception.CustomException;
import com.example.api.common.type.ApplicationStateEnum;
import com.example.api.common.type.ErrorCodeEnum;
import com.example.api.common.utils.AuthenticationUtils;
import com.example.api.matching.adapter.out.persistence.MatchingApplicationPK;
import com.example.api.matching.application.port.in.*;
import com.example.api.matching.domain.MatchingApplication;
import com.example.api.matching.dto.*;
import com.example.api.user.application.port.in.FindUserUsecase;
import com.example.api.user.dto.FindUserDto;
import com.example.api.user.dto.UserAuthorityCheckDto;
import com.example.api.user.type.UserRoleEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,6 +30,7 @@
@Slf4j
@Tag(name = "Matching", description = "Matching API")
public class MatchingController {
private final FindUserUsecase findUserUsecase;
private final SaveMatchingUsecase saveMatchingUsecase;
private final FindMatchingUsecase findMatchingUsecase;
private final DeleteMatchingUsecase deleteMatchingUsecase;
Expand All @@ -48,10 +56,22 @@ public FindMatchingDto createMatching(@RequestBody SaveMatchingDto matchingDto)
@Operation(summary = "Create matching application", description = "새로운 매칭 신청을 생성한다.")
@PostMapping("/matching/application")
public ChatRoom createMatchingApplication(@RequestBody SaveMatchingApplicationDto matchingApplicationDto) {
if (findMatchingUsecase.getMatchingById(matchingApplicationDto.getMatchingId()).isEmpty()) {
log.error("MatchingController::createMatchingApplication: no such matching");
return ChatRoom.builder().build();
Optional<FindMatchingDto> matchingDto = findMatchingUsecase.getMatchingById(matchingApplicationDto.getMatchingId());
if (matchingDto.isEmpty()) {
log.error("MatchingController::createMatchingApplication: No such matching.");
throw new CustomException(ErrorCodeEnum.MATCHING_NOT_FOUND);
}

SecurityUser securityUser = AuthenticationUtils.getCurrentUserAuthentication();
if (securityUser == null) {
log.error("MatchingController::createMatchingApplication: Authentication is needed.");
throw new CustomException(ErrorCodeEnum.LOGIN_IS_NOT_DONE);
}
if (securityUser.getUserId().equals(matchingApplicationDto.getUserId())) {
log.error("MatchingController::createMatchingApplication: WriterId equals to applicantId.");
throw new CustomException(ErrorCodeEnum.INVALID_PERMISSION);
}

MatchingApplication matchingApplication = matchingApplicationUsecase.createMatchingApplicationData(matchingApplicationDto);
ChatRoom chatRoom = matchingApplicationUsecase.createMatchingChatRoom(matchingApplication);
return matchingApplicationUsecase.setupMatchingChatRoom(matchingApplication, chatRoom);
Expand Down Expand Up @@ -166,6 +186,10 @@ public void processMatchingApplication(SaveMatchingApplicationDto matchingApplic
@Operation(summary = "Delete all matching", description = "모든 매칭을 삭제한다.")
@DeleteMapping("/matching")
public void deleteAll() {
if (!(findUserUsecase.getUser().getRole().equals(UserRoleEnum.Admin))) {
log.error("MatchingController::deleteAll: Admin authority is needed.");
throw new CustomException(ErrorCodeEnum.INVALID_PERMISSION);
}
deleteMatchingUsecase.deleteAll();
}

Expand All @@ -176,6 +200,16 @@ public void deleteAll() {
@Operation(summary = "Delete matching", description = "ID가 matchingId인 매칭을 삭제한다.")
@DeleteMapping("/matching/{matchingId}")
public void deleteMatching(@PathVariable Long matchingId) {
UserAuthorityCheckDto userDto = findUserUsecase.getAuthorityUser();
Optional<FindMatchingDto> matchingDto = findMatchingUsecase.getMatchingById(matchingId);
if (matchingDto.isEmpty()) {
log.error("MatchingController::deleteMatching: No such matching.");
throw new CustomException(ErrorCodeEnum.MATCHING_NOT_FOUND);
}
if (!(userDto.getRole().equals(UserRoleEnum.Admin)) && !(userDto.getUserId().equals(matchingDto.get().getWriterId()))) {
log.error("MatchingController::deleteMatching: Admin or owner authority is needed.");
throw new CustomException(ErrorCodeEnum.INVALID_PERMISSION);
}
deleteMatchingUsecase.deleteMatching(matchingId);
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package com.example.api.user.adapter.in.rest;

import com.example.api.common.exception.CustomException;
import com.example.api.common.type.ApplicationStateEnum;
import com.example.api.common.type.ErrorCodeEnum;
import com.example.api.matching.application.port.in.FindMatchingUsecase;
import com.example.api.matching.application.port.in.MatchingApplicationUsecase;
import com.example.api.matching.dto.FindMatchingDto;
import com.example.api.user.application.port.in.*;
import com.example.api.user.dto.CreateUserDto;
import com.example.api.user.dto.FindUserDto;
import com.example.api.user.dto.UpdateUserDto;
import com.example.api.user.type.UserRoleEnum;
import com.example.api.user.validator.CreateGenderValidator;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
Expand All @@ -25,6 +29,7 @@
@RequiredArgsConstructor
@EnableWebMvc
@Validated
@Slf4j
@Tag(name = "User", description = "User API")
public class UserController {
private final SaveUserUsecase saveUserUsecase;
Expand Down Expand Up @@ -126,6 +131,10 @@ public FindUserDto updateUser(@RequestBody UpdateUserDto userDto) {
@Operation(summary = "Delete all users", description = "모든 사용자를 삭제한다.")
@DeleteMapping("/user/all")
public void deleteAll() {
if (!(findUserUsecase.getUser().getRole().equals(UserRoleEnum.Admin))) {
log.error("UserController::deleteAll: Admin authority is needed.");
throw new CustomException(ErrorCodeEnum.INVALID_PERMISSION);
}
deleteUserUsecase.deleteAll();
}

Expand All @@ -135,6 +144,10 @@ public void deleteAll() {
@Operation(summary = "Delete user", description = "ID가 userId인 사용자를 삭제한다.")
@DeleteMapping("/user")
public void deleteUser() {
if (!(findUserUsecase.getUser().getRole().equals(UserRoleEnum.Admin))) {
log.error("UserController::deleteUser: Admin authority is needed.");
throw new CustomException(ErrorCodeEnum.INVALID_PERMISSION);
}
deleteUserUsecase.deleteUser();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.example.api.user.dto.CreateUserDto;
import com.example.api.user.dto.FindUserDto;
import com.example.api.user.dto.UpdateUserDto;
import com.example.api.user.dto.UserAuthorityCheckDto;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
Expand All @@ -23,5 +24,6 @@ public interface UserMapperInterface {
User toDomain(UserEntity userEntity);
FindUserDto toDto(UserEntity userEntity);
FindUserDto toDto(User user);
UserAuthorityCheckDto toAuthorityDto(UserEntity userEntity);
FindUserDto toDto(UpdateUserDto updateUserDto);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.example.api.user.application.port.in;

import com.example.api.user.dto.FindUserDto;
import com.example.api.user.dto.UserAuthorityCheckDto;

import java.util.List;

public interface FindUserUsecase {
List<FindUserDto> getAll();
FindUserDto getUser();
UserAuthorityCheckDto getAuthorityUser();
}
1 change: 0 additions & 1 deletion src/main/java/com/example/api/user/dto/FindUserDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.time.LocalDateTime;

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/example/api/user/dto/UserAuthorityCheckDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.example.api.user.dto;

import com.example.api.user.type.UserRoleEnum;
import jakarta.validation.constraints.NotNull;
import lombok.*;

import java.util.UUID;

@Getter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserAuthorityCheckDto {
@NotNull
private UUID userId;

@NotNull
private UserRoleEnum role;

@NotNull
private Boolean blacklist;

@NotNull
private Boolean isActive;
}
36 changes: 26 additions & 10 deletions src/main/java/com/example/api/user/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.example.api.user.application.port.in.SaveUserUsecase;
import com.example.api.user.dto.CreateUserDto;
import com.example.api.user.dto.UpdateUserDto;
import com.example.api.user.dto.UserAuthorityCheckDto;
import com.example.api.user.type.UserGenderEnum;
import com.example.api.user.type.UserRoleEnum;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -60,6 +61,15 @@ public FindUserDto getDefaultUser() {
.isActive(false)
.build();
}

public UserAuthorityCheckDto getDefaultAuthorityUser() {
return UserAuthorityCheckDto.builder()
.userId(UUID.fromString("00000000-0000-0000-0000-000000000000"))
.role(UserRoleEnum.User)
.blacklist(false)
.isActive(false)
.build();
}

@Override
@Transactional
Expand All @@ -84,12 +94,23 @@ public FindUserDto getUser() {
log.error("UserService::getUser: Authentication is needed");
return this.getDefaultUser();
}
log.info("UserID: {}", securityUser.getUserId());
return findUserPort.getByUserId(securityUser.getUserId())
.map(userMapper::toDto)
.orElse(this.getDefaultUser());
}

@Override
public UserAuthorityCheckDto getAuthorityUser() {
SecurityUser securityUser = AuthenticationUtils.getCurrentUserAuthentication();
if (securityUser == null) {
log.error("UserService::getAuthorityUser: Authentication is needed");
return this.getDefaultAuthorityUser();
}
return findUserPort.getByUserId(securityUser.getUserId())
.map(userMapper::toAuthorityDto)
.orElse(this.getDefaultAuthorityUser());
}

@Override
@Transactional
public FindUserDto updateUser(UpdateUserDto userDto) {
Expand All @@ -112,22 +133,17 @@ public void deleteAll() {
@Transactional
public void deleteUser() {
SecurityUser securityUser = AuthenticationUtils.getCurrentUserAuthentication();
try {
if (securityUser == null) {
log.error("UserService::deleteUser: Authentication is needed.");
throw new Exception();
}
deleteUserPort.deleteByUserId(securityUser.getUserId());
} catch (Exception e) {
e.printStackTrace();
if (securityUser == null) {
log.error("UserService::deleteUser: Authentication is needed.");
return;
}
deleteUserPort.deleteByUserId(securityUser.getUserId());
}

// Social

public SecurityUser findSocialUser(String id, String provider) {
User user = userMapper.toDomain(findUserPort.findSocialUser(id, provider).orElseThrow(IllegalStateException::new));

return SecurityUser.builder()
.userId(user.getUserId())
.naverId(user.getSocialId().getNaverId())
Expand Down

0 comments on commit 3100a2c

Please sign in to comment.