Skip to content

Commit 767f92f

Browse files
authored
Merge pull request #4 from AI-Tutor-2024/develop
Develop
2 parents 4477c9e + cd6a3e2 commit 767f92f

File tree

42 files changed

+1205
-307
lines changed

Some content is hidden

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

42 files changed

+1205
-307
lines changed

build.gradle

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ dependencies {
3434
implementation 'org.springframework.boot:spring-boot-starter-validation'
3535
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
3636
implementation 'org.springframework.boot:spring-boot-starter-security'
37+
implementation 'com.knuddels:jtokkit:0.3.0'
38+
3739

3840
implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.1.0'
3941
testImplementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-api', version: '2.1.0'
@@ -66,9 +68,28 @@ dependencies {
6668
annotationProcessor 'org.projectlombok:lombok'
6769

6870
runtimeOnly 'com.mysql:mysql-connector-j'
71+
runtimeOnly 'com.h2database:h2'
72+
73+
// test Dependencies
74+
75+
// springboot, junit 버전: https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-dependency-versions.html
76+
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3' // JUnit5
77+
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.3'
78+
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3'
6979

80+
// Lombok
81+
testImplementation 'org.projectlombok:lombok'
82+
testAnnotationProcessor 'org.projectlombok:lombok'
83+
84+
// Spring Boot Test
7085
testImplementation 'org.springframework.boot:spring-boot-starter-test'
7186
}
87+
test {
88+
testLogging {
89+
events "passed", "skipped", "failed"
90+
showStandardStreams = true
91+
}
92+
}
7293
tasks.named('test') {
7394
useJUnitPlatform()
7495
}

src/main/java/com/example/ai_tutor/domain/Folder/domain/repository/FolderRepository.java

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/main/java/com/example/ai_tutor/domain/auth/application/AuthService.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,15 @@ public ResponseEntity<?> signIn(SignInReq signInReq) {
129129
.build();
130130
tokenRepository.save(token);
131131

132-
// 교수자 생성
133-
if(user.getProfessor() == null){
134-
Professor professor = Professor.builder()
135-
.professorName(user.getName())
136-
.user(user)
137-
.build();
138-
professorRepository.save(professor);
139-
user.updateProfessor(professor);
140-
}
132+
// // 교수자 생성
133+
// if(user.getProfessor() == null){
134+
// Professor professor = Professor.builder()
135+
// .professorName(user.getName())
136+
// .user(user)
137+
// .build();
138+
// professorRepository.save(professor);
139+
// user.updateProfessor(professor);
140+
// }
141141

142142
AuthRes authResponse = AuthRes.builder()
143143
.accessToken(tokenMapping.getAccessToken())

src/main/java/com/example/ai_tutor/domain/auth/application/CustomDefaultOAuth2UserService.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
import com.example.ai_tutor.global.config.security.auth.OAuth2UserInfo;
88
import com.example.ai_tutor.global.config.security.auth.OAuth2UserInfoFactory;
99
import com.example.ai_tutor.global.config.security.token.UserPrincipal;
10-
import org.springframework.context.annotation.Bean;
11-
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10+
1211
import org.springframework.security.crypto.password.PasswordEncoder;
1312
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
1413
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
@@ -26,6 +25,7 @@
2625
public class CustomDefaultOAuth2UserService extends DefaultOAuth2UserService {
2726

2827
private final UserRepository userRepository;
28+
private PasswordEncoder passwordEncoder;
2929

3030
@Override
3131
public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException {
@@ -57,11 +57,11 @@ private OAuth2User processOAuth2User(OAuth2UserRequest oAuth2UserRequest, OAuth2
5757

5858
private User registerNewUser(OAuth2UserRequest oAuth2UserRequest, OAuth2UserInfo oAuth2UserInfo) {
5959
User user = User.builder()
60+
.name(oAuth2UserInfo.getName())
61+
.email(oAuth2UserInfo.getEmail())
62+
.password(passwordEncoder.encode(oAuth2UserInfo.getId()))
6063
.provider(Provider.valueOf(oAuth2UserRequest.getClientRegistration().getRegistrationId()))
6164
.providerId(oAuth2UserInfo.getId())
62-
.email(oAuth2UserInfo.getEmail())
63-
.name(oAuth2UserInfo.getName())
64-
.password(encodePassword(oAuth2UserInfo.getId()))
6565
.build();
6666

6767
return userRepository.save(user);
@@ -72,15 +72,16 @@ private User updateExistingUser(User user, OAuth2UserInfo oAuth2UserInfo) {
7272
return userRepository.save(user);
7373
}
7474

75-
private String encodePassword(String password) {
76-
// PasswordEncoder를 사용하여 비밀번호 인코딩
77-
return customPasswordEncoder().encode(password);
78-
}
75+
// private String encodePassword(String password) {
76+
// // PasswordEncoder를 사용하여 비밀번호 인코딩
77+
// return passwordEncoder.encode(password);
78+
// }
7979

80-
// PasswordEncoder를 Bean으로 등록하여 사용할 수 있도록 설정
81-
@Bean
82-
public PasswordEncoder customPasswordEncoder() {
83-
return new BCryptPasswordEncoder();
84-
}
80+
// 중복된 빈 등록으로 인한 오류 발생 -> 주석 처리
81+
// // PasswordEncoder를 Bean으로 등록하여 사용할 수 있도록 설정
82+
// @Bean
83+
// public PasswordEncoder customPasswordEncoder() {
84+
// return new BCryptPasswordEncoder();
85+
// }
8586

8687
}

src/main/java/com/example/ai_tutor/domain/auth/application/CustomTokenProviderService.java

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io.jsonwebtoken.security.Keys;
99
import lombok.extern.slf4j.Slf4j;
1010
import org.springframework.beans.factory.annotation.Autowired;
11+
import org.springframework.beans.factory.annotation.Value;
1112
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1213
import org.springframework.security.core.userdetails.UserDetails;
1314
import org.springframework.security.core.Authentication;
@@ -116,20 +117,41 @@ public Long getExpiration(String token) {
116117

117118
public boolean validateToken(String token) {
118119
try {
119-
//log.info("bearerToken = {} \n oAuth2Config.getAuth()={}", token, oAuth2Config.getAuth().getTokenSecret());
120-
Jwts.parserBuilder().setSigningKey(oAuth2Config.getAuth().getTokenSecret()).build().parseClaimsJws(token);
120+
log.info("JWT 검증 시작 - 토큰: {}", token);
121+
122+
String secretKey = oAuth2Config.getAuth().getTokenSecret();
123+
if (secretKey == null || secretKey.isEmpty()) {
124+
log.error("JWT 서명 검증 실패 - Secret Key가 설정되지 않았음");
125+
return false;
126+
}
127+
128+
log.info("JWT 서명 검증을 위한 Secret Key 사용: {}", secretKey);
129+
130+
Jwts.parserBuilder()
131+
.setSigningKey(secretKey)
132+
.build()
133+
.parseClaimsJws(token);
134+
135+
log.info("JWT 검증 성공 - 유효한 토큰입니다.");
121136
return true;
122-
} catch (io.jsonwebtoken.security.SecurityException ex) {
123-
log.error("잘못된 JWT 서명입니다.");
124-
} catch (MalformedJwtException ex) {
125-
log.error("잘못된 JWT 서명입니다.");
137+
138+
} catch (SecurityException | MalformedJwtException ex) {
139+
log.error("잘못된 JWT 서명 - JWT가 변조되었거나, 서명이 일치하지 않습니다. 원인: {}", ex.getMessage());
140+
126141
} catch (ExpiredJwtException ex) {
127-
log.error("만료된 JWT 토큰입니다.");
142+
log.error("만료된 JWT 토큰 - 만료 시간: {} | 현재 시간: {}",
143+
ex.getClaims().getExpiration(), new Date());
144+
128145
} catch (UnsupportedJwtException ex) {
129-
log.error("지원되지 않는 JWT 토큰입니다.");
146+
log.error("지원되지 않는 JWT 형식 - 제공된 토큰이 예상된 형식과 다릅니다. 원인: {}", ex.getMessage());
147+
130148
} catch (IllegalArgumentException ex) {
131-
log.error("JWT 토큰이 잘못되었습니다.");
149+
log.error("JWT 값이 유효하지 않음 - 빈 값이거나, null이 전달됨. 원인: {}", ex.getMessage());
150+
151+
} catch (Exception ex) {
152+
log.error("예기치 않은 JWT 검증 오류 발생: {}", ex.getMessage(), ex);
132153
}
154+
133155
return false;
134156
}
135157

src/main/java/com/example/ai_tutor/domain/auth/dto/SignInReq.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
import io.swagger.v3.oas.annotations.media.Schema;
44
import jakarta.validation.constraints.Email;
5+
import lombok.AllArgsConstructor;
56
import lombok.Data;
67

78
@Data
9+
@AllArgsConstructor
810
public class SignInReq {
911

1012
@Schema( type = "string", example = "string@aa.bb", description="계정 이메일 입니다.")

src/main/java/com/example/ai_tutor/domain/Folder/application/FolderService.java renamed to src/main/java/com/example/ai_tutor/domain/folder/application/FolderService.java

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
package com.example.ai_tutor.domain.Folder.application;
2-
3-
import com.example.ai_tutor.domain.Folder.domain.Folder;
4-
import com.example.ai_tutor.domain.Folder.domain.repository.FolderRepository;
5-
import com.example.ai_tutor.domain.Folder.dto.request.FolderCreateReq;
6-
import com.example.ai_tutor.domain.Folder.dto.response.FolderListRes;
7-
import com.example.ai_tutor.domain.Folder.dto.response.FolderNameListRes;
1+
package com.example.ai_tutor.domain.folder.application;
2+
import com.example.ai_tutor.domain.folder.domain.Folder;
3+
import com.example.ai_tutor.domain.folder.domain.repository.FolderRepository;
4+
import com.example.ai_tutor.domain.folder.dto.request.FolderCreateReq;
5+
import com.example.ai_tutor.domain.folder.dto.response.FolderListRes;
6+
import com.example.ai_tutor.domain.folder.dto.response.FolderNameListRes;
7+
import com.example.ai_tutor.domain.note.dto.response.FolderInfoRes;
88
import com.example.ai_tutor.domain.professor.domain.Professor;
99
import com.example.ai_tutor.domain.professor.domain.repository.ProfessorRepository;
1010
import com.example.ai_tutor.domain.user.domain.User;
1111
import com.example.ai_tutor.domain.user.domain.repository.UserRepository;
12-
import com.example.ai_tutor.global.DefaultAssert;
1312
import com.example.ai_tutor.global.config.security.token.UserPrincipal;
1413
import com.example.ai_tutor.global.payload.ApiResponse;
1514

@@ -34,9 +33,7 @@ public class FolderService {
3433
// 교수자 - 폴더 생성
3534
@Transactional
3635
public ResponseEntity<?> createNewFolder( UserPrincipal userPrincipal, FolderCreateReq folderCreateReq) {
37-
// User user = userRepository.findById(userPrincipal.getId()).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
38-
User user = userRepository.findById(1L).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
39-
36+
User user = getUser(userPrincipal);
4037
String folderName = folderCreateReq.getFolderName();
4138
String professorName = folderCreateReq.getProfessorName();
4239

@@ -69,9 +66,7 @@ public ResponseEntity<?> createNewFolder( UserPrincipal userPrincipal, FolderCre
6966

7067
// 폴더 이름 목록 조회
7168
public ResponseEntity<?> getFolderNames(UserPrincipal userPrincipal) {
72-
// User user = userRepository.findById(userPrincipal.getId()).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
73-
User user = userRepository.findById(1L).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
74-
69+
User user = getUser(userPrincipal);
7570
Professor professor = user.getProfessor();
7671
List<Folder> folders = professor.getFolders();
7772
List<FolderNameListRes> folderRes = folders.stream()
@@ -92,14 +87,13 @@ public ResponseEntity<?> getFolderNames(UserPrincipal userPrincipal) {
9287

9388
// 폴더 목록 조회 (폴더명, 교수자명 포함)
9489
public ResponseEntity<?> getAllFolders(UserPrincipal userPrincipal) {
95-
// User user = userRepository.findById(userPrincipal.getId()).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
96-
User user = userRepository.findById(1L).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
97-
90+
User user = getUser(userPrincipal);
9891
Professor professor = user.getProfessor();
9992
List<Folder> folders = professor.getFolders();
10093
List<FolderListRes> folderRes = folders.stream()
10194
.map(folder -> FolderListRes.builder()
10295
.folderId(folder.getFolderId())
96+
.noteCount(folder.getNotes().size())
10397
.folderName(folder.getFolderName())
10498
.professor(folder.getProfessorName())
10599
.build(
@@ -114,10 +108,28 @@ public ResponseEntity<?> getAllFolders(UserPrincipal userPrincipal) {
114108
return ResponseEntity.ok(apiResponse);
115109
}
116110

111+
// 수업 정보 조회
112+
@Transactional
113+
public ResponseEntity<?> getFolderInfo(UserPrincipal userPrincipal, Long folderId) {
114+
getUser(userPrincipal);
115+
Folder folder = folderRepository.findById(folderId).orElseThrow(() -> new IllegalArgumentException("폴더를 찾을 수 없습니다."));
116+
117+
FolderInfoRes folderInfoRes = FolderInfoRes.builder()
118+
.folderName(folder.getFolderName())
119+
.professor(folder.getProfessor().getUser().getName())
120+
.build();
121+
122+
ApiResponse apiResponse = ApiResponse.builder()
123+
.check(true)
124+
.information(folderInfoRes)
125+
.build();
126+
127+
return ResponseEntity.ok(apiResponse);
128+
}
129+
117130
@Transactional
118131
public ResponseEntity<?> updateFolder(UserPrincipal userPrincipal, Long folderId, FolderCreateReq folderCreateReq) {
119-
// User user = userRepository.findById(userPrincipal.getId()).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
120-
User user = userRepository.findById(1L).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
132+
getUser(userPrincipal);
121133
Folder folder=folderRepository.findById(folderId).orElseThrow(() -> new IllegalArgumentException("폴더를 찾을 수 없습니다."));
122134

123135

@@ -133,8 +145,7 @@ public ResponseEntity<?> updateFolder(UserPrincipal userPrincipal, Long folderId
133145

134146
@Transactional
135147
public ResponseEntity<?> deleteFolder(UserPrincipal userPrincipal, Long folderId) {
136-
// User user = userRepository.findById(userPrincipal.getId()).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
137-
User user = userRepository.findById(1L).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
148+
getUser(userPrincipal);
138149
Folder folder=folderRepository.findById(folderId).orElseThrow(() -> new IllegalArgumentException("폴더를 찾을 수 없습니다."));
139150

140151
folderRepository.delete(folder);
@@ -145,4 +156,9 @@ public ResponseEntity<?> deleteFolder(UserPrincipal userPrincipal, Long folderId
145156

146157
return ResponseEntity.ok(apiResponse);
147158
}
159+
160+
private User getUser(UserPrincipal userPrincipal){
161+
return userRepository.findById(userPrincipal.getId()).orElseThrow(()
162+
-> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
163+
}
148164
}

src/main/java/com/example/ai_tutor/domain/Folder/domain/Folder.java renamed to src/main/java/com/example/ai_tutor/domain/folder/domain/Folder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.example.ai_tutor.domain.Folder.domain;
1+
package com.example.ai_tutor.domain.folder.domain;
22

33
import com.example.ai_tutor.domain.common.BaseEntity;
44
import com.example.ai_tutor.domain.note.domain.Note;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.example.ai_tutor.domain.folder.domain.repository;
2+
3+
import com.example.ai_tutor.domain.folder.domain.Folder;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
@Repository
8+
public interface FolderRepository extends JpaRepository<Folder, Long>{
9+
}

src/main/java/com/example/ai_tutor/domain/Folder/dto/request/FolderCreateReq.java renamed to src/main/java/com/example/ai_tutor/domain/folder/dto/request/FolderCreateReq.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.example.ai_tutor.domain.Folder.dto.request;
1+
package com.example.ai_tutor.domain.folder.dto.request;
22

33
import io.swagger.v3.oas.annotations.media.Schema;
44
import lombok.*;

0 commit comments

Comments
 (0)