Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.websoso.WSSServer.application;

import static org.websoso.WSSServer.domain.common.DiscordWebhookMessageType.WITHDRAW;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.websoso.WSSServer.domain.common.DiscordWebhookMessage;
import org.websoso.WSSServer.dto.user.WithdrawalRequest;
import org.websoso.WSSServer.feed.repository.CommentRepository;
import org.websoso.WSSServer.feed.repository.FeedRepository;
import org.websoso.WSSServer.oauth2.service.AppleService;
import org.websoso.WSSServer.oauth2.service.KakaoService;
import org.websoso.WSSServer.repository.RefreshTokenRepository;
import org.websoso.WSSServer.service.DiscordMessageClient;
import org.websoso.WSSServer.service.MessageFormatter;
import org.websoso.WSSServer.user.domain.User;
import org.websoso.WSSServer.user.domain.WithdrawalReason;
import org.websoso.WSSServer.user.repository.UserRepository;
import org.websoso.WSSServer.user.repository.WithdrawalReasonRepository;

@Service
@RequiredArgsConstructor
@Transactional
public class AccountApplication {
private static final String KAKAO_PREFIX = "kakao";
private static final String APPLE_PREFIX = "apple";

private final WithdrawalReasonRepository withdrawalReasonRepository;
private final DiscordMessageClient discordMessageClient;
private final AppleService appleService;
private final FeedRepository feedRepository;
private final UserRepository userRepository;
private final CommentRepository commentRepository;
private final RefreshTokenRepository refreshTokenRepository;
private final KakaoService kakaoService;

public void withdrawUser(User user, WithdrawalRequest withdrawalRequest) {
unlinkSocialAccount(user);

String messageContent = MessageFormatter.formatUserWithdrawMessage(user.getUserId(), user.getNickname(),
withdrawalRequest.reason());

cleanupUserData(user.getUserId());

discordMessageClient.sendDiscordWebhookMessage(
DiscordWebhookMessage.of(messageContent, WITHDRAW));

withdrawalReasonRepository.save(WithdrawalReason.create(withdrawalRequest.reason()));
}

private void unlinkSocialAccount(User user) {
if (user.getSocialId().startsWith(KAKAO_PREFIX)) {
kakaoService.unlinkFromKakao(user);
} else if (user.getSocialId().startsWith(APPLE_PREFIX)) {
appleService.unlinkFromApple(user);
}
}

private void cleanupUserData(Long userId) {
refreshTokenRepository.deleteAll(refreshTokenRepository.findAllByUserId(userId));
feedRepository.updateUserToUnknown(userId);
commentRepository.updateUserToUnknown(userId);
userRepository.deleteById(userId);
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.websoso.WSSServer.user.service;
package org.websoso.WSSServer.application;

import static org.websoso.WSSServer.exception.error.CustomAuthError.INVALID_TOKEN;

Expand All @@ -9,19 +9,28 @@
import org.websoso.WSSServer.config.jwt.JWTUtil;
import org.websoso.WSSServer.config.jwt.JwtProvider;
import org.websoso.WSSServer.config.jwt.JwtValidationType;
import org.websoso.WSSServer.user.domain.RefreshToken;
import org.websoso.WSSServer.dto.auth.LogoutRequest;
import org.websoso.WSSServer.dto.auth.ReissueResponse;
import org.websoso.WSSServer.dto.user.LoginResponse;
import org.websoso.WSSServer.exception.exception.CustomAuthException;
import org.websoso.WSSServer.oauth2.service.KakaoService;
import org.websoso.WSSServer.repository.RefreshTokenRepository;
import org.websoso.WSSServer.user.domain.RefreshToken;
import org.websoso.WSSServer.user.domain.User;
import org.websoso.WSSServer.user.repository.UserDeviceRepository;
import org.websoso.WSSServer.user.service.UserService;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AuthService {

public class AuthApplication {
private final JwtProvider jwtProvider;
private final JWTUtil jwtUtil;
private final RefreshTokenRepository refreshTokenRepository;
private final UserDeviceRepository userDeviceRepository;
private final UserService userService;
private final KakaoService kakaoService;
private static final String KAKAO_PREFIX = "kakao";
private static final String APPLE_PREFIX = "apple";

public ReissueResponse reissue(String refreshToken) {
RefreshToken storedRefreshToken = refreshTokenRepository.findByRefreshToken(refreshToken)
Expand All @@ -41,4 +50,27 @@ public ReissueResponse reissue(String refreshToken) {

return ReissueResponse.of(newAccessToken, newRefreshToken);
}

// TODO: getUserOrException -> existUserOrException 변경
@Transactional(readOnly = true)
public LoginResponse login(Long userId) {
User user = userService.getUserOrException(userId);

CustomAuthenticationToken customAuthenticationToken = new CustomAuthenticationToken(user.getUserId(), null,
null);
String token = jwtProvider.generateAccessToken(customAuthenticationToken);

return LoginResponse.of(token);
}

public void logout(User user, LogoutRequest request) {
refreshTokenRepository.findByRefreshToken(request.refreshToken())
.ifPresent(refreshTokenRepository::delete);

userDeviceRepository.deleteByUserAndDeviceIdentifier(user, request.deviceIdentifier());

if (user.getSocialId().startsWith(KAKAO_PREFIX)) {
kakaoService.kakaoLogout(user);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,23 @@
import org.websoso.WSSServer.dto.user.WithdrawalRequest;
import org.websoso.WSSServer.oauth2.service.AppleService;
import org.websoso.WSSServer.oauth2.service.KakaoService;
import org.websoso.WSSServer.user.service.AuthService;
import org.websoso.WSSServer.user.service.UserService;
import org.websoso.WSSServer.application.AccountApplication;
import org.websoso.WSSServer.application.AuthApplication;

@RestController
@RequiredArgsConstructor
public class AuthController {

private final AuthService authService;
private final AuthApplication authApplication;
private final KakaoService kakaoService;
private final AppleService appleService;
private final UserService userService;
private final AccountApplication accountApplication;

@PostMapping("/reissue")
public ResponseEntity<ReissueResponse> reissue(@RequestBody ReissueRequest reissueRequest) {
return ResponseEntity
.status(OK)
.body(authService.reissue(reissueRequest.refreshToken()));
.body(authApplication.reissue(reissueRequest.refreshToken()));
}

@PostMapping("/auth/login/kakao")
Expand All @@ -58,7 +58,7 @@ public ResponseEntity<AuthResponse> loginByApple(@Valid @RequestBody AppleLoginR
@PreAuthorize("isAuthenticated()")
public ResponseEntity<Void> logout(@AuthenticationPrincipal User user,
@Valid @RequestBody LogoutRequest request) {
userService.logout(user, request);
authApplication.logout(user, request);
return ResponseEntity
.status(NO_CONTENT)
.build();
Expand All @@ -68,7 +68,7 @@ public ResponseEntity<Void> logout(@AuthenticationPrincipal User user,
@PreAuthorize("isAuthenticated()")
public ResponseEntity<Void> withdrawUser(@AuthenticationPrincipal User user,
@Valid @RequestBody WithdrawalRequest withdrawalRequest) {
userService.withdrawUser(user, withdrawalRequest);
accountApplication.withdrawUser(user, withdrawalRequest);
return ResponseEntity
.status(NO_CONTENT)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.websoso.WSSServer.application.AuthApplication;
import org.websoso.WSSServer.user.domain.User;
import org.websoso.WSSServer.domain.common.SortCriteria;
import org.websoso.WSSServer.dto.feed.UserFeedsGetResponse;
Expand Down Expand Up @@ -58,11 +59,12 @@ public class UserController {

private final UserService userService;
private final UserNovelService userNovelService;
private final AuthApplication authApplication;
private final FeedService feedService;

@PostMapping("/login")
public ResponseEntity<LoginResponse> login(@RequestBody String userId) {
LoginResponse response = userService.login(Long.valueOf(userId));
LoginResponse response = authApplication.login(Long.valueOf(userId));
return ResponseEntity
.status(OK)
.body(response);
Expand Down
84 changes: 13 additions & 71 deletions src/main/java/org/websoso/WSSServer/user/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,13 @@
public class UserService {

private final UserRepository userRepository;
private final JwtProvider jwtProvider;
private final AvatarRepository avatarRepository;
private final GenrePreferenceRepository genrePreferenceRepository;
private final GenreRepository genreRepository;
private final RefreshTokenRepository refreshTokenRepository;
private final KakaoService kakaoService;
private final AppleService appleService;
private final FeedRepository feedRepository;
private final CommentRepository commentRepository;
private final DiscordMessageClient discordMessageClient;
private final WithdrawalReasonRepository withdrawalReasonRepository;
private final UserDeviceRepository userDeviceRepository;
private static final String KAKAO_PREFIX = "kakao";
private static final String APPLE_PREFIX = "apple";

// TODO: 상위 레이어에서 분리 예정
private final DiscordMessageClient discordMessageClient;

@Transactional(readOnly = true)
public NicknameValidation isNicknameAvailable(User user, String nickname) {
Expand All @@ -94,17 +87,6 @@ public NicknameValidation isNicknameAvailable(User user, String nickname) {
return NicknameValidation.of(true);
}

@Transactional(readOnly = true)
public LoginResponse login(Long userId) {
User user = getUserOrException(userId);

CustomAuthenticationToken customAuthenticationToken = new CustomAuthenticationToken(user.getUserId(), null,
null);
String token = jwtProvider.generateAccessToken(customAuthenticationToken);

return LoginResponse.of(token);
}

@Transactional(readOnly = true)
public UserInfoGetResponse getUserInfo(User user) {
return UserInfoGetResponse.of(user);
Expand Down Expand Up @@ -155,6 +137,16 @@ public void updateMyProfileInfo(User user, UpdateMyProfileRequest updateMyProfil
user.updateUserProfile(updateMyProfileRequest);
}

public void registerUserInfo(User user, RegisterUserInfoRequest registerUserInfoRequest) {
checkNicknameIfAlreadyExist(registerUserInfoRequest.nickname());
user.updateUserInfo(registerUserInfoRequest);
List<GenrePreference> preferGenres = createGenrePreferences(user, registerUserInfoRequest.genrePreferences());
genrePreferenceRepository.saveAll(preferGenres);

discordMessageClient.sendDiscordWebhookMessage(DiscordWebhookMessage.of(
MessageFormatter.formatUserJoinMessage(user, SocialLoginType.fromSocialId(user.getSocialId())), JOIN));
}

@Transactional(readOnly = true)
public ProfileGetResponse getProfileInfo(User visitor, Long ownerId) {
if (ownerId == -1L) {
Expand All @@ -176,41 +168,6 @@ private Avatar findAvatarByIdOrThrow(Byte avatarId) {
() -> new CustomAvatarException(AVATAR_NOT_FOUND, "avatar with the given id was not found"));
}

public void registerUserInfo(User user, RegisterUserInfoRequest registerUserInfoRequest) {
checkNicknameIfAlreadyExist(registerUserInfoRequest.nickname());
user.updateUserInfo(registerUserInfoRequest);
List<GenrePreference> preferGenres = createGenrePreferences(user, registerUserInfoRequest.genrePreferences());
genrePreferenceRepository.saveAll(preferGenres);

discordMessageClient.sendDiscordWebhookMessage(DiscordWebhookMessage.of(
MessageFormatter.formatUserJoinMessage(user, SocialLoginType.fromSocialId(user.getSocialId())), JOIN));
}

public void logout(User user, LogoutRequest request) {
refreshTokenRepository.findByRefreshToken(request.refreshToken())
.ifPresent(refreshTokenRepository::delete);

userDeviceRepository.deleteByUserAndDeviceIdentifier(user, request.deviceIdentifier());

if (user.getSocialId().startsWith(KAKAO_PREFIX)) {
kakaoService.kakaoLogout(user);
}
}

public void withdrawUser(User user, WithdrawalRequest withdrawalRequest) {
unlinkSocialAccount(user);

String messageContent = MessageFormatter.formatUserWithdrawMessage(user.getUserId(), user.getNickname(),
withdrawalRequest.reason());

cleanupUserData(user.getUserId());

discordMessageClient.sendDiscordWebhookMessage(
DiscordWebhookMessage.of(messageContent, WITHDRAW));

withdrawalReasonRepository.save(WithdrawalReason.create(withdrawalRequest.reason()));
}

private void checkNicknameIfAlreadyExist(String nickname) {
if (userRepository.existsByNickname(nickname)) {
throw new CustomUserException(DUPLICATED_NICKNAME, "nickname is duplicated.");
Expand Down Expand Up @@ -238,21 +195,6 @@ private Genre findByGenreNameOrThrow(String genreName) {
new CustomGenreException(GENRE_NOT_FOUND, "genre with the given genreName is not found"));
}

private void unlinkSocialAccount(User user) {
if (user.getSocialId().startsWith(KAKAO_PREFIX)) {
kakaoService.unlinkFromKakao(user);
} else if (user.getSocialId().startsWith(APPLE_PREFIX)) {
appleService.unlinkFromApple(user);
}
}

private void cleanupUserData(Long userId) {
refreshTokenRepository.deleteAll(refreshTokenRepository.findAllByUserId(userId));
feedRepository.updateUserToUnknown(userId);
commentRepository.updateUserToUnknown(userId);
userRepository.deleteById(userId);
}

public void editMyInfo(User user, EditMyInfoRequest editMyInfoRequest) {
user.editMyInfo(editMyInfoRequest);
}
Expand Down