Skip to content

Commit

Permalink
Merge branch 'dev' into feat/post-search-tag
Browse files Browse the repository at this point in the history
  • Loading branch information
jschoi-96 authored Mar 21, 2024
2 parents 64e0bd5 + 29ddea8 commit 9a0b937
Show file tree
Hide file tree
Showing 22 changed files with 215 additions and 71 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package balancetalk.global.exception;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class ConstraintViolationHandler {

@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Object> handleConstraintViolationException(ConstraintViolationException e) {
Map<Object, Object> errors = new HashMap<>();
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
String errorMessage = violations.stream()
.map(violation -> violation.getMessage())
.collect(Collectors.joining(", "));
errors.put("message" , errorMessage);
log.info("errorMessage={}", errorMessage);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package balancetalk.global.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;


@Slf4j
@RestControllerAdvice
public class MethodArgumentException {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> handleNoticeTitleSizeExceededExceptions(MethodArgumentNotValidException e) {
Map<Object, Object> errors = new HashMap<>();
FieldError fieldError = e.getBindingResult().getFieldError();
String errorMessage = fieldError.getDefaultMessage();
errors.put("message" , errorMessage);
log.info("errorMessage={}", errorMessage);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
Expand All @@ -11,7 +13,9 @@
@NoArgsConstructor
public class EmailRequest {

@Email
@NotNull
@Size(max = 30)
@Email(regexp = "^[a-zA-Z0-9._%+-]{1,20}@[a-zA-Z0-9.-]{1,10}\\.[a-zA-Z]{2,}$")
@Schema(description = "인증 번호를 받을 이메일 주소", example = "[email protected]")
private String email;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
Expand All @@ -11,7 +13,9 @@
@NoArgsConstructor
public class EmailVerification {

@Email
@NotNull
@Size(max = 30)
@Email(regexp = "^[a-zA-Z0-9._%+-]{1,20}@[a-zA-Z0-9.-]{1,10}\\.[a-zA-Z]{2,}$")
@Schema(description = "인증 번호를 검증할 이메일 주소", example = "[email protected]")
private String email;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@

@RestController
@RequiredArgsConstructor
@Tag(name = "bookmark", description = "게시글 북마크 API")
@RequestMapping("/bookmark")
@RequestMapping("/bookmarks")
@Tag(name = "bookmark", description = "게시글 북마크 API")
public class BookmarkController {

private final BookmarkService bookmarkService;

@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/posts/{postId}")
@PostMapping("/{postId}")
@Operation(summary = "북마크 추가", description = "post-id에 해당하는 게시글을 북마크에 추가한다.")
public String createBookmark(@PathVariable Long postId) {
bookmarkService.createBookmark(postId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand All @@ -24,7 +25,7 @@ public class CommentController {
@ResponseStatus(HttpStatus.CREATED)
@PostMapping
@Operation(summary = "댓글 작성", description = "post-id에 해당하는 게시글에 댓글을 작성한다.")
public String createComment(@PathVariable Long postId, @RequestBody CommentRequest request) {
public String createComment(@PathVariable Long postId, @Valid @RequestBody CommentRequest request) {
commentService.createComment(request, postId);
return "댓글이 정상적으로 작성되었습니다.";
}
Expand Down Expand Up @@ -64,7 +65,7 @@ public String deleteComment(@PathVariable Long commentId, @PathVariable Long pos
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/{commentId}/replies")
@Operation(summary = "답글 작성", description = "comment-id에 해당하는 댓글에 답글을 작성한다.")
public String createComment(@PathVariable Long postId, @PathVariable Long commentId, @RequestBody ReplyCreateRequest request) {
public String createComment(@PathVariable Long postId, @PathVariable Long commentId, @Valid @RequestBody ReplyCreateRequest request) {
commentService.createReply(postId, commentId, request);
return "답글이 정상적으로 작성되었습니다.";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetUrlRequest;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;

@Service
@RequiredArgsConstructor
public class FileUploadService {
public class FileService {

private static final String S3_URL = "https://balance-talk-static-files.s3.ap-northeast-2.amazonaws.com/";
private static final String UPLOAD_DIR = "balance-talk-images/balance-option/";

private final S3Client s3Client;
private final FileRepository fileRepository;
Expand All @@ -31,15 +35,15 @@ public class FileUploadService {

@Transactional
public FileResponse uploadImage(MultipartFile multipartFile) {
String uploadDir = "balance-talk-images/balance-option/";
String originalName = multipartFile.getOriginalFilename();
String storedName = String.format("%s_%s", UUID.randomUUID(), originalName);
long contentLength = multipartFile.getSize();
FileType fileType = convertMimeTypeToFileType(multipartFile.getContentType());

try (InputStream inputStream = multipartFile.getInputStream()) {
putObjectToS3(uploadDir + storedName, inputStream, contentLength);
File file = fileRepository.save(createFile(originalName, storedName, uploadDir, fileType, contentLength));
putObjectToS3(UPLOAD_DIR + storedName, inputStream, contentLength);
File file = fileRepository.save(
createFile(originalName, storedName, S3_URL + UPLOAD_DIR, fileType, contentLength));

return FileResponse.fromEntity(file);
} catch (IOException e) {
Expand Down Expand Up @@ -67,15 +71,24 @@ private void putObjectToS3(String key, InputStream inputStream, long contentLeng
s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, contentLength));
}

private File createFile(String originalName, String storedName, String uploadDir, FileType fileType,
private File createFile(String originalName, String storedName, String path, FileType fileType,
long contentLength) {

return File.builder()
.originalName(originalName)
.storedName(storedName)
.path(uploadDir)
.path(path)
.type(fileType)
.size(contentLength)
.build();
}

@Transactional(readOnly = true)
public String getUrl(String key) {
GetUrlRequest request = GetUrlRequest.builder()
.bucket(bucket)
.key(key)
.build();
return s3Client.utilities().getUrl(request).toString();
}
}
4 changes: 4 additions & 0 deletions src/main/java/balancetalk/module/file/domain/File.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ public class File {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "notice_id")
private Notice notice;

public String getUrl() {
return path + storedName;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package balancetalk.module.file.presentation;

import balancetalk.module.file.application.FileUploadService;
import balancetalk.module.file.application.FileService;
import balancetalk.module.file.dto.FileResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand All @@ -16,12 +16,12 @@
@Tag(name = "file", description = "파일 API")
public class FileController {

private final FileUploadService fileUploadService;
private final FileService fileService;

@ResponseStatus(HttpStatus.CREATED)
@PostMapping(value = "/image/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "파일 업로드", description = "파일을 업로드 한다.")
public FileResponse uploadImage(@RequestPart("file") MultipartFile file) {
return fileUploadService.uploadImage(file);
return fileService.uploadImage(file);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@
import balancetalk.module.member.domain.Member;
import balancetalk.module.member.domain.MemberRepository;
import balancetalk.module.member.dto.*;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/balancetalk/module/member/dto/JoinRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import balancetalk.module.member.domain.Member;
import balancetalk.module.member.domain.Role;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import jakarta.validation.constraints.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
Expand All @@ -18,9 +16,14 @@
@AllArgsConstructor
public class JoinRequest {

@NotBlank
@Size(min = 2, max = 10)
@Schema(description = "회원 닉네임", example = "닉네임")
private String nickname;

@NotNull
@Size(max = 30)
@Email(regexp = "^[a-zA-Z0-9._%+-]{1,20}@[a-zA-Z0-9.-]{1,10}\\.[a-zA-Z]{2,}$")
@Schema(description = "회원 이메일", example = "[email protected]")
private String email;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package balancetalk.module.member.presentation;


import balancetalk.module.member.application.MemberService;
import balancetalk.module.member.dto.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/members")
@Validated
@Tag(name = "member", description = "회원 API")
public class MemberController {

Expand Down Expand Up @@ -53,15 +59,19 @@ public List<MemberResponse> findAllMemberInfo() {
@ResponseStatus(HttpStatus.OK)
@PutMapping("/nickname")
@Operation(summary = "회원 닉네임 수정", description = "회원 닉네임을 수정한다.")
public String updateNickname(@Valid @RequestBody String newNickname, HttpServletRequest request) {
public String updateNickname(@Valid @NotBlank @RequestBody @Size(min = 2, max = 10)String newNickname, HttpServletRequest request) {
// TODO: RequestBody 빈 값일 때 에러체킹 x
memberService.updateNickname(newNickname, request);
return "회원 닉네임이 변경되었습니다.";
}

@ResponseStatus(HttpStatus.OK)
@PutMapping("/password")
@Operation(summary = "회원 비밀번호 수정", description = "회원 패스워드를 수정한다.")
public String updatePassword(@Valid @RequestBody String newPassword, HttpServletRequest request) {
public String updatePassword(@RequestBody @Size(min = 10, max = 20)
@Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d@$!%*#?&]{10,20}$")
String newPassword, HttpServletRequest request) {
// TODO: RequestBody 빈 값일 때 에러체킹 x
memberService.updatePassword(newPassword, request);
return "회원 비밀번호가 변경되었습니다.";
}
Expand All @@ -85,7 +95,8 @@ public String logout() {
@ResponseStatus(HttpStatus.OK)
@GetMapping("/duplicate")
@Operation(summary = "닉네임 중복 검증", description = "중복된 닉네임이 존재하는지 체크한다.")
public String verifyNickname(@RequestParam String nickname) {
public String verifyNickname(@RequestParam @NotBlank
@Size(min = 2, max = 10)String nickname) {
memberService.verifyNickname(nickname);
return "사용 가능한 닉네임 입니다.";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import balancetalk.module.member.domain.MemberRepository;
import balancetalk.module.member.domain.Role;
import balancetalk.module.post.domain.*;
import balancetalk.module.post.dto.BalanceOptionDto;
import balancetalk.module.post.dto.BalanceOptionRequest;
import balancetalk.module.post.dto.PostRequest;
import balancetalk.module.post.dto.PostResponse;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -41,6 +41,7 @@ public PostResponse save(final PostRequest request) {
if (redisService.getValues(writer.getEmail()) == null) {
throw new BalanceTalkException(FORBIDDEN_POST_CREATE);
}

List<File> images = getImages(request);
Post post = request.toEntity(writer, images);

Expand All @@ -56,11 +57,11 @@ public PostResponse save(final PostRequest request) {
return PostResponse.fromEntity(postRepository.save(post), false, false, false);
}

private List<File> getImages(PostRequest postRequestDto) {
List<BalanceOptionDto> balanceOptions = postRequestDto.getBalanceOptions();
private List<File> getImages(PostRequest postRequest) {
List<BalanceOptionRequest> balanceOptions = postRequest.getBalanceOptions();
return balanceOptions.stream()
.filter(optionDto -> optionDto.getStoredFileName() != null && !optionDto.getStoredFileName().isEmpty())
.map(optionDto -> fileRepository.findByStoredName(optionDto.getStoredFileName())
.filter(optionDto -> optionDto.getStoredImageName() != null && !optionDto.getStoredImageName().isEmpty())
.map(optionDto -> fileRepository.findByStoredName(optionDto.getStoredImageName())
.orElseThrow(() -> new BalanceTalkException(NOT_FOUND_FILE)))
.toList();
}
Expand Down
Loading

0 comments on commit 9a0b937

Please sign in to comment.