diff --git a/src/main/java/org/ezcode/codetest/application/usermanagement/auth/service/AuthService.java b/src/main/java/org/ezcode/codetest/application/usermanagement/auth/service/AuthService.java index cc3d6c71..f7614d5b 100644 --- a/src/main/java/org/ezcode/codetest/application/usermanagement/auth/service/AuthService.java +++ b/src/main/java/org/ezcode/codetest/application/usermanagement/auth/service/AuthService.java @@ -16,6 +16,8 @@ import org.ezcode.codetest.application.usermanagement.user.dto.response.ChangeUserPasswordResponse; import org.ezcode.codetest.application.usermanagement.user.dto.response.LogoutResponse; import org.ezcode.codetest.application.usermanagement.user.dto.response.VerifyFindPasswordResponse; +import org.ezcode.codetest.domain.language.model.entity.Language; +import org.ezcode.codetest.domain.language.service.LanguageDomainService; import org.ezcode.codetest.domain.user.exception.AuthException; import org.ezcode.codetest.domain.user.exception.UserException; import org.ezcode.codetest.domain.user.exception.code.AuthExceptionCode; @@ -41,6 +43,7 @@ public class AuthService { private final UserDomainService userDomainService; + private final LanguageDomainService languageDomainService; private final JwtUtil jwtUtil; private final RedisTemplate redisTemplate; private final MailService mailService; @@ -80,12 +83,14 @@ private void userRegisterationProcess(SignupRequest request) { //3. 만약 아예 첫 가입 유저일 때 private void createNewUser(SignupRequest request, String encodedPassword) { String nickname = userDomainService.generateUniqueNickname(); + Language language = languageDomainService.getLanguage(1L); //기본적으로 1번 언어로 가입 시 세팅 User newUser = User.emailUser( request.getEmail(), encodedPassword, request.getUsername(), nickname, - request.getAge() + request.getAge(), + language ); userDomainService.createUser(newUser); diff --git a/src/main/java/org/ezcode/codetest/application/usermanagement/user/dto/request/ModifyUserInfoRequest.java b/src/main/java/org/ezcode/codetest/application/usermanagement/user/dto/request/ModifyUserInfoRequest.java index 6666fed7..d35bb9da 100644 --- a/src/main/java/org/ezcode/codetest/application/usermanagement/user/dto/request/ModifyUserInfoRequest.java +++ b/src/main/java/org/ezcode/codetest/application/usermanagement/user/dto/request/ModifyUserInfoRequest.java @@ -17,6 +17,9 @@ public record ModifyUserInfoRequest( String introduction, @Schema(description = "나이", example = "28") - Integer age + Integer age, + + @Schema(description = "언어 id", example = "1") + Long languageId ) { } diff --git a/src/main/java/org/ezcode/codetest/application/usermanagement/user/dto/response/UserInfoResponse.java b/src/main/java/org/ezcode/codetest/application/usermanagement/user/dto/response/UserInfoResponse.java index daf52921..5ffaa5b1 100644 --- a/src/main/java/org/ezcode/codetest/application/usermanagement/user/dto/response/UserInfoResponse.java +++ b/src/main/java/org/ezcode/codetest/application/usermanagement/user/dto/response/UserInfoResponse.java @@ -1,6 +1,10 @@ package org.ezcode.codetest.application.usermanagement.user.dto.response; +import java.util.List; + +import org.ezcode.codetest.domain.language.model.entity.Language; import org.ezcode.codetest.domain.user.model.entity.User; +import org.ezcode.codetest.domain.user.model.enums.AuthType; import org.ezcode.codetest.domain.user.model.enums.Tier; import org.ezcode.codetest.domain.user.model.enums.UserRole; @@ -47,10 +51,18 @@ public class UserInfoResponse { @Schema(description = "사용자가 푼 문제 총 개수", example = "1235") private final int totalSolvedCount; + @Schema(description = "사용자가 선택한 언어. 기본적으로 1번 언어로 세팅됩니다", example = "1") + private final Language language; + + @Schema(description = "사용자가 가입한 경로(자체/소셜)의 리스트를 보여줍니다", example = "[GOOGLE, GITHUB, EMAIL]") + private final List userAuthTypes; + @Builder public UserInfoResponse(String username, String email, String nickname, UserRole userRole, Tier tier, Integer age, String githubUrl, String blogUrl, String profileImageUrl, String introduction, boolean verified, - int totalSolvedCount) { + int totalSolvedCount, + Language language, + List userAuthTypes) { this.username = username; this.email = email; this.nickname = nickname; @@ -63,6 +75,8 @@ public UserInfoResponse(String username, String email, String nickname, UserRole this.userRole = userRole; this.verified = verified; this.totalSolvedCount = totalSolvedCount; + this.language = language; + this.userAuthTypes = userAuthTypes; } public static UserInfoResponse fromEntity(User user) { diff --git a/src/main/java/org/ezcode/codetest/application/usermanagement/user/service/UserService.java b/src/main/java/org/ezcode/codetest/application/usermanagement/user/service/UserService.java index bef271dc..12ac6715 100644 --- a/src/main/java/org/ezcode/codetest/application/usermanagement/user/service/UserService.java +++ b/src/main/java/org/ezcode/codetest/application/usermanagement/user/service/UserService.java @@ -3,12 +3,15 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.List; +import java.util.stream.Collectors; import org.ezcode.codetest.application.usermanagement.user.dto.response.GrantAdminRoleResponse; import org.ezcode.codetest.application.usermanagement.user.dto.response.UserDailySolvedHistoryResponse; import org.ezcode.codetest.application.usermanagement.user.dto.response.UserProfileImageResponse; import org.ezcode.codetest.application.usermanagement.user.dto.response.UserReviewTokenResponse; import org.ezcode.codetest.application.usermanagement.user.model.UsersByWeek; +import org.ezcode.codetest.domain.language.model.entity.Language; +import org.ezcode.codetest.domain.language.service.LanguageDomainService; import org.ezcode.codetest.domain.submission.dto.DailyCorrectCount; import org.ezcode.codetest.domain.submission.dto.WeeklySolveCount; import org.ezcode.codetest.application.usermanagement.user.dto.request.ChangeUserPasswordRequest; @@ -23,6 +26,7 @@ import org.ezcode.codetest.domain.user.exception.code.UserExceptionCode; import org.ezcode.codetest.domain.user.model.entity.AuthUser; import org.ezcode.codetest.domain.user.model.entity.User; +import org.ezcode.codetest.domain.user.model.entity.UserAuthType; import org.ezcode.codetest.domain.user.model.enums.AuthType; import org.ezcode.codetest.domain.user.model.enums.UserRole; import org.ezcode.codetest.domain.user.service.MailService; @@ -46,6 +50,7 @@ public class UserService { private final UserDomainService userDomainService; + private final LanguageDomainService languageDomainService; private final SubmissionDomainService submissionDomainService; private final RedisTemplate redisTemplate; private final S3Uploader s3Uploader; @@ -55,6 +60,9 @@ public UserInfoResponse getUserInfo(AuthUser authUser) { log.info("authUserEmail: {}, authUserID : {}", authUser.getEmail(), authUser.getId()); User user = userDomainService.getUserById(authUser.getId()); int userSubmissionCount = submissionDomainService.findSubmissionCountByUserId(user.getId()); + List userAuthTypes = userDomainService.getUserAuthTypesByUser(user); + List authTypes = userAuthTypes.stream() + .map(UserAuthType::getAuthType).toList(); return UserInfoResponse.builder() .username(user.getUsername()) @@ -69,19 +77,23 @@ public UserInfoResponse getUserInfo(AuthUser authUser) { .tier(user.getTier()) .verified(user.isVerified()) .totalSolvedCount(userSubmissionCount) + .language(user.getLanguage()) + .userAuthTypes(authTypes) .build(); } @Transactional public UserInfoResponse modifyUserInfo(AuthUser authUser, ModifyUserInfoRequest request, MultipartFile image) { User user = userDomainService.getUserById(authUser.getId()); + Language findLangauge = languageDomainService.getLanguage(request.languageId()); user.modifyUserInfo( request.nickname(), request.githubUrl(), request.blogUrl(), request.introduction(), - request.age()); + request.age(), + findLangauge); if (image != null && !image.isEmpty()) { String profileImageUrl = uploadProfileImage(image); @@ -105,6 +117,7 @@ public UserInfoResponse modifyUserInfo(AuthUser authUser, ModifyUserInfoRequest .githubUrl(user.getGithubUrl()) .userRole(user.getRole()) .tier(user.getTier()) + .language(user.getLanguage()) .build(); } diff --git a/src/main/java/org/ezcode/codetest/domain/user/model/entity/User.java b/src/main/java/org/ezcode/codetest/domain/user/model/entity/User.java index 14dc2333..34757119 100644 --- a/src/main/java/org/ezcode/codetest/domain/user/model/entity/User.java +++ b/src/main/java/org/ezcode/codetest/domain/user/model/entity/User.java @@ -4,12 +4,12 @@ import java.util.List; import org.ezcode.codetest.common.base.entity.BaseEntity; +import org.ezcode.codetest.domain.language.model.entity.Language; import org.ezcode.codetest.domain.user.model.enums.Tier; import org.ezcode.codetest.domain.user.model.enums.UserRole; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; -import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; @@ -17,7 +17,10 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.Builder; @@ -72,17 +75,20 @@ public class User extends BaseEntity { @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private List userAuthTypes = new ArrayList<>(); + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "language_id") + private Language language; + private boolean verified; //이메일 인증 여부 private boolean gitPushStatus; //깃허브 자동 push 여부 - /* 처음 유저 생성(가입) 시에는 기본 정보만 받음 - 이메일, 비번, 이름, 별명, 나이 -> 이후 회원정보 업데이트할 때, 원하는 정보를 입력할 수 있도록 함 */ - public static User emailUser(String email, String password, String username, String nickname, Integer age){ + public static User emailUser(String email, String password, String username, String nickname, Integer age, Language language) { return User.builder() .email(email) .password(password) @@ -94,6 +100,7 @@ public static User emailUser(String email, String password, String username, Str .isDeleted(false) .verified(false) .gitPushStatus(false) + .language(language) .build(); } @@ -101,7 +108,7 @@ public static User emailUser(String email, String password, String username, Str OAuth2로 로그인한 유저 저장 구글 이외의 다른 소셜 로그인 확장 가능성을 고려해 socialUser 이름 유지 */ - public static User socialUser(String email, String username, String nickname, String password){ + public static User socialUser(String email, String username, String nickname, String password, Language language) { return User.builder() .email(email) .username(username) @@ -112,11 +119,12 @@ public static User socialUser(String email, String username, String nickname, St .isDeleted(false) .verified(false) .gitPushStatus(false) + .language(language) .build(); } //깃허브 아이디와 url을 함께 저장하기 위해 따로 저장 - public static User githubUser(String email, String username, String nickname, String password, String githubUrl){ + public static User githubUser(String email, String username, String nickname, String password, String githubUrl, Language language){ return User.builder() .email(email) .username(username) @@ -128,13 +136,14 @@ public static User githubUser(String email, String username, String nickname, St .verified(false) .githubUrl(githubUrl) .gitPushStatus(false) + .language(language) .build(); } @Builder public User(String email, String password, String username, String nickname, - Integer age, Tier tier, UserRole role, boolean isDeleted, boolean verified, String githubUrl, boolean gitPushStatus) { + Integer age, Tier tier, UserRole role, boolean isDeleted, boolean verified, String githubUrl, boolean gitPushStatus, Language language) { this.email = email; this.password = password; this.username = username; @@ -146,18 +155,20 @@ public User(String email, String password, String username, String nickname, this.verified = verified; this.githubUrl = githubUrl; this.gitPushStatus = gitPushStatus; + this.language = language; } /* 유저 정보 업데이트 - 만약 입력 값이 없다면, 기존 값 유지 */ - public void modifyUserInfo(String nickname, String githubUrl, String blogUrl, String introduction, Integer age){ + public void modifyUserInfo(String nickname, String githubUrl, String blogUrl, String introduction, Integer age, Language language) { this.nickname = (nickname == null || nickname.isBlank()) ? this.nickname : nickname; this.githubUrl = (githubUrl == null || githubUrl.isBlank()) ? this.githubUrl : githubUrl; this.blogUrl = (blogUrl == null || blogUrl.isBlank()) ? this.blogUrl : blogUrl; this.introduction = (introduction == null || introduction.isBlank()) ? this.introduction : introduction; this.age = (age == null) ? this.age : age; + this.language = (language == null) ? this.language : language; } diff --git a/src/main/java/org/ezcode/codetest/domain/user/model/entity/UserFactory.java b/src/main/java/org/ezcode/codetest/domain/user/model/entity/UserFactory.java index 5eb316c3..7222eb94 100644 --- a/src/main/java/org/ezcode/codetest/domain/user/model/entity/UserFactory.java +++ b/src/main/java/org/ezcode/codetest/domain/user/model/entity/UserFactory.java @@ -3,12 +3,14 @@ import java.util.UUID; import org.ezcode.codetest.application.usermanagement.user.dto.response.OAuth2Response; +import org.ezcode.codetest.domain.language.model.entity.Language; public class UserFactory { public static User createSocialUser( OAuth2Response response, String nickname, - String provider + String provider, + Language language ) { //나중에 확장성 고려해서 switch문 사용 return switch (provider.toLowerCase()) { @@ -18,13 +20,16 @@ public static User createSocialUser( response.getName(), nickname, UUID.randomUUID().toString(), - response.getGithubUrl() + response.getGithubUrl(), + language + ); default -> User.socialUser( response.getEmail(), response.getName(), nickname, - UUID.randomUUID().toString() + UUID.randomUUID().toString(), + language ); }; } diff --git a/src/main/java/org/ezcode/codetest/domain/user/repository/UserAuthTypeRepository.java b/src/main/java/org/ezcode/codetest/domain/user/repository/UserAuthTypeRepository.java index 740cf906..779e2755 100644 --- a/src/main/java/org/ezcode/codetest/domain/user/repository/UserAuthTypeRepository.java +++ b/src/main/java/org/ezcode/codetest/domain/user/repository/UserAuthTypeRepository.java @@ -10,4 +10,6 @@ public interface UserAuthTypeRepository { void createUserAuthType(UserAuthType userAuthType); List getUserAuthType(User user); + + List getUserAuthTypesByUser(User user); } diff --git a/src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.java b/src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.java index f70aaecf..f6378add 100644 --- a/src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.java +++ b/src/main/java/org/ezcode/codetest/domain/user/service/CustomOAuth2UserService.java @@ -5,6 +5,8 @@ import org.ezcode.codetest.application.usermanagement.user.dto.response.GithubOAuth2Response; import org.ezcode.codetest.application.usermanagement.user.dto.response.GoogleOAuth2Response; import org.ezcode.codetest.application.usermanagement.user.dto.response.OAuth2Response; +import org.ezcode.codetest.domain.language.model.entity.Language; +import org.ezcode.codetest.domain.language.service.LanguageDomainService; import org.ezcode.codetest.domain.user.exception.UserException; import org.ezcode.codetest.domain.user.exception.code.UserExceptionCode; import org.ezcode.codetest.domain.user.model.entity.CustomOAuth2User; @@ -33,6 +35,7 @@ public class CustomOAuth2UserService extends DefaultOAuth2UserService { private final UserRepository userRepository; private final UserAuthTypeRepository userAuthTypeRepository; private final UserDomainService userDomainService; + private final LanguageDomainService languageDomainService; private final UserGithubService userGithubService; @Override @@ -82,7 +85,8 @@ private void processUser( private void createNewUser(OAuth2Response response, AuthType authType, String provider) { String nickname = userDomainService.generateUniqueNickname(); - User newUser = UserFactory.createSocialUser(response, nickname, provider); + Language language = languageDomainService.getLanguage(1L); //기본적으로 1번 언어로 가입 시 세팅 + User newUser = UserFactory.createSocialUser(response, nickname, provider, language); newUser.setVerified(); newUser.setReviewToken(20); userRepository.createUser(newUser); diff --git a/src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.java b/src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.java index 7764d2a5..d3fcf3d4 100644 --- a/src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.java +++ b/src/main/java/org/ezcode/codetest/domain/user/service/UserDomainService.java @@ -128,5 +128,8 @@ public User getUserByEmail(String email) { return userRepository.getUserByEmail(email); } + public List getUserAuthTypesByUser(User user) { + return userAuthTypeRepository.getUserAuthTypesByUser(user); + } } diff --git a/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/user/UserAuthTypeRepositoryImpl.java b/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/user/UserAuthTypeRepositoryImpl.java index 25cfba06..84d38c9a 100644 --- a/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/user/UserAuthTypeRepositoryImpl.java +++ b/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/user/UserAuthTypeRepositoryImpl.java @@ -27,4 +27,11 @@ public List getUserAuthType(User user) { .map(UserAuthType::getAuthType).toList(); } + @Override + public List getUserAuthTypesByUser(User user) { + userAuthTypeJpaRepository.findUserAuthTypeByUser(user).stream() + .map(UserAuthType::getAuthType).toList(); + return List.of(); + } + } diff --git a/src/main/java/org/ezcode/codetest/presentation/usermanagement/UserController.java b/src/main/java/org/ezcode/codetest/presentation/usermanagement/UserController.java index 7cb2cc30..3a844206 100644 --- a/src/main/java/org/ezcode/codetest/presentation/usermanagement/UserController.java +++ b/src/main/java/org/ezcode/codetest/presentation/usermanagement/UserController.java @@ -1,5 +1,6 @@ package org.ezcode.codetest.presentation.usermanagement; +import org.ezcode.codetest.application.submission.dto.response.language.LanguageResponse; import org.ezcode.codetest.application.usermanagement.user.dto.request.ModifyUserInfoRequest; import org.ezcode.codetest.application.usermanagement.user.dto.request.ChangeUserPasswordRequest; import org.ezcode.codetest.application.usermanagement.user.dto.response.ChangeUserPasswordResponse; @@ -16,13 +17,9 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @@ -99,5 +96,4 @@ public ResponseEntity getUserDailySolvedHistory( ){ return ResponseEntity.status(HttpStatus.OK).body(userService.getUserDailySolvedHistory(authUser)); } - } diff --git a/src/test/java/org/ezcode/codetest/application/problem/service/ProblemServiceTest.java b/src/test/java/org/ezcode/codetest/application/problem/service/ProblemServiceTest.java index 632aa12b..9c0a20e5 100644 --- a/src/test/java/org/ezcode/codetest/application/problem/service/ProblemServiceTest.java +++ b/src/test/java/org/ezcode/codetest/application/problem/service/ProblemServiceTest.java @@ -15,6 +15,7 @@ import org.ezcode.codetest.application.problem.dto.response.ProblemResponse; import org.ezcode.codetest.domain.game.model.character.CategoryStat; import org.ezcode.codetest.domain.game.util.StatUpdateUtil; +import org.ezcode.codetest.domain.language.model.entity.Language; import org.ezcode.codetest.domain.problem.model.ProblemSearchCondition; import org.ezcode.codetest.domain.problem.model.entity.Category; import org.ezcode.codetest.domain.problem.model.entity.Problem; @@ -58,6 +59,7 @@ class ProblemServiceTest { @InjectMocks private ProblemService problemService; + @Test @DisplayName("카테고리 생성") void createCategory() { @@ -79,11 +81,11 @@ void createCategory() { @Test @DisplayName("문제 생성 요청 시 유저 조회 및 문제 도메인 저장") void createProblem_shouldCreateWithoutImage() { + Language language = new Language("java", "17", 30L); // given AuthUser auth = new AuthUser(1L, "test", "test", "test@test", UserRole.ADMIN, Tier.NEWBIE); - User user = new User("test@test", "test", "test1", "test1", 13, - Tier.NEWBIE, UserRole.ADMIN, false, false, "testurl", false); + Tier.NEWBIE, UserRole.ADMIN, false, false, "testurl", false, language); ProblemCreateRequest request = new ProblemCreateRequest( Map.of("Math", "수학"), diff --git a/src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java b/src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java index 2cc43a11..d92905f8 100644 --- a/src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java +++ b/src/test/java/org/ezcode/codetest/domain/user/UserDomainServiceTest.java @@ -1,10 +1,10 @@ package org.ezcode.codetest.domain.user; import org.ezcode.codetest.common.security.util.PasswordEncoder; +import org.ezcode.codetest.domain.language.model.entity.Language; +import org.ezcode.codetest.domain.language.service.LanguageDomainService; import org.ezcode.codetest.domain.user.exception.AuthException; -import org.ezcode.codetest.domain.user.exception.UserException; import org.ezcode.codetest.domain.user.exception.code.AuthExceptionCode; -import org.ezcode.codetest.domain.user.exception.code.UserExceptionCode; import org.ezcode.codetest.domain.user.model.entity.User; import org.ezcode.codetest.domain.user.model.entity.UserAuthType; import org.ezcode.codetest.domain.user.model.enums.AuthType; @@ -37,10 +37,14 @@ public class UserDomainServiceTest { @Mock private PasswordEncoder passwordEncoder; - @InjectMocks private UserDomainService userDomainService; + private final Language language = Language.builder() + .judge0Id(30L) + .name("java") + .version("17").build(); + // 테스트 유저 정보 설정 private final User testUser = new User( "test@example.com", @@ -53,7 +57,8 @@ public class UserDomainServiceTest { false, // isDeleted true, // verified "https://github.com/test", - false // gitPushStatus + false, // gitPushStatus + language ) { public Long getId() { return 1L; } public int getReviewToken() { return 5; } @@ -162,7 +167,7 @@ void passwordComparison_shouldPassWhenDifferent() { @Test void isDeletedUser_shouldThrowWhenDeleted() { User deletedUser = new User("email@gmail.com","Aa12345**", "username", - "full@week.com", 100, Tier.CODER, UserRole.USER, true, true, "gitUrl.com", true); + "full@week.com", 100, Tier.CODER, UserRole.USER, true, true, "gitUrl.com", true, language); assertThrows(AuthException.class, () -> userDomainService.isDeletedUser(deletedUser)); }