Skip to content

Commit

Permalink
Merge pull request #45 from LikeLion-12th-SKHU/develop
Browse files Browse the repository at this point in the history
Develop -> main push
  • Loading branch information
ttttkii913 authored Jul 27, 2024
2 parents 3c1c8b2 + c606fad commit 3ff9ed6
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
package org.likelion.likelion_12th_team05.common.advice;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.likelion.likelion_12th_team05.common.error.ErrorCode;
import org.likelion.likelion_12th_team05.common.exception.CustomException;
import org.likelion.likelion_12th_team05.common.exception.NotFoundException;
import org.likelion.likelion_12th_team05.config.ApiResponseTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.stereotype.Component;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@ControllerAdvice
public class CustomExceptionAdvice {
import java.util.HashMap;
import java.util.Map;

private static final Logger log = LoggerFactory.getLogger(CustomExceptionAdvice.class);
@RestControllerAdvice
@Component
@RequiredArgsConstructor
@Slf4j
public class CustomExceptionAdvice {

// ์—”ํ‹ฐํ‹ฐ not found ์—๋Ÿฌ ์ฒ˜๋ฆฌ ํ•ธ๋“ค๋Ÿฌ
@ExceptionHandler(NotFoundException.class)
Expand All @@ -32,10 +39,37 @@ public ApiResponseTemplate handleCustomException(CustomException exception) {
}

// ์›์ธ ๋ชจ๋ฅผ ์ด์œ ์˜ ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public ApiResponseTemplate handleServerException(final Exception e) {
log.error("Internal Server Error: {}", e.getMessage(), e);
return ApiResponseTemplate.errorResponse(ErrorCode.INTERNAL_SERVER_ERROR);
}

/**
* 400 BAD REQUEST validation
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponseTemplate<String> handleValidationExceptions(MethodArgumentNotValidException e) {
log.error("Validation error: {}", e.getMessage(), e); // ์ˆ˜์ •: ๋กœ๊ทธ ์ถ”๊ฐ€

// ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ
Map<String, String> errorMap = new HashMap<>();
for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
}
// ์‘๋‹ต ์ƒ์„ฑ
return ApiResponseTemplate.errorResponse(ErrorCode.VALIDATION_ERROR, convertMapToString(errorMap));
}

private String convertMapToString(Map<String, String> map) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : map.entrySet()) {
sb.append(entry.getKey()).append(" : ").append(entry.getValue()).append(", ");
}
if (sb.length() > 0) {
sb.setLength(sb.length() - 2); // ๋งˆ์ง€๋ง‰ ์‰ผํ‘œ์™€ ๋„์–ด์“ฐ๊ธฐ๋ฅผ ์ œ๊ฑฐ
}
return sb.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public enum SuccessCode { // Success ์ƒํƒœ์™€ ๋ฉ”์„ธ์ง€, ์ฝ”๋“œ๋ฅผ ์ •์˜
LIKE_DELETE_SUCCESS("์ข‹์•„์š”๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."),
USER_SIGNUP_SUCCESS("ํšŒ์›๊ฐ€์ž…์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค."),
USER_LOGIN_SUCCESS("๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค."),
USER_INFO_UPDATE_SUCCESS("์‚ฌ์šฉ์ž์˜ ์ •๋ณด๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."),
/**
* 201 CREATED (POST์˜ ๊ฒฐ๊ณผ ์ƒํƒœ
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@

import lombok.Builder;
import org.likelion.likelion_12th_team05.curation.domain.Curation;

import java.time.LocalDate;
import org.likelion.likelion_12th_team05.location.api.dto.response.LocationInfoResDto;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Builder
public record CurationInfoResDto(
Long id,
String name,
String content,
LocalDateTime createDate,
Integer likeCount
Integer likeCount,
List<LocationInfoResDto> locations
) {
public static CurationInfoResDto from(Curation curation) {
return CurationInfoResDto.builder()
Expand All @@ -21,6 +23,9 @@ public static CurationInfoResDto from(Curation curation) {
.content(curation.getContent())
.createDate(curation.getCreateDate())
.likeCount(curation.getLikeCount())
.locations(curation.getLocations().stream()
.map(LocationInfoResDto::from)
.collect(Collectors.toList()))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ public ApiResponseTemplate<LocationListResDto> locationFindAll(Principal princip
@PostMapping(value = "/{curationId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.OK)
public ApiResponseTemplate<LocationInfoResDto> locationSave(@RequestPart("location") LocationSaveReqDto locationSaveReqDto,
@RequestPart("locationImage") MultipartFile locationImage,
@RequestParam(value = "locationImage", required=false) MultipartFile locationImage,
@PathVariable("curationId") Long curationId,
Principal principal) throws IOException {
LocationInfoResDto locationInfoResDto = locationService.locationSave(locationSaveReqDto, locationImage, curationId, principal);
return ApiResponseTemplate.successResponse(locationInfoResDto, SuccessCode.LOCATION_SAVE_SUCCESS);
}

@Operation(summary = "์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์œ„์น˜ ์ˆ˜์ •", description = "์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์œ„์น˜๋ฅผ ์ˆ˜์ •(์œ„์น˜ ์ด๋ฆ„, ์ด๋ฏธ์ง€)ํ•ฉ๋‹ˆ๋‹ค.")
@Operation(summary = "์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์œ„์น˜ ์ˆ˜์ •", description = "์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์œ„์น˜๋ฅผ ์ˆ˜์ •(์œ„์น˜ ์ด๋ฆ„, ์ด๋ฏธ์ง€(์„ ํƒ), ์ฃผ์†Œ)ํ•ฉ๋‹ˆ๋‹ค.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "์‘๋‹ต ์ƒ์„ฑ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค."),
@ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ์ž…๋‹ˆ๋‹ค."),
Expand All @@ -67,7 +67,7 @@ public ApiResponseTemplate<LocationInfoResDto> locationSave(@RequestPart("locati
@ResponseStatus(HttpStatus.OK)
public ApiResponseTemplate<LocationInfoResDto> locationUpdate(@PathVariable("locationId") Long locationId,
@RequestPart("location") LocationUpdateReqDto locationUpdateReqDto,
@RequestPart("locationImage") MultipartFile locationImage,
@RequestParam(value = "locationImage", required = false) MultipartFile locationImage,
Principal principal) throws IOException {
LocationInfoResDto locationInfoResDto = locationService.locationUpdate(locationId, locationUpdateReqDto, locationImage, principal);
return ApiResponseTemplate.successResponse(locationInfoResDto, SuccessCode.LOCATION_UPDATE_SUCCESS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ public record LocationSaveReqDto(
String address
) {
public Location toEntity(String locationImage, Curation curation, User user) {
// ์œ„์น˜ ์ €์žฅ ์‹œ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒ์œผ๋กœ ์ˆ˜์ •/ ์ด๋ฏธ์ง€๊ฐ€ ๋น„์–ด์žˆ์ง€ ์•Š๋‹ค๋ฉด ์ด๋ฏธ์ง€ ์ €์žฅ, ๋น„์–ด์žˆ๋‹ค๋ฉด ๋นˆ ๋ฌธ์ž์—ด๋กœ locationImage ์ €์žฅ => location ์—”ํ‹ฐํ‹ฐ์—์„œ locationImage nullable ์ง€์›Œ์คŒ
String image = (locationImage != null) ? locationImage : "";

return Location.builder()
.name(name)
.description(description)
.address(address)
.locationImage(locationImage)
.locationImage(image)
.curation(curation)
.user(user)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ public LocationInfoResDto locationSave(LocationSaveReqDto locationSaveReqDto, Mu
, ErrorCode.NO_AUTHORIZATION_EXCEPTION.getMessage());
}

String locationImage = s3Service.upload(multipartFile, "location");
// ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ๋ฅผ ์„ ํƒ์ ์œผ๋กœ ๋„˜๊ธฐ๋ฉด์„œ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ์—๋งŒ ์—…๋กœ๋“œ
String locationImage = null; // ์ด๋ฏธ์ง€ URL์„ ์ €์žฅํ•  ๋ณ€์ˆ˜
if (multipartFile != null && !multipartFile.isEmpty()) {
locationImage = s3Service.upload(multipartFile, "location");
}

Location location = locationSaveReqDto.toEntity(locationImage, curation, user);
locationRepository.save(location);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class Location {
private String description;

@JsonIgnore
@Column(name = "location_image", nullable = false)
@Column(name = "location_image")
private String locationImage;

@JsonIgnore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
import org.likelion.likelion_12th_team05.config.ApiResponseTemplate;
import org.likelion.likelion_12th_team05.global.auth.googleAuth.AuthLoginService;
import org.likelion.likelion_12th_team05.global.auth.googleAuth.GoogleToken;
import org.likelion.likelion_12th_team05.global.auth.jwt.JwtTokenProvider;
import org.likelion.likelion_12th_team05.user.api.dto.request.UserInfoUpdateReqDto;
import org.likelion.likelion_12th_team05.user.api.dto.request.UserSignInReqDto;
import org.likelion.likelion_12th_team05.user.api.dto.request.UserSignUpReqDto;
import org.likelion.likelion_12th_team05.user.api.dto.response.UserInfoResDto;
import org.likelion.likelion_12th_team05.user.api.dto.response.UserSignInResDto;
import org.likelion.likelion_12th_team05.user.application.UserService;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;

@RestController
public class UserController {
private final UserService userService;
Expand Down Expand Up @@ -64,4 +67,16 @@ private ApiResponseTemplate<UserSignInResDto> userSignIn(@RequestBody @Valid Use
UserSignInResDto userSignInResDto = userService.userSignIn(userSignInReqDto);
return ApiResponseTemplate.successResponse(userSignInResDto, SuccessCode.USER_LOGIN_SUCCESS);
}

@Operation(summary = "์‚ฌ์šฉ์ž ์ •๋ณด ์ˆ˜์ •", description = "์‚ฌ์šฉ์ž์˜ ์ •๋ณด(์ด๋ฆ„, ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ)๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "์‘๋‹ต ์ƒ์„ฑ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค."),
@ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ์ž…๋‹ˆ๋‹ค."),
@ApiResponse(responseCode = "401", description = "์ธ์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.")
})
@PatchMapping("/user/info")
private ApiResponseTemplate<UserInfoResDto> userInfoUpdate(@RequestBody @Valid UserInfoUpdateReqDto userInfoUpdateReqDto, Principal principal) {
UserInfoResDto userInfoResDto = userService.userInfoUpdate(userInfoUpdateReqDto, principal);
return ApiResponseTemplate.successResponse(userInfoResDto, SuccessCode.USER_INFO_UPDATE_SUCCESS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.likelion.likelion_12th_team05.user.api.dto.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;

public record UserInfoUpdateReqDto(
@NotBlank(message = "์ด๋ฆ„์„ ํ•„์ˆ˜๋กœ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
@Size(min = 2, max = 15, message = "2์ž ์ด์ƒ, 15์ž ์ดํ•˜๋กœ ์ž…๋ ฅํ•˜์„ธ์š”.")
String name,

@NotBlank(message = "๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ•„์ˆ˜๋กœ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
@Size(min = 8, message = "8์ž ์ด์ƒ ์ž…๋ ฅํ•˜์„ธ์š”.")
String password,

@NotBlank(message = "์ด๋ฉ”์ผ์„ ํ•„์ˆ˜๋กœ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
@Pattern(regexp = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,6}$", message = "์ด๋ฉ”์ผ ํ˜•์‹์ด ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
String email
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.likelion.likelion_12th_team05.user.api.dto.response;

import lombok.Builder;
import org.likelion.likelion_12th_team05.user.domain.User;

@Builder
public record UserInfoResDto(
Long userId,
String name,
String email
) {
public static UserInfoResDto from(User user) {
return UserInfoResDto.builder()
.name(user.getName())
.email(user.getEmail())
.userId(user.getId())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package org.likelion.likelion_12th_team05.user.application;

import lombok.extern.slf4j.Slf4j;
import org.likelion.likelion_12th_team05.common.EntityFinder;
import org.likelion.likelion_12th_team05.common.error.ErrorCode;
import org.likelion.likelion_12th_team05.global.auth.jwt.JwtTokenProvider;
import org.likelion.likelion_12th_team05.user.api.dto.request.UserInfoUpdateReqDto;
import org.likelion.likelion_12th_team05.user.api.dto.request.UserSignInReqDto;
import org.likelion.likelion_12th_team05.user.api.dto.request.UserSignUpReqDto;
import org.likelion.likelion_12th_team05.user.api.dto.response.UserInfoResDto;
import org.likelion.likelion_12th_team05.user.api.dto.response.UserSignInResDto;
import org.likelion.likelion_12th_team05.user.domain.Role;
import org.likelion.likelion_12th_team05.user.domain.User;
Expand All @@ -12,6 +16,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.Principal;

@Slf4j
@Service
@Transactional(readOnly = true)
Expand Down Expand Up @@ -57,4 +63,26 @@ public UserSignInResDto userSignIn(UserSignInReqDto userSignUpReqDto) {

return UserSignInResDto.of(user, accessToken, refreshToken);
}

@Transactional
public UserInfoResDto userInfoUpdate(UserInfoUpdateReqDto userInfoUpdateReqDto, Principal principal) {
String email = principal.getName();
User user = getUserByEmail(email);

user.update(userInfoUpdateReqDto);

// ๋น„๋ฐ€๋ฒˆํ˜ธ ์ˆ˜์ •ํ•  ๊ฒฝ์šฐ์—๋„ ์•”ํ˜ธํ™” ์„ค์ •์ด ๋“ค์–ด๊ฐ€๋„๋ก(์—†์œผ๋ฉด user ํ…Œ์ด๋ธ”์—์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋ณด์ž„)
if (userInfoUpdateReqDto.password() != null && !userInfoUpdateReqDto.password().isEmpty()) {
String newEncodedPassword = passwordEncoder.encode(userInfoUpdateReqDto.password());
user.setPassword(newEncodedPassword);
}

userRepository.save(user);
return UserInfoResDto.from(user);
}

private User getUserByEmail(String email) {
return EntityFinder.findByEmailOrThrow(userRepository.findByEmail(email)
, ErrorCode.USER_NOT_FOUND_EXCEPTION);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
package org.likelion.likelion_12th_team05.user.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;
import org.likelion.likelion_12th_team05.curation.domain.Curation;
import org.likelion.likelion_12th_team05.like.domain.Like;
import org.likelion.likelion_12th_team05.location.domain.Location;
import org.likelion.likelion_12th_team05.user.api.dto.request.UserInfoUpdateReqDto;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
@Id
Expand Down Expand Up @@ -49,4 +48,12 @@ private User(String name, String email, String password, String accessToken, Str
this.refreshToken = refreshToken;
this.role = role;
}

public void update(UserInfoUpdateReqDto userInfoUpdateReqDto) {
this.name = userInfoUpdateReqDto.name();
this.email = userInfoUpdateReqDto.email();
// ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ์€ password๊ฐ€ null์ด๋ผ ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•ด์ค˜์•ผํ•จ
if (userInfoUpdateReqDto.password() != null & !userInfoUpdateReqDto.email().isEmpty())
this.password = userInfoUpdateReqDto.password();
}
}

0 comments on commit 3ff9ed6

Please sign in to comment.