Skip to content

Commit 82fe597

Browse files
authored
Merge pull request #325 from CSE-Shaco/develop
feat: normalize and migrate majors to codes
2 parents bcca779 + ffcceba commit 82fe597

8 files changed

Lines changed: 352 additions & 7 deletions

File tree

src/main/java/inha/gdgoc/domain/auth/service/AuthService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import inha.gdgoc.global.config.jwt.TokenProvider;
2222
import inha.gdgoc.global.config.jwt.TokenProvider.CustomUserDetails;
2323
import inha.gdgoc.global.security.AccessGuard;
24+
import inha.gdgoc.global.util.MajorNormalizer;
2425
import java.io.IOException;
2526
import java.security.GeneralSecurityException;
2627
import java.time.Duration;
@@ -51,6 +52,7 @@ public class AuthService {
5152
private final StringRedisTemplate redisTemplate;
5253
private final AccessGuard accessGuard;
5354
private final PasswordEncoder passwordEncoder;
55+
private final MajorNormalizer majorNormalizer;
5456

5557
@Value("${google.client-id}")
5658
private String googleClientId;
@@ -112,7 +114,7 @@ public LoginSuccessResponse signup(SignupRequest request) {
112114
.email(request.getEmail())
113115
.name(request.getName())
114116
.studentId(request.getStudentId())
115-
.major(request.getMajor())
117+
.major(majorNormalizer.normalize(request.getMajor()))
116118
.phoneNumber(cleanPhone)
117119
.image(request.getImage())
118120
// Role(GUEST), Status(PENDING) 등은 User 엔티티 생성자에서 기본값 처리됨

src/main/java/inha/gdgoc/domain/game/service/GameUserService.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import inha.gdgoc.domain.game.dto.response.GameUserResponse;
55
import inha.gdgoc.domain.game.entity.GameUser;
66
import inha.gdgoc.domain.game.repository.GameUserRepository;
7+
import inha.gdgoc.global.util.MajorNormalizer;
78
import jakarta.transaction.Transactional;
89
import java.time.LocalDate;
910
import java.time.LocalDateTime;
@@ -18,11 +19,18 @@
1819
public class GameUserService {
1920

2021
private final GameUserRepository gameUserRepository;
22+
private final MajorNormalizer majorNormalizer;
2123

2224
@Transactional
2325
public List<GameUserResponse> saveGameResultAndGetRanking(GameUserRequest gameUserRequest) {
2426
// 유저 정보 저장
25-
GameUser gameUser = gameUserRequest.toEntity();
27+
GameUser gameUser = GameUser.builder()
28+
.name(gameUserRequest.getName())
29+
.major(majorNormalizer.normalize(gameUserRequest.getMajor()))
30+
.studentId(gameUserRequest.getStudentId())
31+
.phoneNumber(gameUserRequest.getPhoneNumber())
32+
.typingSpeed(gameUserRequest.getTypingSpeed())
33+
.build();
2634
gameUserRepository.save(gameUser);
2735

2836
return findUserRankings();

src/main/java/inha/gdgoc/domain/recruit/core/service/RecruitCoreApplicationService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import inha.gdgoc.domain.user.repository.UserRepository;
1919
import inha.gdgoc.global.exception.BusinessException;
2020
import inha.gdgoc.global.exception.GlobalErrorCode;
21+
import inha.gdgoc.global.util.MajorNormalizer;
2122
import java.time.Instant;
2223
import java.util.List;
2324
import lombok.RequiredArgsConstructor;
@@ -33,6 +34,7 @@ public class RecruitCoreApplicationService {
3334
private final RecruitCoreApplicationRepository repository;
3435
private final UserRepository userRepository;
3536
private final RecruitCoreSessionResolver recruitCoreSessionResolver;
37+
private final MajorNormalizer majorNormalizer;
3638

3739
@Transactional(readOnly = true)
3840
public RecruitCoreApplicantDetailResponse getApplicantDetail(Long id) {
@@ -82,7 +84,7 @@ public RecruitCoreApplicationCreateResponse submit(Long userId, RecruitCoreAppli
8284
.name(request.snapshot().name())
8385
.studentId(request.snapshot().studentId())
8486
.phone(cleanPhone)
85-
.major(request.snapshot().major())
87+
.major(majorNormalizer.normalize(request.snapshot().major()))
8688
.email(request.snapshot().email())
8789
.team(request.team())
8890
.motivation(request.motivation())

src/main/java/inha/gdgoc/domain/recruit/member/dto/request/RecruitMemberRequest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import inha.gdgoc.domain.recruit.member.enums.AdmissionSemester;
66
import inha.gdgoc.domain.recruit.member.enums.EnrolledClassification;
77
import inha.gdgoc.domain.recruit.member.enums.Gender;
8+
import inha.gdgoc.global.util.MajorNormalizer;
89
import java.time.LocalDate;
910
import lombok.AllArgsConstructor;
1011
import lombok.Builder;
@@ -27,7 +28,7 @@ public class RecruitMemberRequest {
2728
private String major;
2829
private Boolean isPayed;
2930

30-
public RecruitMember toEntity(AdmissionSemester admissionSemester) {
31+
public RecruitMember toEntity(AdmissionSemester admissionSemester, MajorNormalizer majorNormalizer) {
3132
String cleanPhone = phoneNumber.replaceAll("[^0-9]", "");
3233
return RecruitMember.builder()
3334
.name(name)
@@ -37,7 +38,7 @@ public RecruitMember toEntity(AdmissionSemester admissionSemester) {
3738
.email(email)
3839
.gender(Gender.fromType(gender))
3940
.birth(birth)
40-
.major(major)
41+
.major(majorNormalizer.normalize(major))
4142
.isPayed(false)
4243
.admissionSemester(admissionSemester)
4344
.build();

src/main/java/inha/gdgoc/domain/recruit/member/service/RecruitMemberService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import inha.gdgoc.domain.recruit.member.repository.RecruitMemberMemoRepository;
2323
import inha.gdgoc.domain.recruit.member.repository.RecruitMemberRepository;
2424
import inha.gdgoc.global.util.SemesterCalculator;
25+
import inha.gdgoc.global.util.MajorNormalizer;
2526
import java.util.HashMap;
2627
import java.util.List;
2728
import java.util.Map;
@@ -41,6 +42,7 @@ public class RecruitMemberService {
4142
private final ObjectMapper objectMapper;
4243
private final SemesterCalculator semesterCalculator;
4344
private final S3Service s3Service;
45+
private final MajorNormalizer majorNormalizer;
4446

4547
@Transactional
4648
public void addRecruitMember(Map<String, Object> requestPayload, MultipartFile file) {
@@ -63,7 +65,7 @@ public void addRecruitMember(Map<String, Object> requestPayload, MultipartFile f
6365
}
6466

6567
RecruitMember member = memberRequest
66-
.toEntity(semesterCalculator.currentSemester());
68+
.toEntity(semesterCalculator.currentSemester(), majorNormalizer);
6769
recruitMemberRepository.save(member);
6870

6971
List<Answer> answerEntities = answers.entrySet().stream()

src/main/java/inha/gdgoc/domain/user/service/UserService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import inha.gdgoc.domain.user.entity.User;
1010
import inha.gdgoc.domain.user.exception.UserException;
1111
import inha.gdgoc.domain.user.repository.UserRepository;
12+
import inha.gdgoc.global.util.MajorNormalizer;
1213
import java.util.Optional;
1314
import lombok.RequiredArgsConstructor;
1415
import lombok.extern.slf4j.Slf4j;
@@ -22,6 +23,7 @@
2223
public class UserService {
2324

2425
private final UserRepository userRepository;
26+
private final MajorNormalizer majorNormalizer;
2527

2628
public CheckDuplicatedEmailResponse isExistsByEmail(CheckDuplicatedEmailRequest request) {
2729
return new CheckDuplicatedEmailResponse(userRepository.existsByEmail(request.email()));
@@ -35,7 +37,7 @@ public User findUserById(Long userId) {
3537
public FindIdResponse findId(FindIdRequest findIdRequest) {
3638
Optional<User> user = userRepository.findByNameAndMajorAndPhoneNumber(
3739
findIdRequest.getName(),
38-
findIdRequest.getMajor(),
40+
majorNormalizer.normalize(findIdRequest.getMajor()),
3941
findIdRequest.getPhoneNumber()
4042
);
4143

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package inha.gdgoc.global.util;
2+
3+
import java.util.Map;
4+
import java.util.Set;
5+
import org.springframework.stereotype.Component;
6+
7+
@Component
8+
public class MajorNormalizer {
9+
10+
private static final Map<String, String> LABEL_TO_CODE = Map.ofEntries(
11+
Map.entry("인공지능공학과", "AIE"),
12+
Map.entry("데이터사이언스학과", "DSE"),
13+
Map.entry("스마트모빌리티공학과", "SME"),
14+
Map.entry("디자인테크놀로지학과", "DTE"),
15+
Map.entry("컴퓨터공학과", "CSE"),
16+
Map.entry("기계공학과", "ME"),
17+
Map.entry("항공우주공학과", "AAE"),
18+
Map.entry("조선해양공학과", "NAE"),
19+
Map.entry("산업경영공학과", "IME"),
20+
Map.entry("화학공학과", "CHE"),
21+
Map.entry("고분자공학과", "PSE"),
22+
Map.entry("신소재공학과", "MSE"),
23+
Map.entry("사회인프라공학과", "CIE"),
24+
Map.entry("환경공학과", "ENVE"),
25+
Map.entry("공간정보공학과", "GIE"),
26+
Map.entry("건축학부(건축공학)", "ACE"),
27+
Map.entry("건축학부(건축학)", "ARCH"),
28+
Map.entry("에너지자원공학과", "ERE"),
29+
Map.entry("융합기술경영학부", "MOT"),
30+
Map.entry("전기전자공학부", "EEE"),
31+
Map.entry("반도체시스템공학과", "SSE"),
32+
Map.entry("이차전지융합학과", "BCE"),
33+
Map.entry("수학과", "MATH"),
34+
Map.entry("통계학과", "STAT"),
35+
Map.entry("물리학과", "PHYS"),
36+
Map.entry("화학과", "CHEM"),
37+
Map.entry("해양과학과", "OCS"),
38+
Map.entry("식품영양학과", "FNS"),
39+
Map.entry("경영학부(경영학과)", "BUS"),
40+
Map.entry("경영학부(파이낸스경영학과)", "FIN"),
41+
Map.entry("아태물류학부", "APL"),
42+
Map.entry("국제통상학과", "ITC"),
43+
Map.entry("조형예술학과", "FINEART"),
44+
Map.entry("디자인융합학과", "ID"),
45+
Map.entry("스포츠과학과", "SPORTS"),
46+
Map.entry("연극영화학과", "TFA"),
47+
Map.entry("의류디자인학과", "FD"),
48+
Map.entry("행정학과", "PAD"),
49+
Map.entry("정치외교학과", "POL"),
50+
Map.entry("미디어커뮤니케이션학과", "MCS"),
51+
Map.entry("경제학과", "ECON"),
52+
Map.entry("소비자학과", "CONS"),
53+
Map.entry("아동심리학과", "CPSY"),
54+
Map.entry("사회복지학과", "SW"),
55+
Map.entry("자유전공융합학부", "ULS"),
56+
Map.entry("공학융합학부", "ECS"),
57+
Map.entry("자연과학융합학부", "NCS"),
58+
Map.entry("경영융합학부", "BCONV"),
59+
Map.entry("사회과학융합학부", "SCS"),
60+
Map.entry("인문융합학부", "HCS"),
61+
Map.entry("한국어문학과", "KLL"),
62+
Map.entry("사학과", "HIST"),
63+
Map.entry("철학과", "PHIL"),
64+
Map.entry("중국학과", "CHIN"),
65+
Map.entry("일본언어문화학과", "JLC"),
66+
Map.entry("영미유럽인문융합학부", "ELH"),
67+
Map.entry("문화콘텐츠문화경영학과", "CCM"),
68+
Map.entry("메카트로닉스공학과", "MTE"),
69+
Map.entry("소프트웨어융합공학과", "SWE"),
70+
Map.entry("산업경영학과", "IMGT"),
71+
Map.entry("금융투자학과", "FI"),
72+
Map.entry("생명공학과", "BIOE"),
73+
Map.entry("바이오제약공학과", "BPE"),
74+
Map.entry("생명과학과", "BIOS"),
75+
Map.entry("첨단바이오의약학과", "ABM"),
76+
Map.entry("바이오식품공학과", "BFE"),
77+
Map.entry("IBT학과", "IBT"),
78+
Map.entry("ISE학과", "ISE"),
79+
Map.entry("KLC학과", "KLC"),
80+
Map.entry("의예과", "PREMED"),
81+
Map.entry("의학과", "MED"),
82+
Map.entry("간호학과", "NURS"),
83+
Map.entry("국어교육과", "KOR_EDU"),
84+
Map.entry("영어교육과", "ENG_EDU"),
85+
Map.entry("사회교육과", "SOC_EDU"),
86+
Map.entry("교육학과", "EDU"),
87+
Map.entry("체육교육과", "PE_EDU"),
88+
Map.entry("수학교육과", "MATH_EDU")
89+
);
90+
91+
private static final Map<String, String> ALIASES = Map.ofEntries(
92+
Map.entry("스마트모빌리티놀학과", "SME"),
93+
Map.entry("건축공학전공", "ACE"),
94+
Map.entry("건축학전공(5년제)", "ARCH"),
95+
Map.entry("경영학과", "BUS"),
96+
Map.entry("파이낸스경영학과", "FIN"),
97+
Map.entry("파이낸스경영학부(경영학과)", "FIN"),
98+
Map.entry("문화콘텐츠문화경영학부(경영학과)", "CCM"),
99+
Map.entry("문화컨텐츠경영학과", "CCM")
100+
);
101+
102+
private static final Set<String> KNOWN_CODES = Set.copyOf(LABEL_TO_CODE.values());
103+
104+
public String normalize(String major) {
105+
if (major == null) {
106+
return null;
107+
}
108+
109+
String trimmed = major.trim();
110+
if (trimmed.isBlank()) {
111+
return trimmed;
112+
}
113+
114+
if (KNOWN_CODES.contains(trimmed)) {
115+
return trimmed;
116+
}
117+
118+
String fromLabel = LABEL_TO_CODE.get(trimmed);
119+
if (fromLabel != null) {
120+
return fromLabel;
121+
}
122+
123+
return ALIASES.getOrDefault(trimmed, trimmed);
124+
}
125+
}

0 commit comments

Comments
 (0)