Skip to content

Commit 2bc30e2

Browse files
5uhwannwonjunYouKoSeonJeSeooooo24
authored
[release] v1.3.0 (#277)
Co-authored-by: Wonjun You <[email protected]> Co-authored-by: koseonje <[email protected]> Co-authored-by: koseonje <[email protected]> Co-authored-by: Seooooo24 <[email protected]>
1 parent fbb6da7 commit 2bc30e2

File tree

128 files changed

+5665
-225
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+5665
-225
lines changed

build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ dependencies {
5555
implementation 'io.sentry:sentry-logback:7.6.0'
5656
implementation 'com.fasterxml.jackson.core:jackson-core'
5757
implementation 'com.github.f4b6a3:uuid-creator:6.0.0'
58+
implementation 'software.amazon.awssdk:ses:2.24.0'
59+
implementation 'com.google.guava:guava:32.1.3-jre'
5860

5961
//security
6062
implementation 'org.springframework.boot:spring-boot-starter-security'

src/main/java/ddingdong/ddingdongBE/common/config/AmazonS3Config.java

+14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
import org.springframework.beans.factory.annotation.Value;
88
import org.springframework.context.annotation.Bean;
99
import org.springframework.context.annotation.Configuration;
10+
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
11+
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
12+
import software.amazon.awssdk.regions.Region;
13+
import software.amazon.awssdk.services.ses.SesClient;
1014

1115
@Configuration
1216
public class AmazonS3Config {
@@ -30,4 +34,14 @@ public AmazonS3Client amazonS3Client() {
3034
.build();
3135
}
3236

37+
@Bean
38+
public SesClient sesClient() {
39+
return SesClient.builder()
40+
.region(Region.AP_NORTHEAST_2)
41+
.credentialsProvider(StaticCredentialsProvider.create(
42+
AwsBasicCredentials.create(accessKey, secretKey)
43+
))
44+
.build();
45+
}
46+
3347
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package ddingdong.ddingdongBE.common.config;
2+
3+
import java.util.concurrent.Executor;
4+
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
5+
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.scheduling.annotation.AsyncConfigurer;
8+
import org.springframework.scheduling.annotation.EnableAsync;
9+
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
10+
11+
@Configuration
12+
@EnableAsync
13+
public class AsyncConfig implements AsyncConfigurer {
14+
15+
@Override
16+
public Executor getAsyncExecutor() {
17+
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
18+
executor.setCorePoolSize(5);
19+
executor.setMaxPoolSize(10);
20+
executor.setQueueCapacity(500);
21+
executor.setThreadNamePrefix("EmailAsync-");
22+
executor.initialize();
23+
return executor;
24+
}
25+
26+
@Override
27+
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
28+
return new SimpleAsyncUncaughtExceptionHandler();
29+
}
30+
31+
32+
}

src/main/java/ddingdong/ddingdongBE/common/config/SecurityConfig.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ddingdong.ddingdongBE.common.config;
22

33
import static org.springframework.http.HttpMethod.GET;
4+
import static org.springframework.http.HttpMethod.POST;
45

56
import ddingdong.ddingdongBE.auth.service.JwtAuthService;
67
import ddingdong.ddingdongBE.common.filter.JwtAuthenticationFilter;
@@ -46,7 +47,14 @@ public SecurityFilterChain filterChain(HttpSecurity http, JwtAuthService authSer
4647
API_PREFIX + "/banners/**",
4748
API_PREFIX + "/documents/**",
4849
API_PREFIX + "/questions/**",
49-
API_PREFIX + "/feeds/**")
50+
API_PREFIX + "/feeds/**",
51+
API_PREFIX + "/forms/**",
52+
API_PREFIX + "/file/upload-url/form-application"
53+
)
54+
.permitAll()
55+
.requestMatchers(POST,
56+
API_PREFIX + "/forms/{formId}/applications"
57+
)
5058
.permitAll()
5159
.requestMatchers(API_PREFIX + "/internal/**")
5260
.permitAll()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package ddingdong.ddingdongBE.common.converter;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import jakarta.persistence.AttributeConverter;
6+
import jakarta.persistence.Converter;
7+
import java.util.List;
8+
import org.springframework.stereotype.Component;
9+
10+
@Converter
11+
@Component
12+
public class StringListConverter implements AttributeConverter<List<String>, String> {
13+
14+
private final ObjectMapper mapper = new ObjectMapper();
15+
16+
@Override
17+
public String convertToDatabaseColumn(List<String> dataList) {
18+
try {
19+
return mapper.writeValueAsString(dataList);
20+
} catch (JsonProcessingException e) {
21+
throw new RuntimeException(e);
22+
}
23+
}
24+
25+
@Override
26+
public List<String> convertToEntityAttribute(String data) {
27+
try {
28+
return mapper.readValue(data, List.class);
29+
} catch (JsonProcessingException e) {
30+
throw new RuntimeException(e);
31+
}
32+
}
33+
}

src/main/java/ddingdong/ddingdongBE/common/exception/AuthenticationException.java

+8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ sealed public class AuthenticationException extends CustomException {
77
public static final String UNREGISTERED_ID_ERROR_MESSAGE = "등록되지 않은 ID입니다.";
88
public static final String INVALIDATED_PASSWORD_ERROR_MESSAGE = "잘못된 비밀번호입니다.";
99
public static final String NON_EXIST_USER_ROLE_ERROR_MESSAGE = "유저 권한이 존재하지 않습니다.";
10+
public static final String NON_HAVE_AUTHORITY_MESSAGE = "해당 유저에게 권한이 없습니다.";
1011

1112
public AuthenticationException(String message, int errorCode) {
1213
super(message, errorCode);
@@ -32,4 +33,11 @@ public NonExistUserRole() {
3233
super(NON_EXIST_USER_ROLE_ERROR_MESSAGE, UNAUTHORIZED.value());
3334
}
3435
}
36+
37+
public static final class NonHaveAuthority extends AuthenticationException {
38+
39+
public NonHaveAuthority() {
40+
super(NON_HAVE_AUTHORITY_MESSAGE, UNAUTHORIZED.value());
41+
}
42+
}
3543
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package ddingdong.ddingdongBE.common.exception;
2+
3+
import static org.springframework.http.HttpStatus.BAD_REQUEST;
4+
5+
public class FormException extends CustomException {
6+
7+
public static final String FORM_PERIOD_ERROR_MESSAGE = "해당 폼지의 응답기간이 아닙니다";
8+
private static final String INVALID_FORM_DATE_MESSAGE = "입력한 기간과 겹치는 폼이 존재합니다.";
9+
private static final String INVALID_FIELD_TYPE_MESSAGE = "통계를 조회할 질문 유형이 올바르지 않습니다.";
10+
11+
12+
public FormException(String message, int errorCode) {
13+
super(message, errorCode);
14+
}
15+
16+
public static final class FormPeriodException extends FormException {
17+
18+
public FormPeriodException() {
19+
super(FORM_PERIOD_ERROR_MESSAGE, BAD_REQUEST.value());
20+
}
21+
}
22+
23+
public static final class OverlapFormPeriodException extends FormException {
24+
25+
public OverlapFormPeriodException() {
26+
super(INVALID_FORM_DATE_MESSAGE, BAD_REQUEST.value());
27+
}
28+
}
29+
30+
public static final class InvalidFieldTypeException extends FormException {
31+
32+
public InvalidFieldTypeException() {
33+
super(INVALID_FIELD_TYPE_MESSAGE, BAD_REQUEST.value());
34+
}
35+
}
36+
}

src/main/java/ddingdong/ddingdongBE/common/exception/InvalidatedMappingException.java

+1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ public InvalidatedEnumValue(String message) {
1414
super(message, BAD_REQUEST.value());
1515
}
1616
}
17+
1718
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package ddingdong.ddingdongBE.common.utils;
2+
3+
public class CalculationUtils {
4+
5+
public static int calculateRatio(int numerator, int denominator) {
6+
if (denominator == 0) {
7+
return 0;
8+
}
9+
return (int) ((double) numerator / denominator * 100);
10+
}
11+
12+
public static int calculateDifference(int beforeCount, int count) {
13+
return count - beforeCount;
14+
}
15+
16+
public static int calculateDifferenceRatio(int beforeCount, int count) {
17+
int difference = calculateDifference(beforeCount, count);
18+
return calculateRatio(difference, beforeCount);
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ddingdong.ddingdongBE.common.utils;
2+
3+
import java.time.LocalDate;
4+
import java.time.LocalDateTime;
5+
import java.time.format.DateTimeFormatter;
6+
7+
public class TimeUtils {
8+
9+
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm";
10+
11+
public static LocalDateTime parseToLocalDateTime(String dateString) {
12+
if (dateString == null || dateString.isBlank()) {
13+
return null;
14+
}
15+
16+
return LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern(DATE_FORMAT));
17+
}
18+
19+
public static LocalDateTime processDate(String dateString, LocalDateTime currentDate) {
20+
if (dateString == null) {
21+
return null;
22+
}
23+
24+
if (dateString.isBlank()) {
25+
return null;
26+
}
27+
28+
return parseToLocalDateTime(dateString);
29+
}
30+
31+
public static String getYearAndMonth(LocalDate date) {
32+
return date.getYear() + "-" + date.getMonthValue();
33+
}
34+
}

src/main/java/ddingdong/ddingdongBE/domain/activityreport/service/dto/command/CreateActivityReportCommand.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package ddingdong.ddingdongBE.domain.activityreport.service.dto.command;
22

3-
import ddingdong.ddingdongBE.common.utils.TimeParser;
3+
import ddingdong.ddingdongBE.common.utils.TimeUtils;
44
import ddingdong.ddingdongBE.domain.activityreport.domain.ActivityReport;
55
import ddingdong.ddingdongBE.domain.activityreport.domain.Participant;
66
import ddingdong.ddingdongBE.domain.club.entity.Club;
@@ -23,8 +23,8 @@ public ActivityReport toEntity(Club club) {
2323
.term(term)
2424
.content(content)
2525
.place(place)
26-
.startDate(TimeParser.parseToLocalDateTime(startDate))
27-
.endDate(TimeParser.parseToLocalDateTime(endDate))
26+
.startDate(TimeUtils.parseToLocalDateTime(startDate))
27+
.endDate(TimeUtils.parseToLocalDateTime(endDate))
2828
.participants(participants)
2929
.club(club)
3030
.build();

src/main/java/ddingdong/ddingdongBE/domain/activityreport/service/dto/command/UpdateActivityReportCommand.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package ddingdong.ddingdongBE.domain.activityreport.service.dto.command;
22

3-
import ddingdong.ddingdongBE.common.utils.TimeParser;
3+
import ddingdong.ddingdongBE.common.utils.TimeUtils;
44
import ddingdong.ddingdongBE.domain.activityreport.domain.ActivityReport;
55
import ddingdong.ddingdongBE.domain.activityreport.domain.Participant;
66
import java.time.LocalDateTime;
@@ -22,8 +22,8 @@ public ActivityReport toEntity() {
2222
return ActivityReport.builder()
2323
.content(content)
2424
.place(place)
25-
.startDate(TimeParser.processDate(startDate, LocalDateTime.now()))
26-
.endDate(TimeParser.processDate(endDate, LocalDateTime.now()))
25+
.startDate(TimeUtils.processDate(startDate, LocalDateTime.now()))
26+
.endDate(TimeUtils.processDate(endDate, LocalDateTime.now()))
2727
.participants(participants)
2828
.build();
2929
}

src/main/java/ddingdong/ddingdongBE/domain/club/controller/UserClubController.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
import ddingdong.ddingdongBE.domain.club.controller.dto.response.UserClubResponse;
66
import ddingdong.ddingdongBE.domain.club.service.FacadeUserClubService;
77
import ddingdong.ddingdongBE.domain.club.service.dto.query.UserClubQuery;
8-
import java.time.LocalDateTime;
8+
import java.time.LocalDate;
99
import java.util.List;
1010
import lombok.RequiredArgsConstructor;
11-
import org.springframework.web.bind.annotation.PathVariable;
1211
import org.springframework.web.bind.annotation.RestController;
1312

1413
@RestController
@@ -20,7 +19,7 @@ public class UserClubController implements UserClubApi {
2019

2120
@Override
2221
public List<UserClubListResponse> getClubs() {
23-
return facadeUserClubService.findAllWithRecruitTimeCheckPoint(LocalDateTime.now()).stream()
22+
return facadeUserClubService.findAllWithRecruitTimeCheckPoint(LocalDate.now()).stream()
2423
.map(UserClubListResponse::from)
2524
.toList();
2625
}

src/main/java/ddingdong/ddingdongBE/domain/club/controller/dto/request/UpdateClubInfoRequest.java

-9
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ public record UpdateClubInfoRequest(
2727
@Schema(description = "동아리방 위치", example = "S1111")
2828
@NotNull(message = "동아리방 위치는 필수로 입력해야 합니다.")
2929
String location,
30-
@Schema(description = "모집시작 날짜", example = "2024-01-01 00:00")
31-
String startRecruitPeriod,
32-
@Schema(description = "모집마감 날짜", example = "2024-01-01 00:00")
33-
String endRecruitPeriod,
3430
@Schema(description = "정기활동", example = "정기활동")
3531
@NotNull(message = "정기활동은 필수로 입력해야 합니다.")
3632
String regularMeeting,
@@ -42,8 +38,6 @@ public record UpdateClubInfoRequest(
4238
String activity,
4339
@Schema(description = "인재상", example = "인재상")
4440
String ideal,
45-
@Schema(description = "모집 Url", example = "Url")
46-
String formUrl,
4741
@Schema(description = "동아리 프로필 이미지 식별자", example = "0192c828-ffce-7ee8-94a8-d9d4c8cdec00")
4842
String profileImageId,
4943
@Schema(description = "동아리 소개 이미지 식별자", example = "0192c828-ffce-7ee8-94a8-d9d4c8cdec00")
@@ -60,13 +54,10 @@ public UpdateClubInfoCommand toCommand(Long userId) {
6054
clubLeader,
6155
phoneNumber,
6256
location,
63-
startRecruitPeriod,
64-
endRecruitPeriod,
6557
regularMeeting,
6658
introduction,
6759
activity,
6860
ideal,
69-
formUrl,
7061
profileImageId,
7162
introductionImageId
7263
);

src/main/java/ddingdong/ddingdongBE/domain/club/controller/dto/response/MyClubInfoResponse.java

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package ddingdong.ddingdongBE.domain.club.controller.dto.response;
22

3-
import com.fasterxml.jackson.annotation.JsonFormat;
43
import ddingdong.ddingdongBE.domain.club.service.dto.query.MyClubInfoQuery;
54
import ddingdong.ddingdongBE.file.service.dto.query.UploadedFileUrlQuery;
65
import io.swagger.v3.oas.annotations.media.Schema;
7-
import java.time.LocalDateTime;
6+
import java.time.LocalDate;
87

98
@Schema(
109
name = "MyClubInfoResponse",
@@ -24,11 +23,9 @@ public record MyClubInfoResponse(
2423
@Schema(description = "동아리방 위치", example = "S1111")
2524
String location,
2625
@Schema(description = "모집시작날짜", example = "2024-01-01 00:00")
27-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "Asia/Seoul")
28-
LocalDateTime startRecruitPeriod,
26+
LocalDate startDate,
2927
@Schema(description = "모집마감날짜", example = "2024-01-01 00:00")
30-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "Asia/Seoul")
31-
LocalDateTime endRecruitPeriod,
28+
LocalDate endDate,
3229
@Schema(description = "정기활동", example = "정기활동")
3330
String regularMeeting,
3431
@Schema(description = "동아리 소개", example = "소개")
@@ -37,8 +34,6 @@ public record MyClubInfoResponse(
3734
String activity,
3835
@Schema(description = "인재상", example = "인재상")
3936
String ideal,
40-
@Schema(description = "모집Url", example = "url")
41-
String formUrl,
4237
@Schema(description = "동아리 프로필 이미지 Url", example = "url")
4338
MyClubInfoImageUrlResponse profileImage,
4439
MyClubInfoImageUrlResponse introductionImage
@@ -52,13 +47,12 @@ public static MyClubInfoResponse from(MyClubInfoQuery query) {
5247
query.leader(),
5348
query.phoneNumber(),
5449
query.location(),
55-
query.startRecruitPeriod(),
56-
query.endRecruitPeriod(),
50+
query.startDate(),
51+
query.endDate(),
5752
query.regularMeeting(),
5853
query.introduction(),
5954
query.activity(),
6055
query.ideal(),
61-
query.formUrl(),
6256
MyClubInfoImageUrlResponse.from(query.profileImageUrlQuery()),
6357
MyClubInfoImageUrlResponse.from(query.introductionImageUrlQuery())
6458
);

0 commit comments

Comments
 (0)