Skip to content

Commit

Permalink
Merge pull request #278 from MOONSHOT-Team/develop
Browse files Browse the repository at this point in the history
[Deploy] v1.1.0 운영서버 배포
  • Loading branch information
0lynny authored May 29, 2024
2 parents bc23907 + c9a3c11 commit 106b524
Show file tree
Hide file tree
Showing 34 changed files with 1,036 additions and 168 deletions.
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ subprojects {
}

dependencies {
// Spring Security

//Spring Security
implementation 'org.springframework.boot:spring-boot-starter-security'

Expand All @@ -43,6 +41,10 @@ subprojects {
// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mockito:mockito-core:5.9.0'

// Sentry
implementation 'io.sentry:sentry-spring-boot-starter-jakarta:6.28.0'
implementation 'io.sentry:sentry-logback:6.28.0'
}

tasks.named('test') {
Expand Down
27 changes: 27 additions & 0 deletions moonshot-api/src/main/java/org/moonshot/config/AsyncConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.moonshot.config;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {

@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(4);
executor.setQueueCapacity(4);
executor.setKeepAliveSeconds(60);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
executor.setThreadNamePrefix("async-executor-");
executor.initialize();
return executor;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public Optional<AchieveResponseDto> modifyKeyResult(final KeyResultModifyRequest
throw new BadRequestException(REQUIRED_KEY_RESULT_VALUE);
}

Log updateLog = logService.createUpdateLog(request, keyResult.getId());
Log updateLog = logService.createUpdateLog(request, keyResult);
validateLogNum(request.krTarget(), updateLog.getKeyResult().getTarget());

Optional<Log> prevLog = logRepository.findLatestLogByKeyResultId(LogState.RECORD, request.keyResultId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ public Optional<AchieveResponseDto> createRecordLog(final Long userId, final Log
return Optional.empty();
}

public Log createUpdateLog(final KeyResultModifyRequestDto request, final Long keyResultId) {
KeyResult keyResult = keyResultRepository.findById(keyResultId)
.orElseThrow(() -> new NotFoundException(NOT_FOUND_KEY_RESULT));
public Log createUpdateLog(final KeyResultModifyRequestDto request, final KeyResult keyResult) {
return logRepository.save(Log.builder()
.date(LocalDateTime.now())
.state(LogState.UPDATE)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
package org.moonshot.objective.dto.response;

import java.util.List;
import java.util.Map;
import org.moonshot.objective.model.Criteria;

public record HistoryResponseDto(
List<ObjectiveGroupByYearDto> groups,
List<YearDto> years,
List<String> categories
) {
public static HistoryResponseDto of(List<ObjectiveGroupByYearDto> groups, Map<Integer, Integer> years,
List<String> categories, Criteria criteria) {
return new HistoryResponseDto(
groups,
YearDto.of(years),
categories.stream().distinct().toList()
);
public static HistoryResponseDto of(List<ObjectiveGroupByYearDto> groups, List<String> categories) {
return new HistoryResponseDto(groups, categories.stream().distinct().toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.moonshot.common.model.Period;
Expand Down Expand Up @@ -47,7 +46,7 @@ public class ObjectiveService implements IndexService {
private final ObjectiveRepository objectiveRepository;

public void createObjective(final Long userId, final OKRCreateRequestDto request) {
User user = userRepository.findById(userId)
User user = userRepository.findByIdWithCache(userId)
.orElseThrow(() -> new NotFoundException(NOT_FOUND_USER));

List<Objective> objectives = objectiveRepository.findAllByUserId(userId);
Expand Down Expand Up @@ -120,11 +119,6 @@ public HistoryResponseDto getObjectiveHistory(final Long userId, final Integer y
List<Objective> objectives = objectiveRepository.findObjectives(userId, year, category, criteria);
Map<Integer, List<Objective>> groups = objectives.stream()
.collect(Collectors.groupingBy(objective -> objective.getPeriod().getStartAt().getYear()));
Map<Integer, Integer> years = groups.entrySet().stream()
.collect(Collectors.toMap(
Entry::getKey,
entry -> entry.getValue().size()
));
List<String> categories = objectives.stream().map(objective -> objective.getCategory().getValue()).toList();

List<ObjectiveGroupByYearDto> groupList = groups.entrySet().stream()
Expand All @@ -142,7 +136,7 @@ public HistoryResponseDto getObjectiveHistory(final Long userId, final Integer y
.sorted(Comparator.comparingInt(ObjectiveGroupByYearDto::year).reversed()).toList();
}

return HistoryResponseDto.of(groupsSortedByCriteria, years, categories, criteria);
return HistoryResponseDto.of(groupsSortedByCriteria, categories);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static void validateActiveTaskSizeExceeded(final int taskListSize) {
}

public static void validateIndexUnderMaximum(final int requestIndex, final int totalTaskListSize) {
if (requestIndex > totalTaskListSize) {
if (requestIndex > totalTaskListSize || requestIndex < 0) {
throw new BadRequestException(INVALID_TASK_INDEX);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package org.moonshot.user.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.moonshot.jwt.TokenResponse;
Expand All @@ -16,7 +13,6 @@
import org.moonshot.user.dto.response.UserInfoResponse;
import org.moonshot.user.model.LoginUser;
import org.moonshot.user.service.UserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -38,7 +34,7 @@ public class UserController implements UserApi {
@PostMapping("/login")
@Logging(item = "User", action = "Post")
public ResponseEntity<MoonshotResponse<SocialLoginResponse>> login(@RequestHeader("Authorization") final String authorization,
@RequestBody final SocialLoginRequest socialLoginRequest) throws IOException {
@RequestBody final SocialLoginRequest socialLoginRequest) {
return ResponseEntity.ok(MoonshotResponse.success(SuccessType.POST_LOGIN_SUCCESS, userService.login(SocialLoginRequest.of(socialLoginRequest.socialPlatform(), authorization))));
}

Expand Down
117 changes: 7 additions & 110 deletions moonshot-api/src/main/java/org/moonshot/user/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,27 @@
package org.moonshot.user.service;

import static org.moonshot.response.ErrorType.NOT_FOUND_USER;
import static org.moonshot.response.ErrorType.NOT_SUPPORTED_LOGIN_PLATFORM;
import static org.moonshot.user.service.validator.UserValidator.hasChange;
import static org.moonshot.user.service.validator.UserValidator.isNewUser;
import static org.moonshot.user.service.validator.UserValidator.validateUserAuthorization;
import static org.moonshot.util.MDCUtil.USER_REQUEST_ORIGIN;
import static org.moonshot.util.MDCUtil.get;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.moonshot.discord.SignUpEvent;
import org.moonshot.exception.BadRequestException;
import org.moonshot.exception.NotFoundException;
import org.moonshot.jwt.JwtTokenProvider;
import org.moonshot.jwt.TokenResponse;
import org.moonshot.objective.service.ObjectiveService;
import org.moonshot.openfeign.dto.response.google.GoogleInfoResponse;
import org.moonshot.openfeign.dto.response.google.GoogleTokenResponse;
import org.moonshot.openfeign.dto.response.kakao.KakaoTokenResponse;
import org.moonshot.openfeign.dto.response.kakao.KakaoUserResponse;
import org.moonshot.openfeign.google.GoogleApiClient;
import org.moonshot.openfeign.google.GoogleAuthApiClient;
import org.moonshot.openfeign.kakao.KakaoApiClient;
import org.moonshot.openfeign.kakao.KakaoAuthApiClient;
import org.moonshot.user.dto.request.SocialLoginRequest;
import org.moonshot.user.dto.request.UserInfoRequest;
import org.moonshot.user.dto.response.SocialLoginResponse;
import org.moonshot.user.dto.response.UserInfoResponse;
import org.moonshot.user.model.User;
import org.moonshot.user.repository.UserRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.moonshot.user.service.social.SocialLoginContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
Expand All @@ -43,95 +30,16 @@
@RequiredArgsConstructor
public class UserService {

@Value("${google.client-id}")
private String googleClientId;

@Value("${google.client-secret}")
private String googleClientSecret;

@Value("${google.redirect-url}")
private String googleRedirectUrl;

@Value("${kakao.client-id}")
private String kakaoClientId;

@Value("${kakao.redirect-uri}")
private String kakaoRedirectUri;

private final UserRepository userRepository;
private final ObjectiveService objectiveService;
private final ApplicationEventPublisher eventPublisher;

private final GoogleAuthApiClient googleAuthApiClient;
private final GoogleApiClient googleApiClient;
private final KakaoAuthApiClient kakaoAuthApiClient;
private final KakaoApiClient kakaoApiClient;
private final JwtTokenProvider jwtTokenProvider;
private final SocialLoginContext socialLoginContext;

public SocialLoginResponse login(final SocialLoginRequest request) {
return switch (request.socialPlatform().getValue()) {
case "google" -> googleLogin(request);
case "kakao" -> kakaoLogin(request);
default -> null;
};
}

public SocialLoginResponse googleLogin(final SocialLoginRequest request) {
GoogleTokenResponse tokenResponse = googleAuthApiClient.googleAuth(
request.code(),
googleClientId,
googleClientSecret,
googleRedirectUrl,
"authorization_code"
);
GoogleInfoResponse userResponse = googleApiClient.googleInfo("Bearer " + tokenResponse.accessToken());
Optional<User> findUser = userRepository.findUserBySocialId(userResponse.sub());
User user;
if (isNewUser(findUser)) {
User newUser = userRepository.save(User.builderWithSignIn()
.socialId(userResponse.sub())
.socialPlatform(request.socialPlatform())
.name(userResponse.name())
.imageUrl(userResponse.picture())
.email(userResponse.email())
.build());
user = newUser;
publishSignUpEvent(newUser);
} else {
user = findUser.get();
user.resetDeleteAt();
}
TokenResponse token = new TokenResponse(jwtTokenProvider.generateAccessToken(user.getId()), jwtTokenProvider.generateRefreshToken(user.getId()));
return SocialLoginResponse.of(user.getId(), user.getName(), token);
}

public SocialLoginResponse kakaoLogin(final SocialLoginRequest request) {
KakaoTokenResponse tokenResponse = kakaoAuthApiClient.getOAuth2AccessToken(
"authorization_code",
kakaoClientId,
(String)get(USER_REQUEST_ORIGIN) + kakaoRedirectUri,
request.code()
);
KakaoUserResponse userResponse = kakaoApiClient.getUserInformation(
"Bearer " + tokenResponse.accessToken());
Optional<User> findUser = userRepository.findUserBySocialId(userResponse.id());
User user;
if (isNewUser(findUser)) {
User newUser = userRepository.save(User.builderWithSignIn()
.socialId(userResponse.id())
.socialPlatform(request.socialPlatform())
.name(userResponse.kakaoAccount().profile().nickname())
.imageUrl(userResponse.kakaoAccount().profile().profileImageUrl())
.email(null)
.build());
user = newUser;
publishSignUpEvent(newUser);
} else {
user = findUser.get();
user.resetDeleteAt();
if (socialLoginContext.support(request.socialPlatform())) {
return socialLoginContext.doLogin(request);
}
TokenResponse token = new TokenResponse(jwtTokenProvider.generateAccessToken(user.getId()), jwtTokenProvider.generateRefreshToken(user.getId()));
return SocialLoginResponse.of(user.getId(), user.getName(), token);
throw new BadRequestException(NOT_SUPPORTED_LOGIN_PLATFORM);
}

public TokenResponse reissue(final String refreshToken) {
Expand Down Expand Up @@ -181,17 +89,6 @@ public void updateUserProfileImage(final Long userId, final String imageUrl) {
user.modifyProfileImage(imageUrl);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void publishSignUpEvent(final User user) {
eventPublisher.publishEvent(SignUpEvent.of(
user.getName(),
user.getEmail() == null ? "" : user.getEmail(),
user.getSocialPlatform().toString(),
LocalDateTime.now(),
user.getImageUrl()
));
}

public void softDeleteUser(LocalDateTime currentDate) {
List<User> expiredUserList = userRepository.findIdByDeletedAtBefore(currentDate);
if(!expiredUserList.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.moonshot.user.service;

import java.time.LocalDateTime;
import lombok.RequiredArgsConstructor;
import org.moonshot.discord.SignUpEvent;
import org.moonshot.user.model.User;
import org.moonshot.user.repository.UserRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class UserSignUpService {

private final UserRepository userRepository;
private final ApplicationEventPublisher eventPublisher;

@Async
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void publishSignUpEvent(User user) {
Long totalUserCount = userRepository.count();
eventPublisher.publishEvent(SignUpEvent.of(
totalUserCount,
user.getName(),
user.getEmail() == null ? "" : user.getEmail(),
user.getSocialPlatform().toString(),
LocalDateTime.now(),
user.getImageUrl()
));
}

}
Loading

0 comments on commit 106b524

Please sign in to comment.