diff --git a/build.gradle b/build.gradle index f0931d7..06de7d5 100644 --- a/build.gradle +++ b/build.gradle @@ -23,6 +23,12 @@ repositories { mavenCentral() } +dependencyManagement { + imports { + mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.4.0" + } +} + dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' @@ -52,8 +58,10 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-redis' //S3의존성 추가 - implementation("software.amazon.awssdk:bom:2.21.0") - implementation("software.amazon.awssdk:s3:2.21.0") +// implementation("software.amazon.awssdk:bom:2.21.0") +// implementation("software.amazon.awssdk:s3:2.21.0") + + implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3' // Feign 추가 implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.3.0' @@ -81,6 +89,10 @@ dependencies { implementation 'org.ahocorasick:ahocorasick:0.6.3' } + + + + // Querydsl 빌드 옵션 설정 def generated = 'src/main/generated' diff --git a/src/main/java/org/sopt/certi_server/domain/acquisition/dto/response/GetAcquisitionResponse.java b/src/main/java/org/sopt/certi_server/domain/acquisition/dto/response/GetAcquisitionResponse.java index c3096e1..4868464 100644 --- a/src/main/java/org/sopt/certi_server/domain/acquisition/dto/response/GetAcquisitionResponse.java +++ b/src/main/java/org/sopt/certi_server/domain/acquisition/dto/response/GetAcquisitionResponse.java @@ -13,6 +13,7 @@ public record GetAcquisitionResponse( Long acquisitionId, String cardFrontImageUrl, + String certificationType, int index, String name, List tags, @@ -25,6 +26,7 @@ public static GetAcquisitionResponse from(Acquisition acquisition) { return GetAcquisitionResponse.builder() .acquisitionId(acquisition.getId()) .cardFrontImageUrl(acquisition.getCardType().getCardFrontImageUrl()) + .certificationType(acquisition.getCertification().getCertificationType().getKoreanName()) .index(acquisition.getCardType().getIndex()) .name(acquisition.getCertification().getName()) .acquisitionDate(acquisition.getAcquisitionDate()) diff --git a/src/main/java/org/sopt/certi_server/domain/activity/controller/ActivityController.java b/src/main/java/org/sopt/certi_server/domain/activity/controller/ActivityController.java index 75eb415..107891e 100644 --- a/src/main/java/org/sopt/certi_server/domain/activity/controller/ActivityController.java +++ b/src/main/java/org/sopt/certi_server/domain/activity/controller/ActivityController.java @@ -26,7 +26,7 @@ public class ActivityController { @PostMapping @Operation(summary = "대내외활동 추가 API", description = "대내외 활동을 추가합니다") - public ResponseEntity createActivity( + public ResponseEntity> createActivity( @AuthenticationPrincipal Long userId, @Valid @RequestBody CreateActivityRequest request) { activityService.createActivity(userId, request); @@ -46,7 +46,7 @@ public ResponseEntity> getAllActivities @DeleteMapping("/{activity-id}") @Operation(summary = "대내외 활동 삭제 API", description = "대내외 활동을 삭제합니다") - public ResponseEntity deleteActivity( + public ResponseEntity> deleteActivity( @AuthenticationPrincipal Long userId, @Parameter(description = "activity Id", example = "1") @PathVariable(name = "activity-id") Long activityId diff --git a/src/main/java/org/sopt/certi_server/domain/activity/dto/request/CreateActivityRequest.java b/src/main/java/org/sopt/certi_server/domain/activity/dto/request/CreateActivityRequest.java index f063342..dd8185c 100644 --- a/src/main/java/org/sopt/certi_server/domain/activity/dto/request/CreateActivityRequest.java +++ b/src/main/java/org/sopt/certi_server/domain/activity/dto/request/CreateActivityRequest.java @@ -2,15 +2,20 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import java.time.LocalDate; public record CreateActivityRequest( + + @Schema(description = "활동 시작일", example = "2024.05.24", type = "string") @NotNull(message = "활동 시작일은 필수 입력값입니다.") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") LocalDate startAt, + + @Schema(description = "활동 종료일", example = "2024.05.28", type = "string") @NotNull(message = "활동 종료일은 필수 입력값입니다") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") LocalDate endAt, diff --git a/src/main/java/org/sopt/certi_server/domain/user/controller/AuthController.java b/src/main/java/org/sopt/certi_server/domain/user/controller/AuthController.java index 3046e81..c15871f 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/controller/AuthController.java +++ b/src/main/java/org/sopt/certi_server/domain/user/controller/AuthController.java @@ -69,7 +69,7 @@ public ResponseEntity> processSignIn(@Valid @Reque @Operation(summary = "회원 가입", description = "회원 가입을 진행합니다.") public ResponseEntity> processSignup( @RequestHeader("Authorization") @NotEmpty(message = "임시 토큰이 누락되었습니다.") String authorization, - @Valid @RequestBody SignupRequest request + @RequestBody SignupRequest request ) { return ResponseEntity.ok(SuccessResponse.of(SuccessCode.SUCCESS_CREATE, authService.register(authorization, request))); } diff --git a/src/main/java/org/sopt/certi_server/domain/user/controller/UserController.java b/src/main/java/org/sopt/certi_server/domain/user/controller/UserController.java index ce03215..d32cb5b 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/controller/UserController.java +++ b/src/main/java/org/sopt/certi_server/domain/user/controller/UserController.java @@ -2,8 +2,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.Size; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.sopt.certi_server.domain.user.dto.request.*; @@ -61,7 +60,7 @@ public ResponseEntity> getPersonalI @Operation(summary = "개인정보 수정 API", description = "개인정보를 수정합니다.") public ResponseEntity> putPersonalInformation( @AuthenticationPrincipal Long userId, - @RequestBody UpdateUserRequest request + @Valid @RequestBody UpdateUserRequest request ){ userService.updateUserInformation(userId, request); return ResponseEntity.ok(SuccessResponse.of(SuccessCode.SUCCESS_UPDATE)); @@ -122,4 +121,30 @@ public ResponseEntity> getUserTrack( ){ return ResponseEntity.ok(SuccessResponse.of(SuccessCode.SUCCESS_FETCH, userService.getTrack(userId))); } + + @GetMapping(value = "/presigned-url") + @Operation(summary = "presigned URL 반환 API", description = "Presigned URL을 반환합니다. 해당 URL을 통해 이미지를 업로드 할 수 있습니다.") + public ResponseEntity> getPreSignedURL( + @AuthenticationPrincipal Long userId + ){ + return ResponseEntity.ok(SuccessResponse.of(SuccessCode.SUCCESS_FETCH, userService.getPreSignedURL(userId))); + } + + + @GetMapping(value = "/marketing-agreement") + @Operation(summary = "광고성 수신 정보 동의 조회 API", description = "광고성 수신 정보 동의 정보를 조회합니다.") + public ResponseEntity> getMarketingAgreeInformation( + @AuthenticationPrincipal Long userId + ){ + return ResponseEntity.ok(SuccessResponse.of(SuccessCode.SUCCESS_FETCH, userService.getMarketingAgree(userId))); + } + + @PatchMapping(value = "/marketing-agreement") + @Operation(summary = "광고성 수신 정보 동의 토글 API", description = "광고성 수신 정보 동의를 토글식으로 변경합니다.") + public ResponseEntity> patchMarketingAgree( + @AuthenticationPrincipal Long userId + ){ + userService.toggleMarketingAgree(userId); + return ResponseEntity.ok(SuccessResponse.of(SuccessCode.SUCCESS_UPDATE)); + } } diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/request/PatchUserProfileImageRequest.java b/src/main/java/org/sopt/certi_server/domain/user/dto/request/PatchUserProfileImageRequest.java new file mode 100644 index 0000000..6e801cd --- /dev/null +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/request/PatchUserProfileImageRequest.java @@ -0,0 +1,6 @@ +package org.sopt.certi_server.domain.user.dto.request; + +public record PatchUserProfileImageRequest( + String publicURL +) { +} diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/request/UpdateUserRequest.java b/src/main/java/org/sopt/certi_server/domain/user/dto/request/UpdateUserRequest.java index 317722a..c4350bb 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/dto/request/UpdateUserRequest.java +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/request/UpdateUserRequest.java @@ -1,6 +1,7 @@ package org.sopt.certi_server.domain.user.dto.request; import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotEmpty; @@ -18,9 +19,13 @@ public record UpdateUserRequest( @NotEmpty(message = "닉네임은 공백이 될 수 없습니다.") @NoProfanity String nickName, + + @Schema(description = "생년월일", example = "1998.05.24", type = "string") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") @Past(message = "생년월일은 과거 날짜여야 합니다.") - LocalDate birthDate + LocalDate birthDate, + + String publicURL ) { } diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetMyPageInfoResponse.java b/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetMyPageInfoResponse.java index 56c9579..3ca3d16 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetMyPageInfoResponse.java +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetMyPageInfoResponse.java @@ -8,6 +8,7 @@ @Builder public record GetMyPageInfoResponse( String nickname, + String profileImageURL, String email, GetJobResponse jobResponse, int upCount, @@ -19,6 +20,7 @@ public static GetMyPageInfoResponse from( ){ return GetMyPageInfoResponse.builder() .nickname(user.getNickname()) + .profileImageURL(user.getProfileImageUrl()) .email(user.getEmail()) .jobResponse(jobResponse) .upCount(upCount) diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetPreSignedURLResponse.java b/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetPreSignedURLResponse.java new file mode 100644 index 0000000..b6d1acd --- /dev/null +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetPreSignedURLResponse.java @@ -0,0 +1,17 @@ +package org.sopt.certi_server.domain.user.dto.response; + +public record GetPreSignedURLResponse( + String preSignedURL, + String publicURL +) { + public static GetPreSignedURLResponse of( + String preSignedURL, + String publicURL + ){ + return new GetPreSignedURLResponse( + preSignedURL, + publicURL + ); + } + +} diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetUserResponse.java b/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetUserResponse.java index bf556fd..bd6ad41 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetUserResponse.java +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/response/GetUserResponse.java @@ -4,19 +4,27 @@ import org.sopt.certi_server.domain.major.entity.MajorImpl; import org.sopt.certi_server.domain.user.entity.User; +import java.time.LocalDate; + @Builder public record GetUserResponse( String nickname, + String name, String university, String major, + String profileImage, + LocalDate birthDate, int percentage ) { public static GetUserResponse from(User user, MajorImpl majorImpl, int percentage) { return GetUserResponse.builder() .nickname(user.getNickname()) + .name(user.getName()) .university(user.getUniversity().getName()) .major(majorImpl.getName()) + .profileImage(user.getProfileImageUrl()) .percentage(percentage) + .birthDate(user.getBirthDate()) .build(); } } diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/response/MarketingResponse.java b/src/main/java/org/sopt/certi_server/domain/user/dto/response/MarketingResponse.java new file mode 100644 index 0000000..3f2c1ac --- /dev/null +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/response/MarketingResponse.java @@ -0,0 +1,9 @@ +package org.sopt.certi_server.domain.user.dto.response; + +public record MarketingResponse( + boolean isAdAgreed +) { + public static MarketingResponse of(boolean isAdAgreed){ + return new MarketingResponse(isAdAgreed); + }; +} diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/response/OAuthUserInformation.java b/src/main/java/org/sopt/certi_server/domain/user/dto/response/OAuthUserInformation.java index 541b134..b48ddf1 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/dto/response/OAuthUserInformation.java +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/response/OAuthUserInformation.java @@ -18,7 +18,7 @@ public static OAuthUserInformation from( information.id(), SocialType.KAKAO, information.kakaoAccount().email(), - information.kakaoAccount().profile().name(), + information.kakaoAccount().profile().nickname(), information.kakaoAccount().profile().profileImageUrl() ); } diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/response/PersonalInformationResponse.java b/src/main/java/org/sopt/certi_server/domain/user/dto/response/PersonalInformationResponse.java index 72cf237..7335814 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/dto/response/PersonalInformationResponse.java +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/response/PersonalInformationResponse.java @@ -10,7 +10,8 @@ public record PersonalInformationResponse( String nickName, String name, String email, - LocalDate birthDate + LocalDate birthDate, + String profileImageURL ) { public static PersonalInformationResponse from(User user){ @@ -19,6 +20,7 @@ public static PersonalInformationResponse from(User user){ .nickName(user.getNickname()) .email(user.getEmail()) .birthDate(user.getBirthDate()) + .profileImageURL(user.getProfileImageUrl()) .build(); } } diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/response/UserInformation.java b/src/main/java/org/sopt/certi_server/domain/user/dto/response/UserInformation.java index 322ae27..e3c86b4 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/dto/response/UserInformation.java +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/response/UserInformation.java @@ -13,7 +13,7 @@ public static UserInformation from( ) { return new UserInformation( information.kakaoAccount().email(), - information.kakaoAccount().profile().name(), + information.kakaoAccount().profile().nickname(), information.kakaoAccount().profile().profileImageUrl() ); } diff --git a/src/main/java/org/sopt/certi_server/domain/user/dto/response/kakao/KakaoUserInformationResponse.java b/src/main/java/org/sopt/certi_server/domain/user/dto/response/kakao/KakaoUserInformationResponse.java index ada4d37..e859d34 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/dto/response/kakao/KakaoUserInformationResponse.java +++ b/src/main/java/org/sopt/certi_server/domain/user/dto/response/kakao/KakaoUserInformationResponse.java @@ -18,7 +18,7 @@ public record KakaoAccount( @JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) public record KakaoProfile( - String name, + String nickname, String profileImageUrl ) { diff --git a/src/main/java/org/sopt/certi_server/domain/user/entity/User.java b/src/main/java/org/sopt/certi_server/domain/user/entity/User.java index 925509a..5e7c4cf 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/entity/User.java +++ b/src/main/java/org/sopt/certi_server/domain/user/entity/User.java @@ -61,6 +61,9 @@ public class User extends BaseTimeEntity { @Column(name = "birth_date") private LocalDate birthDate; + @Column(name = "marketing_agree") + private Boolean marketingAgree; + public User(String nickname, String email, String profileImageUrl) { this.nickname = nickname; @@ -70,7 +73,7 @@ public User(String nickname, String email, String profileImageUrl) { @Builder public User(Long id, University university, String track, String grade, MajorImpl major, String nickname, String name, String email, - String profileImageUrl, SocialType socialType, Long socialId) { + String profileImageUrl, SocialType socialType, Long socialId, Boolean marketingAgree) { this.id = id; this.university = university; this.track = TrackType.from(track); @@ -82,13 +85,15 @@ public User(Long id, University university, String track, String grade, MajorImp this.profileImageUrl = profileImageUrl; this.socialType = socialType; this.socialId = socialId; + this.marketingAgree = marketingAgree; } - public void changeUser(String name, String nickname, String email, LocalDate birthDate){ + public void changeUser(String name, String nickname, String email, LocalDate birthDate, String profileImageUrl){ this.name = name; this.nickname = nickname; this.email = email; this.birthDate = birthDate; + this.profileImageUrl = profileImageUrl; } public void changeUniversity(University university) { @@ -98,4 +103,12 @@ public void changeUniversity(University university) { public void changeMajor(MajorImpl mi) { this.major = mi; } + + public void updateMarketingAgree() { + this.marketingAgree = !this.marketingAgree; + } + + public void updateProfileImage(String publicKey) { + this.profileImageUrl = publicKey; + } } diff --git a/src/main/java/org/sopt/certi_server/domain/user/service/KakaoService.java b/src/main/java/org/sopt/certi_server/domain/user/service/KakaoService.java index 5bffad3..5e8f194 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/service/KakaoService.java +++ b/src/main/java/org/sopt/certi_server/domain/user/service/KakaoService.java @@ -54,7 +54,7 @@ public OAuthUserInformation getUserInfo(String code) { public OAuthUserInformation getUserInfoByAccessToken(String accessToken) { try { KakaoUserInformationResponse information = kakaoApiFeignClient.getInformation("Bearer " + accessToken); - log.info(information.kakaoAccount().profile().name()); + log.info(information.kakaoAccount().profile().nickname()); log.info(information.kakaoAccount().email()); return OAuthUserInformation.from(information); } catch (Exception e) { diff --git a/src/main/java/org/sopt/certi_server/domain/user/service/UserService.java b/src/main/java/org/sopt/certi_server/domain/user/service/UserService.java index 3ebe17c..49e5c3e 100644 --- a/src/main/java/org/sopt/certi_server/domain/user/service/UserService.java +++ b/src/main/java/org/sopt/certi_server/domain/user/service/UserService.java @@ -9,6 +9,7 @@ import org.sopt.certi_server.domain.job.repository.JobRepository; import org.sopt.certi_server.domain.major.entity.MajorImpl; import org.sopt.certi_server.domain.major.repository.MajorImplRepository; +import org.sopt.certi_server.domain.user.dto.request.PatchUserProfileImageRequest; import org.sopt.certi_server.domain.user.dto.request.UpdateUserRequest; import org.sopt.certi_server.domain.user.dto.response.*; import org.sopt.certi_server.domain.user.entity.University; @@ -22,12 +23,14 @@ import org.sopt.certi_server.global.error.code.ErrorCode; import org.sopt.certi_server.global.error.exception.InvalidNicknameException; import org.sopt.certi_server.global.error.exception.NotFoundException; +import org.sopt.certi_server.global.s3.S3Service; import org.sopt.certi_server.global.valid.ProfanityFilter; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Objects; +import java.util.UUID; @Service @RequiredArgsConstructor @@ -35,6 +38,8 @@ @Slf4j public class UserService { + + private final S3Service s3Service; private final UserRepository userRepository; private final MajorImplRepository majorImplRepository; private final UserJobRepository userJobRepository; @@ -147,7 +152,8 @@ public void updateUserInformation(final Long userId, final UpdateUserRequest req request.name(), request.nickName(), request.email(), - request.birthDate() + request.birthDate(), + request.publicURL() ); } @@ -161,7 +167,7 @@ public void validateNickname(final Long userId, String nickname) { validateKeyword(nickname); } - public void validateNickname(String nickname) { + public void validateNickname(final String nickname) { if(userRepository.existsByNickname(nickname)) { throw new InvalidNicknameException(ErrorCode.NICKNAME_DUPLICATE); @@ -208,9 +214,35 @@ public void changeMajor(final Long userId, final String majorName) { user.changeMajor(mi); } - public GetTrackResponse getTrack(Long userId) { + public GetTrackResponse getTrack(final Long userId) { User user = getUser(userId); return GetTrackResponse.of(user.getTrack()); } + public MarketingResponse getMarketingAgree(final Long userId){ + User user = getUser(userId); + + return MarketingResponse.of(user.getMarketingAgree()); + } + + @Transactional + public void toggleMarketingAgree(final Long userId) { + User user = getUser(userId); + + user.updateMarketingAgree(); + } + + public GetPreSignedURLResponse getPreSignedURL(final Long userId) { + String key = "profiles/user-" + userId + "/" + UUID.randomUUID(); + String publicKey = s3Service.getPublicKey(key); + String preSignedURL = s3Service.getPreSignedUrlForUpload(key); + + return GetPreSignedURLResponse.of(preSignedURL, publicKey); + } + + @Transactional + public void updateUserProfileImage(final Long userId, final PatchUserProfileImageRequest request) { + User user = getUser(userId); + user.updateProfileImage(request.publicURL()); + } } diff --git a/src/main/java/org/sopt/certi_server/domain/userprecertification/controller/UserPreCertificationController.java b/src/main/java/org/sopt/certi_server/domain/userprecertification/controller/UserPreCertificationController.java index 880d8bd..e236929 100644 --- a/src/main/java/org/sopt/certi_server/domain/userprecertification/controller/UserPreCertificationController.java +++ b/src/main/java/org/sopt/certi_server/domain/userprecertification/controller/UserPreCertificationController.java @@ -36,7 +36,6 @@ public ResponseEntity> getPr @Operation(summary = "취득예정 자격증 추가 API", description = "취득예정 자격증을 추가합니다") public ResponseEntity> addPreCertification( @AuthenticationPrincipal Long userId, - @Parameter(description = "certification Id", example = "1") @RequestBody CreateUserPreCertificationRequest request ) { boolean isPreCertificated = userPreCertificationService.createNewPreCertification(userId, request); diff --git a/src/main/java/org/sopt/certi_server/domain/userprecertification/dto/response/PreCertificationSimple.java b/src/main/java/org/sopt/certi_server/domain/userprecertification/dto/response/PreCertificationSimple.java index 9fe31cc..c4207cf 100644 --- a/src/main/java/org/sopt/certi_server/domain/userprecertification/dto/response/PreCertificationSimple.java +++ b/src/main/java/org/sopt/certi_server/domain/userprecertification/dto/response/PreCertificationSimple.java @@ -9,6 +9,8 @@ public record PreCertificationSimple( Long certificationId, String certificationName, + String certificationType, + String description, String averagePeriod, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") LocalDate nearestTestDate, String agencyName, @@ -22,6 +24,8 @@ public static PreCertificationSimple from(UserPreCertification upc) { return new PreCertificationSimple( upc.getCertification().getId(), upc.getCertification().getName(), + upc.getCertification().getCertificationType().getKoreanName(), + upc.getCertification().getDescription(), upc.getCertification().getAveragePeriod(), upc.getCertification().getNearestTestDate(), upc.getCertification().getAgency().getName(), diff --git a/src/main/java/org/sopt/certi_server/global/s3/S3Service.java b/src/main/java/org/sopt/certi_server/global/s3/S3Service.java new file mode 100644 index 0000000..d0df2d4 --- /dev/null +++ b/src/main/java/org/sopt/certi_server/global/s3/S3Service.java @@ -0,0 +1,42 @@ +package org.sopt.certi_server.global.s3; + +import io.awspring.cloud.s3.S3Template; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.net.URL; +import java.time.Duration; + +@Service +@RequiredArgsConstructor +public class S3Service { + private final S3Template s3Template; + + @Value("${spring.cloud.aws.s3.bucket}") + private String bucketName; + + /** + * S3에서 파일을 업로드하기 위한 Presigned URL 생성 + * @param key 파일 경로 및 이름 (예: "images/profile.png") + * @return 생성된 URL + */ + public String getPreSignedUrlForUpload(String key) { + // 10분 동안 유효한 업로드용 URL 생성 + URL preSignedUrl = s3Template.createSignedPutURL(bucketName, key, Duration.ofMinutes(10)); + return preSignedUrl.toString(); + } + + public String getPublicKey(String key){ + return String.format("https://%s.s3.ap-northeast-2.amazonaws.com/%s", bucketName, key); + } + + /** + * S3에 있는 파일을 조회하기 위한 Presigned URL 생성 + */ + public String getPreSignedUrlForDownload(String key) { + // 10분 동안 유효한 조회용 URL 생성 + URL preSignedUrl = s3Template.createSignedGetURL(bucketName, key, Duration.ofMinutes(10)); + return preSignedUrl.toString(); + } +}