Skip to content

Commit

Permalink
Merge pull request #57 from IT-Cotato/develop
Browse files Browse the repository at this point in the history
Release: 0709 작업 내용 이전
  • Loading branch information
gikhoon authored Jul 9, 2024
2 parents 3564f87 + ff35c50 commit 1489dd5
Show file tree
Hide file tree
Showing 29 changed files with 505 additions and 172 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ dependencies {
//S3 관련 의존성 부여
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

implementation group: 'org.redisson', name: 'redisson-spring-boot-starter', version: '3.32.0'

implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'javax.xml.bind:jaxb-api:2.3.0'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package org.cotato.csquiz.api.member.controller;

import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cotato.csquiz.api.admin.dto.MemberInfoResponse;
import org.cotato.csquiz.api.member.dto.MemberMyPageInfoResponse;
import org.cotato.csquiz.api.member.dto.UpdatePasswordRequest;
import org.cotato.csquiz.api.member.dto.UpdatePhoneNumberRequest;
import org.cotato.csquiz.common.config.jwt.JwtTokenProvider;
import org.cotato.csquiz.domain.auth.service.MemberService;
import org.springframework.context.annotation.Description;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
Expand Down Expand Up @@ -42,6 +45,16 @@ public ResponseEntity<Void> updatePassword(@RequestHeader("Authorization") Strin
return ResponseEntity.noContent().build();
}

@Operation(summary = "멤버 전화번호 수정", description = "멤버 전화번호 수정하기")
@PatchMapping("/phone-number")
public ResponseEntity<Void> updatePhoneNumber(
@RequestHeader("Authorization") String authorizationHeader,
@RequestBody @Valid UpdatePhoneNumberRequest request) {
String accessToken = jwtTokenProvider.getBearer(authorizationHeader);
memberService.updatePhoneNumber(accessToken,request.phoneNumber());
return ResponseEntity.noContent().build();
}

@GetMapping("/{memberId}/mypage")
public ResponseEntity<MemberMyPageInfoResponse> findMyPageInfo(@PathVariable("memberId") Long memberId) {
return ResponseEntity.ok().body(memberService.findMyPageInfo(memberId));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.cotato.csquiz.api.member.dto;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public record UpdatePhoneNumberRequest(
@NotNull(message = "전화번호를 입력해주세요.")
@Size(min = 11, max = 11, message = "'-'없이 11자리의 전화번호를 입력해주세요.")
String phoneNumber
) {
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
package org.cotato.csquiz.api.session.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cotato.csquiz.api.session.dto.AddSessionPhotoRequest;
import org.cotato.csquiz.api.session.dto.AddSessionPhotoResponse;
import org.cotato.csquiz.api.session.dto.AddSessionRequest;
import org.cotato.csquiz.api.session.dto.AddSessionResponse;
import org.cotato.csquiz.api.session.dto.CsEducationOnSessionNumberResponse;
import org.cotato.csquiz.api.session.dto.DeleteSessionPhotoRequest;
import org.cotato.csquiz.api.session.dto.SessionListResponse;
import org.cotato.csquiz.api.session.dto.UpdateSessionDescriptionRequest;
import org.cotato.csquiz.api.session.dto.UpdateSessionNumberRequest;
import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoOrderRequest;
import org.cotato.csquiz.api.session.dto.UpdateSessionPhotoRequest;
import org.cotato.csquiz.api.session.dto.UpdateSessionRequest;
import org.cotato.csquiz.domain.generation.service.SessionService;
import org.cotato.csquiz.common.error.exception.ImageException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PatchMapping;
Expand All @@ -33,20 +40,21 @@ public class SessionController {

private final SessionService sessionService;

@Operation(summary = "Session 리스트 정보 얻기", description = "Get Session Infos")
@GetMapping("")
public ResponseEntity<List<SessionListResponse>> findSessionsByGenerationId(@RequestParam Long generationId) {
return ResponseEntity.status(HttpStatus.OK).body(sessionService.findSessionsByGenerationId(generationId));
}

@Operation(summary = "Session 추가하기", description = "세션 추가하기")
@PostMapping(value = "/add", consumes = "multipart/form-data")
public ResponseEntity<AddSessionResponse> addSession(@ModelAttribute @Valid AddSessionRequest request)
throws ImageException {
return ResponseEntity.status(HttpStatus.CREATED).body(sessionService.addSession(request));
}

@PatchMapping(value = "/update", consumes = "multipart/form-data")
public ResponseEntity<Void> updateSession(@ModelAttribute @Valid UpdateSessionRequest request)
throws ImageException {
public ResponseEntity<Void> updateSession(@RequestBody @Valid UpdateSessionRequest request) {
sessionService.updateSession(request);
return ResponseEntity.noContent().build();
}
Expand All @@ -57,16 +65,24 @@ public ResponseEntity<Void> updateSessionNumber(@RequestBody @Valid UpdateSessio
return ResponseEntity.noContent().build();
}

@PatchMapping("/description")
public ResponseEntity<Void> updateSessionDescription(@RequestBody @Valid UpdateSessionDescriptionRequest request) {
sessionService.updateSessionDescription(request);
@Operation(summary = "Session 수정 - 사진 순서", description = "세션 사진 순서 바꾸기")
@PatchMapping("/photo/order")
public ResponseEntity<Void> updateSessionPhotoOrder(@RequestBody UpdateSessionPhotoOrderRequest request) {
sessionService.updateSessionPhotoOrder(request);
return ResponseEntity.noContent().build();
}

@PatchMapping(value = "/update/photo", consumes = "multipart/form-data")
public ResponseEntity<Void> updateSessionPhoto(@ModelAttribute @Valid UpdateSessionPhotoRequest request)
@Operation(summary = "Session 수정 - 사진 추가하기", description = "세션 수정 시 사진 추가하기, photoId 반환")
@PostMapping(value = "/photo", consumes = "multipart/form-data")
public ResponseEntity<AddSessionPhotoResponse> additionalSessionPhoto(@ModelAttribute @Valid AddSessionPhotoRequest request)
throws ImageException {
sessionService.updateSessionPhoto(request);
return ResponseEntity.status(HttpStatus.CREATED).body(sessionService.additionalSessionPhoto(request));
}

@Operation(summary = "Session 수정 - 사진 삭제하기", description = "사진 삭제하기")
@DeleteMapping(value = "/photo")
public ResponseEntity<Void> deleteSessionPhoto(@RequestBody DeleteSessionPhotoRequest request) {
sessionService.deleteSessionPhoto(request);
return ResponseEntity.noContent().build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.cotato.csquiz.api.session.dto;

import jakarta.validation.constraints.NotNull;
import org.springframework.web.multipart.MultipartFile;

public record AddSessionPhotoRequest(

@NotNull
Long sessionId,
@NotNull
MultipartFile photo
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.cotato.csquiz.api.session.dto;

import jakarta.validation.constraints.NotNull;
import org.cotato.csquiz.domain.generation.entity.SessionPhoto;
import org.springframework.web.multipart.MultipartFile;

public record AddSessionPhotoResponse(
Long photoId,
String photoUrl,
Integer order
) {
public static AddSessionPhotoResponse from(SessionPhoto sessionPhoto) {
return new AddSessionPhotoResponse(sessionPhoto.getId(),
sessionPhoto.getS3Info().getUrl(),
sessionPhoto.getOrder());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.cotato.csquiz.api.session.dto;

import java.util.List;
import org.cotato.csquiz.domain.generation.enums.CSEducation;
import org.cotato.csquiz.domain.generation.enums.DevTalk;
import org.cotato.csquiz.domain.generation.enums.ItIssue;
Expand All @@ -10,7 +11,7 @@
public record AddSessionRequest(
@NotNull
Long generationId,
MultipartFile sessionImage,
List<MultipartFile> photos,
@NotNull
String title,
@NotNull
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.cotato.csquiz.api.session.dto;

import jakarta.validation.constraints.NotNull;

public record DeleteSessionPhotoRequest(
@NotNull
Long photoId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.cotato.csquiz.api.session.dto;

import jakarta.validation.constraints.NotNull;
import java.util.List;
import org.cotato.csquiz.domain.generation.entity.SessionPhoto;

public record SessionListPhotoInfoResponse(
Long photoId,
String photoUrl,
Integer order
) {
public static SessionListPhotoInfoResponse from(SessionPhoto sessionPhoto) {
return new SessionListPhotoInfoResponse(sessionPhoto.getId(),
sessionPhoto.getS3Info().getUrl(),
sessionPhoto.getOrder());
}

public static List<SessionListPhotoInfoResponse> from(List<SessionPhoto> sessionPhotos) {
return sessionPhotos.stream()
.map(SessionListPhotoInfoResponse::from)
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package org.cotato.csquiz.api.session.dto;

import java.util.List;
import org.cotato.csquiz.domain.generation.embedded.SessionContents;
import org.cotato.csquiz.domain.generation.entity.Session;

public record SessionListResponse(
Long sessionId,
Integer sessionNumber,
String title,
String photoUrl,
List<SessionListPhotoInfoResponse> photoInfos,
String description,
Long generationId,
SessionContents sessionContents
Expand All @@ -17,7 +18,7 @@ public static SessionListResponse from(Session session) {
session.getId(),
session.getNumber(),
session.getTitle(),
(session.getPhotoS3Info() != null) ? session.getPhotoS3Info().getUrl() : null,
SessionListPhotoInfoResponse.from(session.getSessionPhotos()),
session.getDescription(),
session.getGeneration().getId(),
session.getSessionContents()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.cotato.csquiz.api.session.dto;

import jakarta.validation.constraints.NotNull;

public record UpdateSessionPhotoOrderInfoRequest(
@NotNull
Long photoId,
@NotNull
Integer order
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.cotato.csquiz.api.session.dto;

import java.util.List;

public record UpdateSessionPhotoOrderRequest(
Long sessionId,
List<UpdateSessionPhotoOrderInfoRequest> orderInfos
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
public record UpdateSessionPhotoRequest(
@NotNull
Long sessionId,
MultipartFile sessionImage
MultipartFile photo
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@
import org.cotato.csquiz.domain.generation.enums.ItIssue;
import org.cotato.csquiz.domain.generation.enums.Networking;
import jakarta.validation.constraints.NotNull;
import org.springframework.web.multipart.MultipartFile;

public record UpdateSessionRequest(
@NotNull
Long sessionId,
MultipartFile sessionImage,
@NotNull
Boolean isPhotoUpdated,
String title,
String description,
@NotNull
Expand All @@ -21,7 +17,6 @@ public record UpdateSessionRequest(
Networking networking,
@NotNull
CSEducation csEducation,

@NotNull
DevTalk devTalk
) {
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/org/cotato/csquiz/common/S3/S3Uploader.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package org.cotato.csquiz.common.S3;

import static org.cotato.csquiz.common.util.FileUtil.checkAllowedImageFileExtension;
import static org.cotato.csquiz.common.util.FileUtil.extractFileExtension;

import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import java.util.List;
import java.util.Objects;
import org.cotato.csquiz.common.entity.S3Info;
import org.cotato.csquiz.common.error.ErrorCode;
import org.cotato.csquiz.common.error.exception.ImageException;
Expand Down Expand Up @@ -67,7 +68,7 @@ private void removeNewFile(File targetFile) {
if (targetFile.delete()) {
log.info("삭제 완료");
} else {
log.info("삭제 에러");
log.error("삭제 에러");
}
}

Expand All @@ -78,7 +79,10 @@ private String putS3(File uploadFile, String fileName) {
}

private Optional<File> convert(MultipartFile file) throws ImageException {
File convertFile = new File(System.getProperty("user.dir") + "/" + UUID.randomUUID());
String fileExtension = extractFileExtension(file);
checkAllowedImageFileExtension(fileExtension);

File convertFile = new File(System.getProperty("user.dir") + "/" + UUID.randomUUID() + "." + fileExtension);
log.info("converted file name: {}", convertFile.getName());

try {
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/org/cotato/csquiz/common/error/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ public enum ErrorCode {
EDUCATION_STATUS_NOT_BEFORE(HttpStatus.BAD_REQUEST, "E-402", "이미 시작한 적이 있는 교육입니다."),
MEMBER_CANT_ACCESS(HttpStatus.BAD_REQUEST, "E-403", "해당 멤버의 ROLE로 접근할 수 없습니다"),

//세션 사진
SESSION_PHOTO_COUNT_MISMATCH(HttpStatus.BAD_REQUEST, "P-101", "저장된 사진 수와 요청 사진 수가 다릅니다."),
SESSION_ORDER_INVALID(HttpStatus.BAD_REQUEST, "P-102", "입력한 순서는 유효하지 않습니다."),

FILE_EXTENSION_FAULT(HttpStatus.BAD_REQUEST, "F-001", "해당 파일은 등록 할 수 없는 확장자명입니다."),


INVALID_ANSWER(HttpStatus.BAD_REQUEST, "Q-101", "객관식 문제는 숫자 형식의 값만 정답으로 추가할 수 있습니다."),
CONTENT_IS_NOT_ANSWER(HttpStatus.BAD_REQUEST, "Q-201", "추가되지 않은 정답을 추가할 수 없습니다."),
QUIZ_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "Q-301", "퀴즈 번호는 중복될 수 없습니다."),
Expand All @@ -69,6 +76,7 @@ public enum ErrorCode {
IMAGE_DELETE_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S-003", "s3 이미지 삭제처리를 실패했습니다"),
INTERNAL_SQL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "S-004", "SQL 관련 에러 발생"),
ENUM_NOT_RESOLVED(HttpStatus.BAD_REQUEST, "S-005", "입력한 Enum이 존재하지 않습니다."),
SCORER_LOCK_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "S-006", "득점자 락 획득 과정에서 에러 발생");
;

private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ public ResponseEntity<ErrorResponse> handleAppCustomException(AppException e, Ht
public ResponseEntity<ErrorResponse> handleImageException(ImageException e, HttpServletRequest request) {
log.error("이미지 처리 실패 예외 발생: {}", e.getErrorCode().getMessage());
log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI());
ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.IMAGE_PROCESSING_FAIL, request);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
ErrorResponse errorResponse = ErrorResponse.of(e.getErrorCode(), request);
return ResponseEntity.status(e.getErrorCode().getHttpStatus())
.body(errorResponse);
}

@Override
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/org/cotato/csquiz/common/util/FileUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.cotato.csquiz.common.util;

import java.util.Arrays;
import org.cotato.csquiz.common.error.ErrorCode;
import org.cotato.csquiz.common.error.exception.ImageException;
import org.springframework.web.multipart.MultipartFile;

public class FileUtil {

private static final String[] ALLOWED_IMAGE_FILE_EXTENSIONS = {"png", "jpg", "jpeg", "heif"};

public static String extractFileExtension(MultipartFile file) throws ImageException {
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || !originalFilename.contains(".")) {
throw new ImageException(ErrorCode.FILE_EXTENSION_FAULT);
}

return originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
}

public static void checkAllowedImageFileExtension(String fileExtension) throws ImageException {
if (!Arrays.asList(ALLOWED_IMAGE_FILE_EXTENSIONS).contains(fileExtension)) {
throw new ImageException(ErrorCode.FILE_EXTENSION_FAULT);
}
}
}
Loading

0 comments on commit 1489dd5

Please sign in to comment.