Skip to content

Commit 37883dd

Browse files
authored
Merge pull request #874 from woowacourse-teams/develop
[release] v1.1.4
2 parents 2485e92 + efe18c1 commit 37883dd

File tree

50 files changed

+326
-192
lines changed

Some content is hidden

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

50 files changed

+326
-192
lines changed

backend/src/main/java/com/allog/dallog/domain/auth/application/JwtTokenProvider.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public void validateToken(final String token) {
7171
claims.getBody()
7272
.getExpiration()
7373
.before(new Date());
74-
} catch (JwtException | IllegalArgumentException e) {
74+
} catch (final JwtException | IllegalArgumentException e) {
7575
throw new InvalidTokenException("권한이 없습니다.");
7676
}
7777
}

backend/src/main/java/com/allog/dallog/domain/auth/dto/response/AccessTokenResponse.java

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.allog.dallog.domain.auth.dto.response;
22

3-
import java.util.Objects;
4-
53
public class AccessTokenResponse {
64

75
private String accessToken;

backend/src/main/java/com/allog/dallog/domain/category/application/CategoryService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public CategoriesResponse findNormalByName(final String name) {
102102
return new CategoriesResponse(categories);
103103
}
104104

105-
// 멤버가 ADMIN이 아니어도 일정 추가/제거/수정이 가능하므로, findAdminCategories와 별도의 메소드로 분리해야함
105+
// 회원이 ADMIN이 아니어도 일정 추가/제거/수정이 가능하므로, findAdminCategories와 별도의 메소드로 분리해야함
106106
public CategoriesResponse findScheduleEditableCategories(final Long memberId) {
107107
List<CategoryRole> categoryRoles = categoryRoleRepository.findByMemberId(memberId);
108108
Set<CategoryRoleType> roleTypes = CategoryRoleType.getHavingAuthorities(Set.of(ADD_SCHEDULE, UPDATE_SCHEDULE));

backend/src/main/java/com/allog/dallog/domain/category/domain/Category.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public void changeName(final String name) {
6767

6868
private void validatePersonal() {
6969
if (isPersonal()) {
70-
throw new InvalidCategoryException("내 일정은 수정할 수 없습니다.");
70+
throw new InvalidCategoryException("'내 일정' 카테고리는 수정할 수 없습니다.");
7171
}
7272
}
7373

@@ -76,7 +76,7 @@ private void validateNameLength(final String name) {
7676
throw new InvalidCategoryException("카테고리 이름은 공백일 수 없습니다.");
7777
}
7878
if (name.length() > MAX_NAME_LENGTH) {
79-
throw new InvalidCategoryException("카테고리 이름의 길이는 20을 초과할 수 없습니다.");
79+
throw new InvalidCategoryException(String.format("카테고리 이름의 길이는 %d을 초과할 수 없습니다.", MAX_NAME_LENGTH));
8080
}
8181
}
8282

@@ -124,11 +124,11 @@ public Member getMember() {
124124
return member;
125125
}
126126

127-
public CategoryType getCategoryType() {
128-
return categoryType;
129-
}
130-
131127
public void setMember(final Member member) {
132128
this.member = member;
133129
}
130+
131+
public CategoryType getCategoryType() {
132+
return categoryType;
133+
}
134134
}

backend/src/main/java/com/allog/dallog/domain/category/domain/CategoryType.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public enum CategoryType {
99
public static CategoryType from(final String value) {
1010
try {
1111
return CategoryType.valueOf(value.toUpperCase());
12-
} catch (IllegalArgumentException e) {
12+
} catch (final IllegalArgumentException e) {
1313
throw new NoSuchCategoryException("(" + value + ")는 존재하지 않는 카테고리 타입입니다.");
1414
}
1515
}

backend/src/main/java/com/allog/dallog/domain/categoryrole/application/CategoryRoleService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ private void validateAuthority(final Long loginMemberId, final Long categoryId)
4545
private void validateSoleAdmin(final Long memberId, final Long categoryId) {
4646
boolean isSoleAdmin = categoryRoleRepository.isMemberSoleAdminInCategory(memberId, categoryId);
4747
if (isSoleAdmin) {
48-
throw new NotAbleToChangeRoleException("변경 대상 회원이 유일한 ADMIN이므로 다른 역할로 변경할 수 없습니다.");
48+
throw new NotAbleToChangeRoleException("변경 대상 회원이 유일한 관리자이므로 다른 역할로 변경할 수 없습니다.");
4949
}
5050
}
5151

backend/src/main/java/com/allog/dallog/domain/member/application/MemberService.java

+2-21
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,13 @@
22

33
import static com.allog.dallog.domain.categoryrole.domain.CategoryAuthority.FIND_SUBSCRIBERS;
44

5-
import com.allog.dallog.domain.auth.domain.OAuthTokenRepository;
6-
import com.allog.dallog.domain.auth.domain.TokenRepository;
7-
import com.allog.dallog.domain.category.domain.CategoryRepository;
8-
import com.allog.dallog.domain.category.domain.ExternalCategoryDetailRepository;
95
import com.allog.dallog.domain.categoryrole.domain.CategoryRole;
106
import com.allog.dallog.domain.categoryrole.domain.CategoryRoleRepository;
117
import com.allog.dallog.domain.member.domain.Member;
128
import com.allog.dallog.domain.member.domain.MemberRepository;
139
import com.allog.dallog.domain.member.dto.request.MemberUpdateRequest;
1410
import com.allog.dallog.domain.member.dto.response.MemberResponse;
1511
import com.allog.dallog.domain.member.dto.response.SubscribersResponse;
16-
import com.allog.dallog.domain.schedule.domain.ScheduleRepository;
1712
import com.allog.dallog.domain.subscription.domain.Subscription;
1813
import com.allog.dallog.domain.subscription.domain.SubscriptionRepository;
1914
import java.util.List;
@@ -25,29 +20,15 @@
2520
public class MemberService {
2621

2722
private final MemberRepository memberRepository;
28-
private final CategoryRepository categoryRepository;
29-
private final ExternalCategoryDetailRepository externalCategoryDetailRepository;
30-
private final ScheduleRepository scheduleRepository;
3123
private final SubscriptionRepository subscriptionRepository;
32-
private final OAuthTokenRepository oAuthTokenRepository;
3324
private final CategoryRoleRepository categoryRoleRepository;
34-
private final TokenRepository tokenRepository;
3525

36-
public MemberService(final MemberRepository memberRepository, final CategoryRepository categoryRepository,
37-
final ExternalCategoryDetailRepository externalCategoryDetailRepository,
38-
final ScheduleRepository scheduleRepository,
26+
public MemberService(final MemberRepository memberRepository,
3927
final SubscriptionRepository subscriptionRepository,
40-
final OAuthTokenRepository oAuthTokenRepository,
41-
final CategoryRoleRepository categoryRoleRepository,
42-
final TokenRepository tokenRepository) {
28+
final CategoryRoleRepository categoryRoleRepository) {
4329
this.memberRepository = memberRepository;
44-
this.categoryRepository = categoryRepository;
45-
this.externalCategoryDetailRepository = externalCategoryDetailRepository;
46-
this.scheduleRepository = scheduleRepository;
4730
this.subscriptionRepository = subscriptionRepository;
48-
this.oAuthTokenRepository = oAuthTokenRepository;
4931
this.categoryRoleRepository = categoryRoleRepository;
50-
this.tokenRepository = tokenRepository;
5132
}
5233

5334
public MemberResponse findById(final Long id) {

backend/src/main/java/com/allog/dallog/domain/member/domain/Member.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private void validateEmail(final String email) {
6161

6262
private void validateDisplayName(final String displayName) {
6363
if (displayName.isEmpty() || displayName.length() > MAX_DISPLAY_NAME_LENGTH) {
64-
throw new InvalidMemberException("이름 형식이 올바르지 않습니다.");
64+
throw new InvalidMemberException(String.format("이름은 1자 이상 1자 %d이하여야 합니다.", MAX_DISPLAY_NAME_LENGTH));
6565
}
6666
}
6767

backend/src/main/java/com/allog/dallog/domain/schedule/application/ScheduleService.java

+1-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import com.allog.dallog.domain.category.domain.ExternalCategoryDetailRepository;
1313
import com.allog.dallog.domain.categoryrole.domain.CategoryRole;
1414
import com.allog.dallog.domain.categoryrole.domain.CategoryRoleRepository;
15-
import com.allog.dallog.domain.member.domain.MemberRepository;
1615
import com.allog.dallog.domain.schedule.domain.IntegrationSchedule;
1716
import com.allog.dallog.domain.schedule.domain.Schedule;
1817
import com.allog.dallog.domain.schedule.domain.ScheduleRepository;
@@ -27,11 +26,8 @@
2726
import com.allog.dallog.domain.subscription.domain.Color;
2827
import com.allog.dallog.domain.subscription.domain.SubscriptionRepository;
2928
import com.allog.dallog.domain.subscription.domain.Subscriptions;
30-
import com.allog.dallog.presentation.MemberController;
3129
import java.time.LocalDateTime;
3230
import java.util.List;
33-
import org.slf4j.Logger;
34-
import org.slf4j.LoggerFactory;
3531
import org.springframework.stereotype.Service;
3632
import org.springframework.transaction.annotation.Transactional;
3733

@@ -42,22 +38,20 @@ public class ScheduleService {
4238
private final ScheduleRepository scheduleRepository;
4339
private final CategoryRepository categoryRepository;
4440
private final CategoryRoleRepository categoryRoleRepository;
45-
private final MemberRepository memberRepository;
4641
private final SubscriptionRepository subscriptionRepository;
4742
private final OAuthTokenRepository oAuthTokenRepository;
4843
private final ExternalCategoryDetailRepository externalCategoryDetailRepository;
4944
private final ColorPicker colorPicker;
5045

5146
public ScheduleService(final ScheduleRepository scheduleRepository, final CategoryRepository categoryRepository,
52-
final CategoryRoleRepository categoryRoleRepository, final MemberRepository memberRepository,
47+
final CategoryRoleRepository categoryRoleRepository,
5348
final SubscriptionRepository subscriptionRepository,
5449
final OAuthTokenRepository oAuthTokenRepository,
5550
final ExternalCategoryDetailRepository externalCategoryDetailRepository,
5651
final ColorPicker colorPicker) {
5752
this.scheduleRepository = scheduleRepository;
5853
this.categoryRepository = categoryRepository;
5954
this.categoryRoleRepository = categoryRoleRepository;
60-
this.memberRepository = memberRepository;
6155
this.subscriptionRepository = subscriptionRepository;
6256
this.oAuthTokenRepository = oAuthTokenRepository;
6357
this.externalCategoryDetailRepository = externalCategoryDetailRepository;

backend/src/main/java/com/allog/dallog/domain/schedule/domain/Schedule.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public void change(final Category category, final String title, final LocalDateT
7474

7575
private void validateTitleLength(final String title) {
7676
if (title.length() > MAX_TITLE_LENGTH) {
77-
throw new InvalidScheduleException("일정 제목의 길이는 20을 초과할 수 없습니다.");
77+
throw new InvalidScheduleException(String.format("일정 제목의 길이는 %d을 초과할 수 없습니다.", MAX_TITLE_LENGTH));
7878
}
7979
}
8080

@@ -96,7 +96,7 @@ private boolean isNotValidDateTimeRange(final LocalDateTime dateTime) {
9696

9797
private void validateMemoLength(final String memo) {
9898
if (memo.length() > MAX_MEMO_LENGTH) {
99-
throw new InvalidScheduleException("일정 메모의 길이는 255를 초과할 수 없습니다.");
99+
throw new InvalidScheduleException(String.format("일정 메모의 길이는 %d를 초과할 수 없습니다.", MAX_MEMO_LENGTH));
100100
}
101101
}
102102

backend/src/main/java/com/allog/dallog/domain/schedule/dto/request/DateRangeRequest.java

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ public DateRangeRequest(final String startDateTime, final String endDateTime) {
1515
this.endDateTime = LocalDateTime.parse(endDateTime, DateTimeFormatter.ofPattern(DATE_FORMAT));
1616
}
1717

18-
// TODO: 리팩토링
1918
public static DateRangeRequest of(final LocalDateTime startDateTime, final LocalDateTime endDateTime) {
2019
String startDateTimeFormat = startDateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT));
2120
String endDateTimeFormat = endDateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.allog.dallog.global.config.replication;
2+
3+
import static com.allog.dallog.global.config.replication.DataSourceKey.KeyName.REPLICA_1_NAME;
4+
import static com.allog.dallog.global.config.replication.DataSourceKey.KeyName.REPLICA_2_NAME;
5+
import static com.allog.dallog.global.config.replication.DataSourceKey.KeyName.SOURCE_NAME;
6+
import static com.allog.dallog.global.config.replication.DataSourceKey.REPLICA_1;
7+
import static com.allog.dallog.global.config.replication.DataSourceKey.REPLICA_2;
8+
import static com.allog.dallog.global.config.replication.DataSourceKey.SOURCE;
9+
10+
import java.util.Map;
11+
import javax.sql.DataSource;
12+
import org.springframework.beans.factory.annotation.Qualifier;
13+
import org.springframework.boot.context.properties.ConfigurationProperties;
14+
import org.springframework.boot.jdbc.DataSourceBuilder;
15+
import org.springframework.context.annotation.Bean;
16+
import org.springframework.context.annotation.Configuration;
17+
import org.springframework.context.annotation.Primary;
18+
import org.springframework.context.annotation.Profile;
19+
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
20+
21+
@Configuration
22+
@Profile({"prod", "dev"})
23+
public class DataSourceConfiguration {
24+
25+
@Bean
26+
@Primary
27+
public DataSource dataSource() {
28+
DataSource determinedDataSource = routingDataSource(sourceDataSource(), replica1DataSource(),
29+
replica2DataSource());
30+
return new LazyConnectionDataSourceProxy(determinedDataSource);
31+
}
32+
33+
@Bean
34+
@Qualifier(SOURCE_NAME)
35+
@ConfigurationProperties(prefix = "spring.datasource.source")
36+
public DataSource sourceDataSource() {
37+
return DataSourceBuilder.create()
38+
.build();
39+
}
40+
41+
@Bean
42+
@Qualifier(REPLICA_1_NAME)
43+
@ConfigurationProperties(prefix = "spring.datasource.replica1")
44+
public DataSource replica1DataSource() {
45+
return DataSourceBuilder.create()
46+
.build();
47+
}
48+
49+
@Bean
50+
@Qualifier(REPLICA_2_NAME)
51+
@ConfigurationProperties(prefix = "spring.datasource.replica2")
52+
public DataSource replica2DataSource() {
53+
return DataSourceBuilder.create()
54+
.build();
55+
}
56+
57+
@Bean
58+
public DataSource routingDataSource(
59+
@Qualifier(SOURCE_NAME) DataSource sourceDataSource,
60+
@Qualifier(REPLICA_1_NAME) DataSource replica1DataSource,
61+
@Qualifier(REPLICA_2_NAME) DataSource replica2DataSource
62+
) {
63+
Map<Object, Object> dataSources = Map.of(
64+
SOURCE, sourceDataSource, REPLICA_1, replica1DataSource, REPLICA_2, replica2DataSource
65+
);
66+
67+
RoutingDataSource routingDataSource = new RoutingDataSource();
68+
routingDataSource.setTargetDataSources(dataSources);
69+
routingDataSource.setDefaultTargetDataSource(sourceDataSource);
70+
71+
return routingDataSource;
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.allog.dallog.global.config.replication;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
import java.util.stream.Collectors;
6+
7+
public enum DataSourceKey {
8+
SOURCE(KeyName.SOURCE_NAME, false),
9+
REPLICA_1(KeyName.REPLICA_1_NAME, true),
10+
REPLICA_2(KeyName.REPLICA_2_NAME, true);
11+
12+
private final String key;
13+
private final boolean isReplica;
14+
15+
DataSourceKey(final String key, final boolean isReplica) {
16+
this.key = key;
17+
this.isReplica = isReplica;
18+
}
19+
20+
public static List<DataSourceKey> getReplicas() {
21+
return Arrays.stream(values())
22+
.filter(key -> key.isReplica)
23+
.collect(Collectors.toList());
24+
}
25+
26+
// 어노테이션에서도 참조할 수 있도록 중첩 클래스에 상수 선언
27+
public static class KeyName {
28+
public static final String SOURCE_NAME = "SOURCE";
29+
public static final String REPLICA_1_NAME = "REPLICA_1";
30+
public static final String REPLICA_2_NAME = "REPLICA_2";
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.allog.dallog.global.config.replication;
2+
3+
import java.util.List;
4+
import java.util.concurrent.ThreadLocalRandom;
5+
6+
public class RandomReplicaKeys {
7+
8+
private static final ThreadLocalRandom random = ThreadLocalRandom.current();
9+
10+
private final List<DataSourceKey> dataSourceKeys;
11+
private final int size;
12+
13+
public RandomReplicaKeys() {
14+
this.dataSourceKeys = List.copyOf(DataSourceKey.getReplicas());
15+
this.size = dataSourceKeys.size();
16+
}
17+
18+
public DataSourceKey next() {
19+
int currentDataSourceIndex = random.nextInt(size);
20+
return dataSourceKeys.get(currentDataSourceIndex);
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.allog.dallog.global.config.replication;
2+
3+
import static com.allog.dallog.global.config.replication.DataSourceKey.SOURCE;
4+
5+
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
6+
import org.springframework.transaction.support.TransactionSynchronizationManager;
7+
8+
public class RoutingDataSource extends AbstractRoutingDataSource {
9+
10+
private final RandomReplicaKeys randomReplicaKeys = new RandomReplicaKeys();
11+
12+
@Override
13+
protected Object determineCurrentLookupKey() {
14+
boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
15+
16+
if (isReadOnly) {
17+
return randomReplicaKeys.next();
18+
}
19+
20+
return SOURCE;
21+
}
22+
}

backend/src/main/java/com/allog/dallog/global/error/ControllerAdvice.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ public ResponseEntity<ErrorResponse> handleNotSupportedMethod() {
120120

121121
@ExceptionHandler(OAuthException.class)
122122
public ResponseEntity<ErrorResponse> handleOAuthException(final RuntimeException e) {
123-
log.error("OAuth 통신 과정에서 에러가 발생했습니다.", e);
124-
ErrorResponse errorResponse = new ErrorResponse("OAuth 통신 과정에서 에러가 발생했습니다.");
123+
log.error(e.getMessage(), e);
124+
ErrorResponse errorResponse = new ErrorResponse(e.getMessage());
125125
return ResponseEntity.internalServerError().body(errorResponse);
126126
}
127127

0 commit comments

Comments
 (0)