Skip to content

Commit

Permalink
Merge branch 'develop' into feature/57
Browse files Browse the repository at this point in the history
  • Loading branch information
jhsseonn authored Mar 16, 2024
2 parents 8c5d4f6 + c68721f commit ee05ce7
Show file tree
Hide file tree
Showing 100 changed files with 3,663 additions and 409 deletions.
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ dependencies {
// thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

// s3
implementation platform('software.amazon.awssdk:bom:2.20.56')
implementation 'software.amazon.awssdk:s3'
implementation "org.testcontainers:localstack:1.19.6"

// monitoring
implementation 'org.springframework.boot:spring-boot-starter-actuator'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
Expand Down
15 changes: 4 additions & 11 deletions src/docs/asciidoc/authentication.adoc
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
=== 로그인
==== 요청
include::{snippets}/authentication-controller-test/oauth_access_token을_통해_로그인시_첫_로그인이라면_회원가입_여부를_참으로_반환한다/http-request.adoc[]
include::{snippets}/authentication-controller-test/oauth_access_token을_통해_로그인시_첫_로그인이라면_회원가입_여부를_참으로_반환한다/request-headers.adoc[]
include::{snippets}/authentication-controller-test/oauth_access_token을_통해_로그인시_첫_로그인이라면_회원가입_여부를_참으로_반환한다/path-parameters.adoc[]
include::{snippets}/authentication-controller-test/oauth_access_token을_통해_로그인시_첫_로그인이라면_회원가입_여부를_참으로_반환한다/request-fields.adoc[]
operation::authentication-controller-test/oauth_access_token을_통해_로그인시_첫_로그인이라면_회원가입_여부를_참으로_반환한다[snippets='http-request,request-headers,path-parameters,request-fields']
==== 응답
include::{snippets}/authentication-controller-test/oauth_access_token을_통해_로그인시_첫_로그인이라면_회원가입_여부를_참으로_반환한다/http-response.adoc[]
include::{snippets}/authentication-controller-test/oauth_access_token을_통해_로그인시_첫_로그인이라면_회원가입_여부를_참으로_반환한다/response-fields.adoc[]
operation::authentication-controller-test/oauth_access_token을_통해_로그인시_첫_로그인이라면_회원가입_여부를_참으로_반환한다[snippets='http-response,response-fields']

=== Access Token 재발급
==== 요청
include::{snippets}/authentication-controller-test/refresh_token을_통해_access_token을_재발행한다/http-request.adoc[]
include::{snippets}/authentication-controller-test/refresh_token을_통해_access_token을_재발행한다/request-headers.adoc[]
include::{snippets}/authentication-controller-test/refresh_token을_통해_access_token을_재발행한다/request-fields.adoc[]
operation::authentication-controller-test/refresh_token을_통해_access_token을_재발행한다[snippets='http-request,request-headers,request-fields']
==== 응답
include::{snippets}/authentication-controller-test/refresh_token을_통해_access_token을_재발행한다/http-response.adoc[]
include::{snippets}/authentication-controller-test/refresh_token을_통해_access_token을_재발행한다/response-fields.adoc[]
operation::authentication-controller-test/refresh_token을_통해_access_token을_재발행한다[snippets='http-response,response-fields']
2 changes: 2 additions & 0 deletions src/docs/asciidoc/docs.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ include::stamp.adoc[]
== 콕 찌르기
include::poke.adoc[]

== 신고
include::report.adoc[]
6 changes: 2 additions & 4 deletions src/docs/asciidoc/notification.adoc
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
=== 알림 목록 조회
==== 요청
include::{snippets}/notification-controller-test/사용자의_알림_목록을_조회한다/http-request.adoc[]
include::{snippets}/notification-controller-test/사용자의_알림_목록을_조회한다/request-headers.adoc[]
operation::notification-controller-test/사용자의_알림_목록을_조회한다[snippets='http-request,request-headers']
==== 응답
include::{snippets}/notification-controller-test/사용자의_알림_목록을_조회한다/http-response.adoc[]
include::{snippets}/notification-controller-test/사용자의_알림_목록을_조회한다/response-fields.adoc[]
operation::notification-controller-test/사용자의_알림_목록을_조회한다[snippets='http-response,response-fields']
17 changes: 17 additions & 0 deletions src/docs/asciidoc/report.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
=== 사용자 신고
==== 요청
operation::report-controller-test/사용자를_신고한다[snippets='http-request,request-headers,path-parameters,request-fields']
==== 응답
operation::report-controller-test/사용자를_신고한다[snippets='http-response']

=== 골 신고
==== 요청
operation::report-controller-test/골을_신고한다[snippets='http-request,request-headers,path-parameters,request-fields']
==== 응답
operation::report-controller-test/골을_신고한다[snippets='http-response']

=== 스탬프 신고
==== 요청
operation::report-controller-test/스탬프를_신고한다[snippets='http-request,request-headers,path-parameters,request-fields']
==== 응답
operation::report-controller-test/스탬프를_신고한다[snippets='http-response']
6 changes: 2 additions & 4 deletions src/docs/asciidoc/themecolor.adoc
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
=== 전체 테마 색상 목록 조회
==== 요청
include::{snippets}/theme-color-controller-test/전체_테마_색상_목록을_조회한다/http-request.adoc[]
include::{snippets}/theme-color-controller-test/전체_테마_색상_목록을_조회한다/request-headers.adoc[]
operation::theme-color-controller-test/전체_테마_색상_목록을_조회한다[snippets='http-request,request-headers']
==== 응답
include::{snippets}/theme-color-controller-test/전체_테마_색상_목록을_조회한다/http-response.adoc[]
include::{snippets}/theme-color-controller-test/전체_테마_색상_목록을_조회한다/response-fields.adoc[]
operation::theme-color-controller-test/전체_테마_색상_목록을_조회한다[snippets='http-response,response-fields']
21 changes: 7 additions & 14 deletions src/docs/asciidoc/user.adoc
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
=== 사용자 정보 조회
==== 요청
include::{snippets}/user-controller-test/사용자_정보를_조회한다/http-request.adoc[]
include::{snippets}/user-controller-test/사용자_정보를_조회한다/request-headers.adoc[]
operation::user-controller-test/사용자_정보를_조회한다[snippets='http-request,request-headers']
==== 응답
include::{snippets}/user-controller-test/사용자_정보를_조회한다/http-response.adoc[]
include::{snippets}/user-controller-test/사용자_정보를_조회한다/response-fields.adoc[]
operation::user-controller-test/사용자_정보를_조회한다[snippets='http-response']

=== 검색을 통한 사용자 정보 목록 조회
==== 요청
include::{snippets}/user-controller-test/검색한_키워드가_이름에_포한된_사용자_목록을_조회한다/http-request.adoc[]
include::{snippets}/user-controller-test/검색한_키워드가_이름에_포한된_사용자_목록을_조회한다/request-headers.adoc[]
include::{snippets}/user-controller-test/검색한_키워드가_이름에_포한된_사용자_목록을_조회한다/query-parameters.adoc[]
operation::user-controller-test/검색한_키워드가_이름에_포한된_사용자_목록을_조회한다[snippets='http-request,request-headers,query-parameters']
==== 응답
include::{snippets}/user-controller-test/검색한_키워드가_이름에_포한된_사용자_목록을_조회한다/http-response.adoc[]
include::{snippets}/user-controller-test/검색한_키워드가_이름에_포한된_사용자_목록을_조회한다/response-fields.adoc[]
operation::user-controller-test/검색한_키워드가_이름에_포한된_사용자_목록을_조회한다[snippets='http-response,response-fields']

=== 사용자 정보 수정
==== 요청
include::{snippets}/user-controller-test/사용자의_모든_정보를_수정한다/http-request.adoc[]
include::{snippets}/user-controller-test/사용자의_모든_정보를_수정한다/request-headers.adoc[]
include::{snippets}/user-controller-test/사용자의_모든_정보를_수정한다/request-fields.adoc[]
operation::user-controller-test/사용자의_모든_정보를_수정한다[snippets='http-request,request-headers,request-parts']

==== 응답
include::{snippets}/user-controller-test/사용자의_모든_정보를_수정한다/http-response.adoc[]
include::{snippets}/user-controller-test/사용자의_모든_정보를_수정한다/response-fields.adoc[]
operation::user-controller-test/사용자의_모든_정보를_수정한다[snippets='http-response,response-fields']
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
public class FCMConfiguration {

@Value("${fcm.key.path}")
private String FCM_PRIVATE_KEY_PATH;
private String fcmPrivateKeyPath;

@Value("${fcm.key.scope}")
private String fireBaseScope;
Expand Down Expand Up @@ -53,7 +53,7 @@ private FirebaseOptions createFirebaseOptions() throws IOException {
}

private GoogleCredentials createGoogleCredentials() throws IOException {
final Resource resource = new ClassPathResource(FCM_PRIVATE_KEY_PATH);
final Resource resource = new ClassPathResource(fcmPrivateKeyPath);
final List<String> scopes = List.of(fireBaseScope);

return GoogleCredentials.fromStream(resource.getInputStream())
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/com/backend/blooming/exception/ExceptionMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,25 @@ public enum ExceptionMessage {
CREATE_STAMP_FORBIDDEN("스탬프를 추가할 권한이 없습니다."),
READ_STAMP_FORBIDDEN("스탬프를 조회할 권한이 없습니다."),
INVALID_STAMP_MESSAGE("스탬프 인증 메시지는 비어있거나 50자 초과일 수 없습니다."),
NOT_FOUND_STAMP("스탬프를 찾을 수 없습니다."),

// 신고
NULL_OR_EMPTY_CONTENT("신고 메시지는 비어있을 수 없습니다."),
NOT_ALLOWED_REPORT_OWN_USER("자신을 신고할 수 없습니다."),
ALREADY_REPORT_USER("이미 신고한 사용자입니다."),
ALREADY_REPORT_GOAL("이미 신고한 골입니다."),
NOT_ALLOWED_REPORT_OWN_GOAL("자신이 관리자인 골은 신고할 수 없습니다."),
GOAL_REPORT_FORBIDDEN("해당 골을 신고할 권한이 없습니다."),
ALREADY_REPORT_STAMP("이미 신고한 스탬프입니다."),
NOT_ALLOWED_REPORT_OWN_STAMP("자신의 스탬프는 신고할 수 없습니다."),
STAMP_REPORT_FORBIDDEN("해당 스탬프를 신고할 권한이 없습니다."),

// 이미지
EMPTY_IMAGE_FILE("저장할 이미지 파일이 없습니다."),
EMPTY_IMAGE_PATH("이미지 저장 경로가 비어있습니다."),
UPLOAD_FILE_CONTROL("이미지 업로드 시 파일 처리에서 문제가 발생했습니다."),
UPLOAD_SDK("이미지 업로드 시 sdk에서 문제가 발생했습니다."),
NOT_SUPPORTED_MEDIA_TYPE("지원하지 않는 이미지 확장자입니다."),

// 관리자 페이지
INVALID_FRIEND_STATUS("잘못된 친구 상태입니다.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
import com.backend.blooming.goal.application.exception.NotFoundGoalException;
import com.backend.blooming.goal.application.exception.ReadGoalForbiddenException;
import com.backend.blooming.goal.application.exception.UpdateGoalForbiddenException;
import com.backend.blooming.image.infrastructure.exception.UploadImageException;
import com.backend.blooming.notification.application.exception.NotFoundGoalManagerException;
import com.backend.blooming.report.application.exception.InvalidGoalReportException;
import com.backend.blooming.report.application.exception.InvalidStampReportException;
import com.backend.blooming.report.application.exception.InvalidUserReportException;
import com.backend.blooming.report.application.exception.ReportForbiddenException;
import com.backend.blooming.stamp.application.exception.CreateStampForbiddenException;
import com.backend.blooming.stamp.application.exception.ReadStampForbiddenException;
import com.backend.blooming.stamp.domain.exception.InvalidStampException;
Expand Down Expand Up @@ -288,6 +293,71 @@ public ResponseEntity<ExceptionResponse> handleReadStampForbiddenException(
.body(new ExceptionResponse(exception.getMessage()));
}

@ExceptionHandler(InvalidUserReportException.class)
public ResponseEntity<ExceptionResponse> handleInvalidUserReportException(
final InvalidUserReportException exception, final HttpServletRequest request
) {
logWarn(exception, request);

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ExceptionResponse(exception.getMessage()));
}

@ExceptionHandler(InvalidGoalReportException.class)
public ResponseEntity<ExceptionResponse> handleInvalidGoalReportException(
final InvalidGoalReportException exception, final HttpServletRequest request
) {
logWarn(exception, request);

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ExceptionResponse(exception.getMessage()));
}

@ExceptionHandler(InvalidStampReportException.class)
public ResponseEntity<ExceptionResponse> handleInvalidStampReportException(
final InvalidStampReportException exception, final HttpServletRequest request
) {
logWarn(exception, request);

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ExceptionResponse(exception.getMessage()));
}

@ExceptionHandler(ReportForbiddenException.class)
public ResponseEntity<ExceptionResponse> handleReportForbiddenException(
final ReportForbiddenException exception, final HttpServletRequest request
) {
logWarn(exception, request);

return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(new ExceptionResponse(exception.getMessage()));
}

@ExceptionHandler({
UploadImageException.EmptyFileException.class,
UploadImageException.EmptyPathException.class,
UploadImageException.NotSupportedMediaTypeException.class,
UploadImageException.FileControlException.class
})
public ResponseEntity<ExceptionResponse> handleUploadImageBadRequestException(
final UploadImageException exception, final HttpServletRequest request
) {
logWarn(exception, request);

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ExceptionResponse(exception.getMessage()));
}

@ExceptionHandler(UploadImageException.SdkException.class)
public ResponseEntity<ExceptionResponse> handleUploadImageServerException(
final UploadImageException exception, final HttpServletRequest request
) {
logWarn(exception, request);

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ExceptionResponse(exception.getMessage()));
}

private void logError(final Exception exception, final HttpServletRequest request) {
setMDC(request);

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/backend/blooming/goal/domain/Goal.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ public boolean isTeam(final User user) {
return teams.isTeam(user);
}

public boolean isManager(final Long userId) {
return managerId.equals(userId);
}

public List<GoalTeam> getTeams() {
return teams.getGoalTeams();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.backend.blooming.image.application;

import com.backend.blooming.image.application.util.ImageStoragePath;
import org.springframework.web.multipart.MultipartFile;
import org.testcontainers.shaded.com.google.common.net.MediaType;

import java.util.List;

public interface ImageStorageManager {

List<MediaType> SUPPORTED_MEDIA_TYPE = List.of(MediaType.PNG, MediaType.JPEG, MediaType.parse("image/jpg"));
String EXTENSION_DOT = ".";

String upload(final MultipartFile multipartFile, final ImageStoragePath path);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.backend.blooming.image.application.util;


import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum ImageStoragePath {

PROFILE("profile/");

private final String path;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.backend.blooming.image.configuration;

import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.utility.DockerImageName;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;

import static org.testcontainers.containers.localstack.LocalStackContainer.Service;

@Profile("test | local")
@Configuration
public class LocalS3Configuration {

private static final DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:0.11.3");

@Value("${cloud.aws.s3.bucket}")
private String bucket;

@Bean(initMethod = "start", destroyMethod = "stop")
public LocalStackContainer localStackContainer() {
return new LocalStackContainer(LOCALSTACK_IMAGE).withServices(Service.S3);
}

@Bean
public S3Client s3Client(final LocalStackContainer localStack) {
final S3Client s3Client = S3Client.builder()
.endpointOverride(localStack.getEndpoint())
.credentialsProvider(getAwsCredentialsProvider(localStack))
.region(Region.of(localStack.getRegion()))
.build();
final CreateBucketRequest bucketRequest = CreateBucketRequest.builder()
.bucket(bucket)
.build();
s3Client.createBucket(bucketRequest);

return s3Client;
}

@NotNull
private static StaticCredentialsProvider getAwsCredentialsProvider(final LocalStackContainer localStack) {
return StaticCredentialsProvider.create(
AwsBasicCredentials.create(localStack.getAccessKey(), localStack.getSecretKey())
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.backend.blooming.image.configuration;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

@Profile("dev | prod")
@Configuration
public class S3Configuration {

@Value("${cloud.aws.credentials.access-key}")
private String accessKey;

@Value("${cloud.aws.credentials.secret-key}")
private String secretKey;

@Value("${cloud.aws.s3.region}")
private String region;

@Bean
public S3Client amazonS3() {
final AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);

return S3Client.builder()
.region(Region.of(region))
.credentialsProvider(StaticCredentialsProvider.create(credentials))
.build();
}
}
Loading

0 comments on commit ee05ce7

Please sign in to comment.