diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2de5ec95..e57256c1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,16 +1,16 @@ ### Issue -- +- # ### 내용 -- +- [x] ### 핵심 구현 방법 -- +- 없음 ### 전달 사항 -- \ No newline at end of file +- 없음 \ No newline at end of file diff --git a/.github/workflows/gradleTest.yml b/.github/workflows/githubaction-ci.yml similarity index 85% rename from .github/workflows/gradleTest.yml rename to .github/workflows/githubaction-ci.yml index 5aebdf3c..9076802f 100644 --- a/.github/workflows/gradleTest.yml +++ b/.github/workflows/githubaction-ci.yml @@ -26,19 +26,24 @@ jobs: with: java-version: '11' distribution: 'temurin' + - name: Grant execute permission for gradlew run: chmod +x gradlew + + - name: Build with Gradle + run: ./gradlew clean build -x test + - name: Check Code Formatting run: ./gradlew spotlessJavaCheck - - name: Build with Gradle - run: ./gradlew clean build - - name: Check Test Results + + - name: Test with Gradle run: | - TEST_RESULT=$(./gradlew test --quiet) + TEST_RESULT=$(./gradlew test) if [[ $TEST_RESULT == *"FAILURE"* ]]; then echo "::error::Unit tests failed. Please check the code and try again." exit 1 fi + - name: Notify Slack if: always() uses: 8398a7/action-slack@v2.6.0 @@ -53,6 +58,13 @@ jobs: Commit: ${{ github.sha }} Event: ${{ github.event_name }} Branch: ${{ github.ref }} + + - name: Publish Unit Test Results + uses: EnricoMi/publish-unit-test-result-action@v1 + if: ${{ always() }} + with: + files: build/test-results/**/*.xml + - name: Prevent merge on failure if: ${{ failure() }} run: echo "::set-output name=mergeable::false" diff --git a/.gitignore b/.gitignore index d699dbae..c74c3a80 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ cmake-build-*/ */out/production/* */out/test/* out/production +out/test # mpeltonen/sbt-idea plugin .idea_modules/ diff --git a/api-module/src/main/java/com/miracle/user/controller/UserController.java b/api-module/src/main/java/com/miracle/user/controller/UserController.java deleted file mode 100644 index 56e2be01..00000000 --- a/api-module/src/main/java/com/miracle/user/controller/UserController.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.miracle.user.controller; - -import com.miracle.user.controller.request.JoinReq; -import com.miracle.user.controller.response.JoinRes; -import com.miracle.user.service.JoinUserService; -import com.miracle.user.service.dto.JoinReqDto; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/user") -public class UserController { - private final JoinUserService joinService; - - @GetMapping("/join") - public ResponseEntity join(@RequestBody JoinReq joinReq) { - JoinReqDto joinReqDto = JoinReq.toDto(joinReq); - joinService.join(joinReqDto); - return ResponseEntity.ok(JoinRes.builder().message("회원가입이 완료되었습니다.").build()); - } -} diff --git a/api-module/src/main/java/com/miracle/user/controller/request/JoinReq.java b/api-module/src/main/java/com/miracle/user/controller/request/JoinReq.java deleted file mode 100644 index c2cdf9b0..00000000 --- a/api-module/src/main/java/com/miracle/user/controller/request/JoinReq.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.miracle.user.controller.request; - -import com.miracle.user.service.dto.JoinReqDto; -import lombok.*; - -@Getter -@Builder -@AllArgsConstructor -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class JoinReq { - - private String userId; - private String password; - - public static JoinReqDto toDto(JoinReq joinReq) { - return JoinReqDto.builder() - .userId(joinReq.getUserId()) - .password(joinReq.getPassword()) - .build(); - } -} diff --git a/api-module/src/main/java/com/miracle/user/service/JoinUserService.java b/api-module/src/main/java/com/miracle/user/service/JoinUserService.java deleted file mode 100644 index afb01d6d..00000000 --- a/api-module/src/main/java/com/miracle/user/service/JoinUserService.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.miracle.user.service; - -import com.miracle.user.service.dto.JoinReqDto; - -public interface JoinUserService { - - void join(JoinReqDto joinReqDto); -} diff --git a/api-module/src/main/java/com/miracle/user/service/JoinUserServiceImpl.java b/api-module/src/main/java/com/miracle/user/service/JoinUserServiceImpl.java deleted file mode 100644 index c6edfc84..00000000 --- a/api-module/src/main/java/com/miracle/user/service/JoinUserServiceImpl.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.miracle.user.service; - -import com.miracle.user.service.dto.JoinReqDto; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class JoinUserServiceImpl implements JoinUserService { - - @Override - public void join(JoinReqDto joinReqDto) { - System.out.println("안녕 친구들!"); - } -} diff --git a/api-module/src/main/java/com/miracle/user/service/UserDetailServiceImpl.java b/api-module/src/main/java/com/miracle/user/service/UserDetailServiceImpl.java deleted file mode 100644 index 6da7b08c..00000000 --- a/api-module/src/main/java/com/miracle/user/service/UserDetailServiceImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.miracle.user.service; - -import lombok.RequiredArgsConstructor; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class UserDetailServiceImpl implements UserDetailsService { - - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - return null; - } -} diff --git a/api-module/src/main/java/com/miracle/user/service/dto/JoinReqDto.java b/api-module/src/main/java/com/miracle/user/service/dto/JoinReqDto.java deleted file mode 100644 index a9884ded..00000000 --- a/api-module/src/main/java/com/miracle/user/service/dto/JoinReqDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.miracle.user.service.dto; - -import lombok.Builder; -import lombok.Getter; - -@Getter -public class JoinReqDto { - - private String userId; - private String password; - - @Builder - public JoinReqDto(String userId, String password) { - this.userId = userId; - this.password = password; - } -} diff --git a/api-module/src/main/java/com/miracle/user/service/dto/JoinResDto.java b/api-module/src/main/java/com/miracle/user/service/dto/JoinResDto.java deleted file mode 100644 index c5629e83..00000000 --- a/api-module/src/main/java/com/miracle/user/service/dto/JoinResDto.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.miracle.user.service.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public class JoinResDto {} diff --git a/build.gradle b/build.gradle index ab153885..d5176be3 100644 --- a/build.gradle +++ b/build.gradle @@ -22,10 +22,25 @@ repositories { } dependencies { - implementation project(':api-module') implementation project(':core-module') + implementation project(':member-module') + implementation project(':member-module:member-web-adapter') + implementation project(':member-module:member-application') + implementation project(':member-module:member-persistence-adapter') + + implementation project(':teacher-module') + implementation project(':teacher-module:teacher-web-adapter') + implementation project(':teacher-module:teacher-application') + implementation project(':teacher-module:teacher-persistence-adapter') + + implementation project(':wronganswernote-module') + implementation project(':wronganswernote-module:wronganswernote-web-adapter') + implementation project(':wronganswernote-module:wronganswernote-application') + implementation project(':wronganswernote-module:wronganswernote-persistence-adapter') + implementation 'org.springframework.boot:spring-boot-starter-web' + testImplementation 'com.h2database:h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' } @@ -47,6 +62,10 @@ subprojects { apply plugin: 'io.spring.dependency-management' apply plugin: 'java-library' + jar { + enabled = true + } + repositories { mavenCentral() maven { url 'https://repo.spring.io/milestone' } @@ -60,6 +79,7 @@ subprojects { } dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-security' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' @@ -75,24 +95,35 @@ tasks.named('test') { useJUnitPlatform() } -project(':api-module') { +project(':member-module') { dependencies { implementation project(':core-module') + implementation project(':member-module:member-web-adapter') + implementation project(':member-module:member-application') + implementation project(':member-module:member-persistence-adapter') + } +} - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1' - runtimeOnly 'com.h2database:h2' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:2.3.1' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +project(':teacher-module') { + dependencies { + implementation project(':core-module') + implementation project(':teacher-module:teacher-web-adapter') + implementation project(':teacher-module:teacher-application') + implementation project(':teacher-module:teacher-persistence-adapter') + } +} + +project(':wronganswernote-module') { + dependencies { + implementation project(':core-module') + implementation project(':wronganswernote-module:wronganswernote-web-adapter') + implementation project(':wronganswernote-module:wronganswernote-application') + implementation project(':wronganswernote-module:wronganswernote-persistence-adapter') } } project(':core-module') { dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' implementation("io.jsonwebtoken:jjwt-api:0.11.5") runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5") runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5") diff --git a/core-module/build.gradle b/core-module/build.gradle index ed9488c4..e6540b53 100644 --- a/core-module/build.gradle +++ b/core-module/build.gradle @@ -10,6 +10,8 @@ repositories { } dependencies { + testImplementation 'com.h2database:h2:2.1.214' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' } diff --git a/core-module/src/main/java/com/miracle/dto/ErrorMessage.java b/core-module/src/main/java/com/ohdab/template/ErrorMessage.java similarity index 67% rename from core-module/src/main/java/com/miracle/dto/ErrorMessage.java rename to core-module/src/main/java/com/ohdab/template/ErrorMessage.java index 88c08ef8..2777db04 100644 --- a/core-module/src/main/java/com/miracle/dto/ErrorMessage.java +++ b/core-module/src/main/java/com/ohdab/template/ErrorMessage.java @@ -1,4 +1,4 @@ -package com.miracle.dto; +package com.ohdab.template; import lombok.Builder; import lombok.Getter; @@ -8,5 +8,5 @@ public class ErrorMessage { private int errorCode; - private String errorMessage; + private String message; } diff --git a/core-module/src/main/java/com/ohdab/template/SuccessMessage.java b/core-module/src/main/java/com/ohdab/template/SuccessMessage.java new file mode 100644 index 00000000..594b5c17 --- /dev/null +++ b/core-module/src/main/java/com/ohdab/template/SuccessMessage.java @@ -0,0 +1,9 @@ +package com.ohdab.template; + +import lombok.Builder; + +@Builder +public class SuccessMessage { + + private int code; +} diff --git a/core-module/src/main/java/com/miracle/util/jwt/JwtTokenProvider.java b/core-module/src/main/java/com/ohdab/util/jwt/JwtTokenProvider.java similarity index 87% rename from core-module/src/main/java/com/miracle/util/jwt/JwtTokenProvider.java rename to core-module/src/main/java/com/ohdab/util/jwt/JwtTokenProvider.java index d9bee256..af348a75 100644 --- a/core-module/src/main/java/com/miracle/util/jwt/JwtTokenProvider.java +++ b/core-module/src/main/java/com/ohdab/util/jwt/JwtTokenProvider.java @@ -1,5 +1,6 @@ -package com.miracle.util.jwt; +package com.ohdab.util.jwt; +import com.ohdab.util.jwt.exception.CustomWeakKeyException; import io.jsonwebtoken.*; import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.WeakKeyException; @@ -51,12 +52,12 @@ public void afterPropertiesSet() { byte[] keyBytes = Base64.getDecoder().decode(secretKey); this.key = Keys.hmacShaKeyFor(keyBytes); } catch (WeakKeyException e) { - log.error("key 생성 실패", e); - throw new RuntimeException(e); + log.error("제공된 secret key가 256bit를 넘지 않습니다.", e); + throw new CustomWeakKeyException(e); } } - public String createToken(Authentication authentication) { + public String createToken(Authentication authentication, Long id) { String authorities = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) @@ -68,8 +69,9 @@ public String createToken(Authentication authentication) { .setIssuer(issuer) // JWT 토큰 발급자 .setIssuedAt(now) // JWT 토큰 발급 시간 .setExpiration(expiration) + .claim("id", id) .claim(authoritiesKey, authorities) - .signWith(getKey(secretKey), SignatureAlgorithm.HS256) + .signWith(key, SignatureAlgorithm.HS256) .compact(); // JWT 토큰 생성 } @@ -95,16 +97,11 @@ public boolean validateToken(String token) { } catch (UnsupportedJwtException e) { log.error("지원하지 않는 JWT 토큰입니다.", e); } catch (IllegalArgumentException e) { - log.error("JWT 토큰이 잘못되었습니다.", e); + log.error("JWT 토큰이 없거나 잘못되었습니다.", e); } return false; } - private Key getKey(String secretKey) { - String encodedSecretKey = Base64.getEncoder().encodeToString(secretKey.getBytes()); - return Keys.hmacShaKeyFor(encodedSecretKey.getBytes()); - } - private Claims parseClaims(String token) { return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody(); } diff --git a/core-module/src/main/java/com/ohdab/util/jwt/exception/CustomWeakKeyException.java b/core-module/src/main/java/com/ohdab/util/jwt/exception/CustomWeakKeyException.java new file mode 100644 index 00000000..d7c1df1f --- /dev/null +++ b/core-module/src/main/java/com/ohdab/util/jwt/exception/CustomWeakKeyException.java @@ -0,0 +1,17 @@ +package com.ohdab.util.jwt.exception; + +public class CustomWeakKeyException extends RuntimeException { + public CustomWeakKeyException() {} + + public CustomWeakKeyException(String message) { + super(message); + } + + public CustomWeakKeyException(String message, Throwable cause) { + super(message, cause); + } + + public CustomWeakKeyException(Throwable cause) { + super(cause); + } +} diff --git a/core-module/src/main/java/com/miracle/util/security/WebSecurityConfig.java b/core-module/src/main/java/com/ohdab/util/security/config/WebSecurityConfig.java similarity index 76% rename from core-module/src/main/java/com/miracle/util/security/WebSecurityConfig.java rename to core-module/src/main/java/com/ohdab/util/security/config/WebSecurityConfig.java index 574b6b16..a7b68f28 100644 --- a/core-module/src/main/java/com/miracle/util/security/WebSecurityConfig.java +++ b/core-module/src/main/java/com/ohdab/util/security/config/WebSecurityConfig.java @@ -1,15 +1,18 @@ -package com.miracle.util.security; +package com.ohdab.util.security.config; -import com.miracle.util.jwt.JwtAuthFilter; -import com.miracle.util.jwt.JwtTokenProvider; +import com.ohdab.util.jwt.JwtTokenProvider; +import com.ohdab.util.security.filter.JwtAuthFilter; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; @@ -22,6 +25,7 @@ public class WebSecurityConfig { private final JwtTokenProvider jwtTokenProvider; private final AuthenticationEntryPoint authenticationEntryPoint; + private final AccessDeniedHandler accessDeniedHandler; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) { @@ -33,12 +37,17 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) { .disable() .exceptionHandling() .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler) .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() - .antMatchers("/user/**") + .antMatchers("/user/login", "/user/join") + .permitAll() + .antMatchers("/user/test") + .hasRole("ADMIN") + .anyRequest() .authenticated() .and() .addFilterBefore( @@ -50,6 +59,11 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) { } } + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + // CORS 허용 @Bean public CorsConfigurationSource corsConfigurationSource() { diff --git a/core-module/src/main/java/com/miracle/util/jwt/JwtAuthFilter.java b/core-module/src/main/java/com/ohdab/util/security/filter/JwtAuthFilter.java similarity index 94% rename from core-module/src/main/java/com/miracle/util/jwt/JwtAuthFilter.java rename to core-module/src/main/java/com/ohdab/util/security/filter/JwtAuthFilter.java index b2a6c22b..90a420a8 100644 --- a/core-module/src/main/java/com/miracle/util/jwt/JwtAuthFilter.java +++ b/core-module/src/main/java/com/ohdab/util/security/filter/JwtAuthFilter.java @@ -1,5 +1,6 @@ -package com.miracle.util.jwt; +package com.ohdab.util.security.filter; +import com.ohdab.util.jwt.JwtTokenProvider; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; diff --git a/core-module/src/main/java/com/ohdab/util/security/handler/JwtAccessDeniedHandler.java b/core-module/src/main/java/com/ohdab/util/security/handler/JwtAccessDeniedHandler.java new file mode 100644 index 00000000..392ec0cb --- /dev/null +++ b/core-module/src/main/java/com/ohdab/util/security/handler/JwtAccessDeniedHandler.java @@ -0,0 +1,48 @@ +package com.ohdab.util.security.handler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ohdab.template.ErrorMessage; +import java.io.IOException; +import java.io.PrintWriter; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + + private final ObjectMapper objectMapper; + + @Override + public void handle( + HttpServletRequest request, + HttpServletResponse response, + AccessDeniedException accessDeniedException) + throws IOException, ServletException { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding("UTF-8"); + PrintWriter writer = response.getWriter(); + ErrorMessage errorMessage = + ErrorMessage.builder().errorCode(403).message("접근 권한이 없습니다.").build(); + try { + writer.write(objectMapper.writeValueAsString(errorMessage)); + } catch (Exception e) { + log.error("응답 메시지 작성 실패", e); + } finally { + if (writer != null) { + writer.flush(); + writer.close(); + } + } + response.getWriter().write(objectMapper.writeValueAsString(errorMessage)); + } +} diff --git a/core-module/src/main/java/com/miracle/util/jwt/handler/JwtAuthenticationEntryPoint.java b/core-module/src/main/java/com/ohdab/util/security/handler/JwtAuthenticationEntryPoint.java similarity index 79% rename from core-module/src/main/java/com/miracle/util/jwt/handler/JwtAuthenticationEntryPoint.java rename to core-module/src/main/java/com/ohdab/util/security/handler/JwtAuthenticationEntryPoint.java index 9e3b21f0..6698318c 100644 --- a/core-module/src/main/java/com/miracle/util/jwt/handler/JwtAuthenticationEntryPoint.java +++ b/core-module/src/main/java/com/ohdab/util/security/handler/JwtAuthenticationEntryPoint.java @@ -1,7 +1,7 @@ -package com.miracle.util.jwt.handler; +package com.ohdab.util.security.handler; import com.fasterxml.jackson.databind.ObjectMapper; -import com.miracle.dto.ErrorMessage; +import com.ohdab.template.ErrorMessage; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; @@ -27,11 +27,13 @@ public void commence( HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding("UTF-8"); PrintWriter writer = response.getWriter(); ErrorMessage errorMessage = - ErrorMessage.builder().errorCode(999).errorMessage("error!!!").build(); + ErrorMessage.builder().errorCode(401).message("인증되지 않은 사용자입니다.").build(); try { - response.setContentType(MediaType.APPLICATION_JSON_VALUE); writer.write(objectMapper.writeValueAsString(errorMessage)); } catch (Exception e) { log.error("응답 메시지 작성 실패", e); diff --git a/core-module/src/test/resources/application.yml b/core-module/src/test/resources/application.yml new file mode 100644 index 00000000..b076decc --- /dev/null +++ b/core-module/src/test/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:test + jpa: + hibernate: + ddl-auto: create-drop + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + format_sql: true + use_sql_comments: true \ No newline at end of file diff --git a/api-module/build.gradle b/member-module/build.gradle similarity index 100% rename from api-module/build.gradle rename to member-module/build.gradle diff --git a/member-module/member-application/build.gradle b/member-module/member-application/build.gradle new file mode 100644 index 00000000..10bf1a4c --- /dev/null +++ b/member-module/member-application/build.gradle @@ -0,0 +1,21 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':core-module') + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/member-module/member-application/src/main/java/com/ohdab/JoinService.java b/member-module/member-application/src/main/java/com/ohdab/JoinService.java new file mode 100644 index 00000000..e084b0b5 --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/JoinService.java @@ -0,0 +1,60 @@ +package com.ohdab; + +import com.ohdab.domain.Member; +import com.ohdab.domain.authority.Authority; +import com.ohdab.domain.profile.Profile; +import com.ohdab.dto.JoinReqDto; +import com.ohdab.exception.DuplicatedMemberException; +import com.ohdab.port.in.JoinUsecase; +import com.ohdab.port.out.FindMemberPort; +import com.ohdab.port.out.SaveMemberPort; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class JoinService implements JoinUsecase { + + private final PasswordEncoder passwordEncoder; + private final FindMemberPort findMemberPort; + private final SaveMemberPort saveMemberPort; + + @Override + public void join(JoinReqDto joinReqDto) { + checkDuplicatedMember(joinReqDto.getName()); + Member member = createMember(joinReqDto, createAuthorities(joinReqDto)); + saveMemberPort.save(member); + } + + private List createAuthorities(JoinReqDto joinReqDto) { + List roleList = joinReqDto.getRole(); + return roleList.stream() + .map(role -> Authority.builder().role(role).build()) + .collect(Collectors.toList()); + } + + private Member createMember(JoinReqDto joinReqDto, List authorities) { + return Member.builder() + .profile(createMemberProfile(joinReqDto)) + .authorities(authorities) + .build(); + } + + private Profile createMemberProfile(JoinReqDto joinReqDto) { + return Profile.builder() + .name(joinReqDto.getName()) + .password(passwordEncoder.encode(joinReqDto.getPassword())) + .build(); + } + + private void checkDuplicatedMember(String name) { + Optional member = findMemberPort.findByMemberProfile_Name(name); + if (member.isPresent()) { + throw new DuplicatedMemberException("이미 존재하는 회원입니다."); + } + } +} diff --git a/member-module/member-application/src/main/java/com/ohdab/LoginService.java b/member-module/member-application/src/main/java/com/ohdab/LoginService.java new file mode 100644 index 00000000..66157932 --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/LoginService.java @@ -0,0 +1,45 @@ +package com.ohdab; + +import com.ohdab.domain.Member; +import com.ohdab.dto.LoginReqDto; +import com.ohdab.dto.LoginResDto; +import com.ohdab.helper.MemberHelperService; +import com.ohdab.port.in.LoginUsecase; +import com.ohdab.util.jwt.JwtTokenProvider; +import lombok.AllArgsConstructor; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@AllArgsConstructor +public class LoginService implements LoginUsecase { + + private final MemberHelperService memberHelperService; + private final UserDetailsService userDetailsService; + private final JwtTokenProvider jwtTokenProvider; + private final PasswordEncoder passwordEncoder; + + public LoginResDto login(LoginReqDto loginReqDto) { + UserDetails userDetails = userDetailsService.loadUserByUsername(loginReqDto.getName()); + Member member = memberHelperService.findExistingMember(loginReqDto.getName()); + if (!member.matchPassword( + passwordEncoder, loginReqDto.getPassword(), userDetails.getPassword())) { + throw new BadCredentialsException("비밀번호가 일치하지 않습니다."); + } + Authentication authentication = createAuthentication(userDetails); + return LoginResDto.builder() + .memberId(member.getId()) + .jwtToken(jwtTokenProvider.createToken(authentication, member.getId())) + .build(); + } + + private Authentication createAuthentication(UserDetails userDetails) { + return new UsernamePasswordAuthenticationToken( + userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities()); + } +} diff --git a/member-module/member-application/src/main/java/com/ohdab/UserDetailServiceImpl.java b/member-module/member-application/src/main/java/com/ohdab/UserDetailServiceImpl.java new file mode 100644 index 00000000..c96ee35e --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/UserDetailServiceImpl.java @@ -0,0 +1,39 @@ +package com.ohdab; + +import com.ohdab.domain.Member; +import com.ohdab.helper.MemberHelperService; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class UserDetailServiceImpl implements UserDetailsService { + + private final MemberHelperService memberHelperService; + + @Override + public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { + Member member = memberHelperService.findExistingMember(name); + return createUserDetails(member); + } + + private UserDetails createUserDetails(Member member) { + return new User( + member.getProfile().getName(), + member.getProfile().getPassword(), + mapToSimpleGrandAuthority(member)); + } + + private List mapToSimpleGrandAuthority(Member member) { + return member.getAuthorities().stream() + .map(authority -> new SimpleGrantedAuthority(authority.getRole())) + .collect(Collectors.toList()); + } +} diff --git a/member-module/member-application/src/main/java/com/ohdab/domain/Member.java b/member-module/member-application/src/main/java/com/ohdab/domain/Member.java new file mode 100644 index 00000000..daa12440 --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/domain/Member.java @@ -0,0 +1,27 @@ +package com.ohdab.domain; + +import com.ohdab.domain.authority.Authority; +import com.ohdab.domain.profile.Profile; +import java.util.List; +import lombok.Builder; +import lombok.Getter; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Getter +public class Member { + Long id; + Profile profile; + List authorities; + + @Builder + public Member(Long id, Profile profile, List authorities) { + this.id = id; + this.profile = profile; + this.authorities = authorities; + } + + public boolean matchPassword( + PasswordEncoder passwordEncoder, String rawPassword, String encodedPassword) { + return passwordEncoder.matches(rawPassword, encodedPassword); + } +} diff --git a/member-module/member-application/src/main/java/com/ohdab/domain/authority/Authority.java b/member-module/member-application/src/main/java/com/ohdab/domain/authority/Authority.java new file mode 100644 index 00000000..0c878e75 --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/domain/authority/Authority.java @@ -0,0 +1,15 @@ +package com.ohdab.domain.authority; + +import lombok.Builder; +import lombok.Getter; + +@Getter +public class Authority { + + private String role; + + @Builder + public Authority(String role) { + this.role = role; + } +} diff --git a/member-module/member-application/src/main/java/com/ohdab/domain/profile/Profile.java b/member-module/member-application/src/main/java/com/ohdab/domain/profile/Profile.java new file mode 100644 index 00000000..48586cf1 --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/domain/profile/Profile.java @@ -0,0 +1,17 @@ +package com.ohdab.domain.profile; + +import lombok.Builder; +import lombok.Getter; + +@Getter +public class Profile { + + private String name; + private String password; + + @Builder + public Profile(String name, String password) { + this.name = name; + this.password = password; + } +} diff --git a/member-module/member-application/src/main/java/com/ohdab/dto/JoinReqDto.java b/member-module/member-application/src/main/java/com/ohdab/dto/JoinReqDto.java new file mode 100644 index 00000000..a1f70cfb --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/dto/JoinReqDto.java @@ -0,0 +1,14 @@ +package com.ohdab.dto; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class JoinReqDto { + + private String name; + private String password; + private List role; +} diff --git a/member-module/member-application/src/main/java/com/ohdab/dto/LoginReqDto.java b/member-module/member-application/src/main/java/com/ohdab/dto/LoginReqDto.java new file mode 100644 index 00000000..236d1589 --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/dto/LoginReqDto.java @@ -0,0 +1,12 @@ +package com.ohdab.dto; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class LoginReqDto { + + private String name; + private String password; +} diff --git a/member-module/member-application/src/main/java/com/ohdab/dto/LoginResDto.java b/member-module/member-application/src/main/java/com/ohdab/dto/LoginResDto.java new file mode 100644 index 00000000..f33585f5 --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/dto/LoginResDto.java @@ -0,0 +1,12 @@ +package com.ohdab.dto; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class LoginResDto { + + private Long memberId; + private String jwtToken; +} diff --git a/member-module/member-application/src/main/java/com/ohdab/exception/DuplicatedMemberException.java b/member-module/member-application/src/main/java/com/ohdab/exception/DuplicatedMemberException.java new file mode 100644 index 00000000..8a0114ca --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/exception/DuplicatedMemberException.java @@ -0,0 +1,17 @@ +package com.ohdab.exception; + +public class DuplicatedMemberException extends RuntimeException { + public DuplicatedMemberException() {} + + public DuplicatedMemberException(String message) { + super(message); + } + + public DuplicatedMemberException(String message, Throwable cause) { + super(message, cause); + } + + public DuplicatedMemberException(Throwable cause) { + super(cause); + } +} diff --git a/member-module/member-application/src/main/java/com/ohdab/exception/NoMemberException.java b/member-module/member-application/src/main/java/com/ohdab/exception/NoMemberException.java new file mode 100644 index 00000000..841dd95d --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/exception/NoMemberException.java @@ -0,0 +1,17 @@ +package com.ohdab.exception; + +public class NoMemberException extends RuntimeException { + public NoMemberException() {} + + public NoMemberException(String message) { + super(message); + } + + public NoMemberException(String message, Throwable cause) { + super(message, cause); + } + + public NoMemberException(Throwable cause) { + super(cause); + } +} diff --git a/member-module/member-application/src/main/java/com/ohdab/helper/MemberHelperService.java b/member-module/member-application/src/main/java/com/ohdab/helper/MemberHelperService.java new file mode 100644 index 00000000..f055b5ce --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/helper/MemberHelperService.java @@ -0,0 +1,20 @@ +package com.ohdab.helper; + +import com.ohdab.domain.Member; +import com.ohdab.exception.NoMemberException; +import com.ohdab.port.out.FindMemberPort; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public final class MemberHelperService { + + private final FindMemberPort findMemberPort; + + public Member findExistingMember(String name) { + return findMemberPort + .findByMemberProfile_Name(name) + .orElseThrow(() -> new NoMemberException("존재하지 않는 회원입니다.")); + } +} diff --git a/member-module/member-application/src/main/java/com/ohdab/port/in/JoinUsecase.java b/member-module/member-application/src/main/java/com/ohdab/port/in/JoinUsecase.java new file mode 100644 index 00000000..70a9c642 --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/port/in/JoinUsecase.java @@ -0,0 +1,8 @@ +package com.ohdab.port.in; + +import com.ohdab.dto.JoinReqDto; + +public interface JoinUsecase { + + void join(JoinReqDto joinReqDto); +} diff --git a/member-module/member-application/src/main/java/com/ohdab/port/in/LoginUsecase.java b/member-module/member-application/src/main/java/com/ohdab/port/in/LoginUsecase.java new file mode 100644 index 00000000..4dddf955 --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/port/in/LoginUsecase.java @@ -0,0 +1,9 @@ +package com.ohdab.port.in; + +import com.ohdab.dto.LoginReqDto; +import com.ohdab.dto.LoginResDto; + +public interface LoginUsecase { + + LoginResDto login(LoginReqDto loginReqDto); +} diff --git a/member-module/member-application/src/main/java/com/ohdab/port/out/FindMemberPort.java b/member-module/member-application/src/main/java/com/ohdab/port/out/FindMemberPort.java new file mode 100644 index 00000000..48ac8b8b --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/port/out/FindMemberPort.java @@ -0,0 +1,8 @@ +package com.ohdab.port.out; + +import com.ohdab.domain.Member; +import java.util.Optional; + +public interface FindMemberPort { + Optional findByMemberProfile_Name(String name); +} diff --git a/member-module/member-application/src/main/java/com/ohdab/port/out/SaveMemberPort.java b/member-module/member-application/src/main/java/com/ohdab/port/out/SaveMemberPort.java new file mode 100644 index 00000000..1082c60a --- /dev/null +++ b/member-module/member-application/src/main/java/com/ohdab/port/out/SaveMemberPort.java @@ -0,0 +1,8 @@ +package com.ohdab.port.out; + +import com.ohdab.domain.Member; + +public interface SaveMemberPort { + + void save(Member member); +} diff --git a/member-module/member-persistence-adapter/build.gradle b/member-module/member-persistence-adapter/build.gradle new file mode 100644 index 00000000..94d3fee6 --- /dev/null +++ b/member-module/member-persistence-adapter/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':member-module:member-application') + + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1' + runtimeOnly 'com.h2database:h2' + + testImplementation 'com.h2database:h2:2.1.214' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/member-module/member-persistence-adapter/src/main/java/com/ohdab/FindMemberDbAdapter.java b/member-module/member-persistence-adapter/src/main/java/com/ohdab/FindMemberDbAdapter.java new file mode 100644 index 00000000..c56ab244 --- /dev/null +++ b/member-module/member-persistence-adapter/src/main/java/com/ohdab/FindMemberDbAdapter.java @@ -0,0 +1,27 @@ +package com.ohdab; + +import com.ohdab.domain.Member; +import com.ohdab.entity.MemberEntity; +import com.ohdab.mapper.MemberPersistenceMapper; +import com.ohdab.port.out.FindMemberPort; +import com.ohdab.repository.MemberRepository; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class FindMemberDbAdapter implements FindMemberPort { + + private final MemberRepository memberRepository; + + @Override + public Optional findByMemberProfile_Name(String name) { + Optional memberJpaOpt = memberRepository.findByProfileVO_Name(name); + if (memberJpaOpt.isEmpty()) { + return Optional.empty(); + } + Member member = MemberPersistenceMapper.toDomain(memberJpaOpt.get()); + return Optional.of(member); + } +} diff --git a/member-module/member-persistence-adapter/src/main/java/com/ohdab/SaveMemberAdapter.java b/member-module/member-persistence-adapter/src/main/java/com/ohdab/SaveMemberAdapter.java new file mode 100644 index 00000000..421e0521 --- /dev/null +++ b/member-module/member-persistence-adapter/src/main/java/com/ohdab/SaveMemberAdapter.java @@ -0,0 +1,22 @@ +package com.ohdab; + +import com.ohdab.domain.Member; +import com.ohdab.entity.MemberEntity; +import com.ohdab.mapper.MemberPersistenceMapper; +import com.ohdab.port.out.SaveMemberPort; +import com.ohdab.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class SaveMemberAdapter implements SaveMemberPort { + + private final MemberRepository memberRepository; + + @Override + public void save(Member member) { + MemberEntity memberEntity = MemberPersistenceMapper.toEntity(member); + memberRepository.save(memberEntity); + } +} diff --git a/member-module/member-persistence-adapter/src/main/java/com/ohdab/entity/AuthorityVO.java b/member-module/member-persistence-adapter/src/main/java/com/ohdab/entity/AuthorityVO.java new file mode 100644 index 00000000..433a6b04 --- /dev/null +++ b/member-module/member-persistence-adapter/src/main/java/com/ohdab/entity/AuthorityVO.java @@ -0,0 +1,14 @@ +package com.ohdab.entity; + +import javax.persistence.Embeddable; +import lombok.*; + +@Embeddable +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AuthorityVO { + + private String role; +} diff --git a/member-module/member-persistence-adapter/src/main/java/com/ohdab/entity/MemberEntity.java b/member-module/member-persistence-adapter/src/main/java/com/ohdab/entity/MemberEntity.java new file mode 100644 index 00000000..73809f95 --- /dev/null +++ b/member-module/member-persistence-adapter/src/main/java/com/ohdab/entity/MemberEntity.java @@ -0,0 +1,32 @@ +package com.ohdab.entity; + +import java.util.List; +import javax.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "MEMBER") +public class MemberEntity { + + @Id + @GeneratedValue + @Column(name = "member_id") + private Long id; + + @Embedded private ProfileVO profileVO; + + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(name = "MEMBER_AUTHORITY_LIST", joinColumns = @JoinColumn(name = "member_id")) + private List authorities; + + @Builder + public MemberEntity(ProfileVO profileVO, List authorities) { + this.profileVO = profileVO; + this.authorities = authorities; + } +} diff --git a/member-module/member-persistence-adapter/src/main/java/com/ohdab/entity/ProfileVO.java b/member-module/member-persistence-adapter/src/main/java/com/ohdab/entity/ProfileVO.java new file mode 100644 index 00000000..abed468b --- /dev/null +++ b/member-module/member-persistence-adapter/src/main/java/com/ohdab/entity/ProfileVO.java @@ -0,0 +1,19 @@ +package com.ohdab.entity; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import lombok.*; + +@Embeddable +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ProfileVO { + + @Column(name = "member_name") + private String name; + + @Column(name = "member_password") + private String password; +} diff --git a/member-module/member-persistence-adapter/src/main/java/com/ohdab/mapper/MemberPersistenceMapper.java b/member-module/member-persistence-adapter/src/main/java/com/ohdab/mapper/MemberPersistenceMapper.java new file mode 100644 index 00000000..06c61f87 --- /dev/null +++ b/member-module/member-persistence-adapter/src/main/java/com/ohdab/mapper/MemberPersistenceMapper.java @@ -0,0 +1,55 @@ +package com.ohdab.mapper; + +import com.ohdab.domain.Member; +import com.ohdab.domain.authority.Authority; +import com.ohdab.domain.profile.Profile; +import com.ohdab.entity.AuthorityVO; +import com.ohdab.entity.MemberEntity; +import com.ohdab.entity.ProfileVO; +import java.util.List; +import java.util.stream.Collectors; + +public class MemberPersistenceMapper { + + public static Member toDomain(MemberEntity memberEntity) { + + return Member.builder() + .id(memberEntity.getId()) + .profile(toMemberProfile(memberEntity)) + .authorities(toAuthority(memberEntity)) + .build(); + } + + private static Profile toMemberProfile(MemberEntity memberEntity) { + return Profile.builder() + .name(memberEntity.getProfileVO().getName()) + .password(memberEntity.getProfileVO().getPassword()) + .build(); + } + + private static List toAuthority(MemberEntity memberEntity) { + return memberEntity.getAuthorities().stream() + .map(authorityVO -> Authority.builder().role(authorityVO.getRole()).build()) + .collect(Collectors.toList()); + } + + public static MemberEntity toEntity(Member member) { + return MemberEntity.builder() + .profileVO(toMemberProfileJpa(member)) + .authorities(toAuthorityJpa(member)) + .build(); + } + + private static ProfileVO toMemberProfileJpa(Member member) { + return ProfileVO.builder() + .name(member.getProfile().getName()) + .password(member.getProfile().getPassword()) + .build(); + } + + private static List toAuthorityJpa(Member member) { + return member.getAuthorities().stream() + .map(authority -> AuthorityVO.builder().role(authority.getRole()).build()) + .collect(Collectors.toList()); + } +} diff --git a/member-module/member-persistence-adapter/src/main/java/com/ohdab/repository/MemberRepository.java b/member-module/member-persistence-adapter/src/main/java/com/ohdab/repository/MemberRepository.java new file mode 100644 index 00000000..89beba56 --- /dev/null +++ b/member-module/member-persistence-adapter/src/main/java/com/ohdab/repository/MemberRepository.java @@ -0,0 +1,10 @@ +package com.ohdab.repository; + +import com.ohdab.entity.MemberEntity; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberRepository extends JpaRepository { + + Optional findByProfileVO_Name(String name); +} diff --git a/member-module/member-persistence-adapter/src/test/resources/application.yml b/member-module/member-persistence-adapter/src/test/resources/application.yml new file mode 100644 index 00000000..b076decc --- /dev/null +++ b/member-module/member-persistence-adapter/src/test/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:test + jpa: + hibernate: + ddl-auto: create-drop + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + format_sql: true + use_sql_comments: true \ No newline at end of file diff --git a/member-module/member-web-adapter/build.gradle b/member-module/member-web-adapter/build.gradle new file mode 100644 index 00000000..4581338d --- /dev/null +++ b/member-module/member-web-adapter/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':core-module') + implementation project(':member-module:member-application') + + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + + testImplementation 'com.h2database:h2:2.1.214' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/member-module/member-web-adapter/src/main/java/com/ohdab/MemberController.java b/member-module/member-web-adapter/src/main/java/com/ohdab/MemberController.java new file mode 100644 index 00000000..454aa991 --- /dev/null +++ b/member-module/member-web-adapter/src/main/java/com/ohdab/MemberController.java @@ -0,0 +1,39 @@ +package com.ohdab; + +import com.ohdab.dto.LoginResDto; +import com.ohdab.mapper.MemberWebMapper; +import com.ohdab.port.in.JoinUsecase; +import com.ohdab.port.in.LoginUsecase; +import com.ohdab.request.JoinReq; +import com.ohdab.request.LoginReq; +import com.ohdab.response.JoinRes; +import com.ohdab.response.LoginRes; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/user") +public class MemberController { + + private final JoinUsecase joinUsecase; + private final LoginUsecase loginUsecase; + + @PostMapping("/join") + public ResponseEntity join(@RequestBody JoinReq joinReq) { + joinUsecase.join(MemberWebMapper.toJoinReqDto(joinReq)); + return ResponseEntity.ok(JoinRes.builder().message("회원가입이 완료되었습니다.").build()); + } + + @PostMapping("/login") + public ResponseEntity login(@RequestBody LoginReq loginReq) { + LoginResDto loginResDto = loginUsecase.login(MemberWebMapper.toLoginReqDto(loginReq)); + return ResponseEntity.ok(MemberWebMapper.toLoginResDto(loginResDto)); + } + + @GetMapping("/test") + public String adminAndTokenTest() { + return "hohoho"; + } +} diff --git a/member-module/member-web-adapter/src/main/java/com/ohdab/mapper/MemberWebMapper.java b/member-module/member-web-adapter/src/main/java/com/ohdab/mapper/MemberWebMapper.java new file mode 100644 index 00000000..36b6e6ef --- /dev/null +++ b/member-module/member-web-adapter/src/main/java/com/ohdab/mapper/MemberWebMapper.java @@ -0,0 +1,34 @@ +package com.ohdab.mapper; + +import com.ohdab.dto.JoinReqDto; +import com.ohdab.dto.LoginReqDto; +import com.ohdab.dto.LoginResDto; +import com.ohdab.request.JoinReq; +import com.ohdab.request.LoginReq; +import com.ohdab.response.LoginRes; + +public class MemberWebMapper { + + public static JoinReqDto toJoinReqDto(JoinReq joinReq) { + return JoinReqDto.builder() + .name(joinReq.getName()) + .password(joinReq.getPassword()) + .role(joinReq.getRole()) + .build(); + } + + public static LoginReqDto toLoginReqDto(LoginReq loginReq) { + return LoginReqDto.builder() + .name(loginReq.getName()) + .password(loginReq.getPassword()) + .build(); + } + + public static LoginRes toLoginResDto(LoginResDto loginResDto) { + return LoginRes.builder() + .message("로그인에 성공하였습니다.") + .memberId(loginResDto.getMemberId()) + .jwtToken(loginResDto.getJwtToken()) + .build(); + } +} diff --git a/member-module/member-web-adapter/src/main/java/com/ohdab/request/JoinReq.java b/member-module/member-web-adapter/src/main/java/com/ohdab/request/JoinReq.java new file mode 100644 index 00000000..78f73e05 --- /dev/null +++ b/member-module/member-web-adapter/src/main/java/com/ohdab/request/JoinReq.java @@ -0,0 +1,21 @@ +package com.ohdab.request; + +import java.util.List; +import javax.validation.constraints.NotNull; +import lombok.*; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class JoinReq { + + @NotNull(message = "이름은 필수 입력 값입니다.") + private String name; + + @NotNull(message = "비밀번호는 필수 입력 값입니다.") + private String password; + + @NotNull(message = "권한정보는 필수 입력 값입니다.") + private List role; +} diff --git a/member-module/member-web-adapter/src/main/java/com/ohdab/request/LoginReq.java b/member-module/member-web-adapter/src/main/java/com/ohdab/request/LoginReq.java new file mode 100644 index 00000000..7647a3c5 --- /dev/null +++ b/member-module/member-web-adapter/src/main/java/com/ohdab/request/LoginReq.java @@ -0,0 +1,17 @@ +package com.ohdab.request; + +import javax.validation.constraints.NotNull; +import lombok.*; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class LoginReq { + + @NotNull(message = "이름은 필수 입력 값입니다.") + private String name; + + @NotNull(message = "비밀번호는 필수 입력 값입니다.") + private String password; +} diff --git a/api-module/src/main/java/com/miracle/user/controller/response/JoinRes.java b/member-module/member-web-adapter/src/main/java/com/ohdab/response/JoinRes.java similarity index 70% rename from api-module/src/main/java/com/miracle/user/controller/response/JoinRes.java rename to member-module/member-web-adapter/src/main/java/com/ohdab/response/JoinRes.java index 62303f34..792c7534 100644 --- a/api-module/src/main/java/com/miracle/user/controller/response/JoinRes.java +++ b/member-module/member-web-adapter/src/main/java/com/ohdab/response/JoinRes.java @@ -1,4 +1,4 @@ -package com.miracle.user.controller.response; +package com.ohdab.response; import lombok.Builder; import lombok.Getter; diff --git a/member-module/member-web-adapter/src/main/java/com/ohdab/response/LoginRes.java b/member-module/member-web-adapter/src/main/java/com/ohdab/response/LoginRes.java new file mode 100644 index 00000000..9f154597 --- /dev/null +++ b/member-module/member-web-adapter/src/main/java/com/ohdab/response/LoginRes.java @@ -0,0 +1,22 @@ +package com.ohdab.response; + +import com.ohdab.dto.LoginResDto; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class LoginRes { + + private String message; + private Long memberId; + private String jwtToken; + + public static LoginRes toRes(LoginResDto loginResDto) { + return LoginRes.builder() + .message("로그인에 성공하였습니다.") + .memberId(loginResDto.getMemberId()) + .jwtToken(loginResDto.getJwtToken()) + .build(); + } +} diff --git a/member-module/member-web-adapter/src/test/resources/application.yml b/member-module/member-web-adapter/src/test/resources/application.yml new file mode 100644 index 00000000..b076decc --- /dev/null +++ b/member-module/member-web-adapter/src/test/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:test + jpa: + hibernate: + ddl-auto: create-drop + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + format_sql: true + use_sql_comments: true \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 28e6f3e3..d4360e91 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,5 +7,25 @@ pluginManagement { } rootProject.name = 'ohdab' include 'core-module' -include 'api-module' +include 'member-module' +include 'member-module:member-web-adapter' +findProject(':member-module:member-web-adapter')?.name = 'member-web-adapter' +include 'member-module:member-application' +findProject(':member-module:member-application')?.name = 'member-application' +include 'member-module:member-persistence-adapter' +findProject(':member-module:member-persistence-adapter')?.name = 'member-persistence-adapter' +include 'teacher-module' +include 'teacher-module:teacher-web-adapter' +findProject(':teacher-module:teacher-web-adapter')?.name = 'teacher-web-adapter' +include 'teacher-module:teacher-application' +findProject(':teacher-module:teacher-application')?.name = 'teacher-application' +include 'teacher-module:teacher-persistence-adapter' +findProject(':teacher-module:teacher-persistence-adapter')?.name = 'teacher-persistence-adapter' +include 'wronganswernote-module' +include 'wronganswernote-module:wronganswernote-web-adapter' +findProject(':wronganswernote-module:wronganswernote-web-adapter')?.name = 'wronganswernote-web-adapter' +include 'wronganswernote-module:wronganswernote-application' +findProject(':wronganswernote-module:wronganswernote-application')?.name = 'wronganswernote-application' +include 'wronganswernote-module:wronganswernote-persistence-adapter' +findProject(':wronganswernote-module:wronganswernote-persistence-adapter')?.name = 'wronganswernote-persistence-adapter' diff --git a/src/main/java/com/miracle/MiracleApplication.java b/src/main/java/com/ohdab/OhDabApplication.java similarity index 62% rename from src/main/java/com/miracle/MiracleApplication.java rename to src/main/java/com/ohdab/OhDabApplication.java index 6f416fc0..bb80aa70 100644 --- a/src/main/java/com/miracle/MiracleApplication.java +++ b/src/main/java/com/ohdab/OhDabApplication.java @@ -1,12 +1,12 @@ -package com.miracle; +package com.ohdab; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class MiracleApplication { +public class OhDabApplication { public static void main(String[] args) { - SpringApplication.run(MiracleApplication.class, args); + SpringApplication.run(OhDabApplication.class, args); } } diff --git a/src/test/java/com/miracle/MiracleApplicationTests.java b/src/test/java/com/ohdab/OhDabApplicationTests.java similarity index 74% rename from src/test/java/com/miracle/MiracleApplicationTests.java rename to src/test/java/com/ohdab/OhDabApplicationTests.java index 52e3046c..9a2ff41e 100644 --- a/src/test/java/com/miracle/MiracleApplicationTests.java +++ b/src/test/java/com/ohdab/OhDabApplicationTests.java @@ -1,10 +1,10 @@ -package com.miracle; +package com.ohdab; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest -class MiracleApplicationTests { +class OhDabApplicationTests { @Test void contextLoads() {} diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml new file mode 100644 index 00000000..b076decc --- /dev/null +++ b/src/test/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:test + jpa: + hibernate: + ddl-auto: create-drop + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + format_sql: true + use_sql_comments: true \ No newline at end of file diff --git a/src/test/resources/jwt.yml b/src/test/resources/jwt.yml new file mode 100644 index 00000000..215a5bce --- /dev/null +++ b/src/test/resources/jwt.yml @@ -0,0 +1,4 @@ +issuer: miracle +authorities-key: auth +secret-key: keyfortestkeyfortestkeyfortestkeyfortestkeyfortestkeyfortestkeyfortestkeyfortestkeyfortestkeyfortestkeyfortestkeyfortest +expiration-minutes: 3600000 \ No newline at end of file diff --git a/teacher-module/build.gradle b/teacher-module/build.gradle new file mode 100644 index 00000000..8a515155 --- /dev/null +++ b/teacher-module/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/teacher-module/teacher-application/build.gradle b/teacher-module/teacher-application/build.gradle new file mode 100644 index 00000000..8a515155 --- /dev/null +++ b/teacher-module/teacher-application/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/teacher-module/teacher-application/src/main/java/com/ohdab/domain/Teacher.java b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/Teacher.java new file mode 100644 index 00000000..4d44e45c --- /dev/null +++ b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/Teacher.java @@ -0,0 +1,14 @@ +package com.ohdab.domain; + +import com.ohdab.domain.group.Group; +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class Teacher { + + private Long id; + private List classes; +} diff --git a/teacher-module/teacher-application/src/main/java/com/ohdab/domain/group/Grade.java b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/group/Grade.java new file mode 100644 index 00000000..0387fa89 --- /dev/null +++ b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/group/Grade.java @@ -0,0 +1,13 @@ +package com.ohdab.domain.group; + +import lombok.Getter; + +@Getter +public enum Grade { + MID_1, + MID_2, + MID_3, + HIGH_1, + HIGH_2, + HIGH_3; +} diff --git a/teacher-module/teacher-application/src/main/java/com/ohdab/domain/group/Group.java b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/group/Group.java new file mode 100644 index 00000000..07e6b6eb --- /dev/null +++ b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/group/Group.java @@ -0,0 +1,16 @@ +package com.ohdab.domain.group; + +import com.ohdab.domain.student.Student; +import com.ohdab.domain.workbook.Workbook; +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class Group { + + private GroupInfo classInfo; + private List workbooks; + private List students; +} diff --git a/teacher-module/teacher-application/src/main/java/com/ohdab/domain/group/GroupInfo.java b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/group/GroupInfo.java new file mode 100644 index 00000000..a92e8957 --- /dev/null +++ b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/group/GroupInfo.java @@ -0,0 +1,12 @@ +package com.ohdab.domain.group; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class GroupInfo { + + private String name; + private Grade grade; +} diff --git a/teacher-module/teacher-application/src/main/java/com/ohdab/domain/student/Student.java b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/student/Student.java new file mode 100644 index 00000000..15d9d243 --- /dev/null +++ b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/student/Student.java @@ -0,0 +1,11 @@ +package com.ohdab.domain.student; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class Student { + + private String name; +} diff --git a/teacher-module/teacher-application/src/main/java/com/ohdab/domain/workbook/Workbook.java b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/workbook/Workbook.java new file mode 100644 index 00000000..80d4501c --- /dev/null +++ b/teacher-module/teacher-application/src/main/java/com/ohdab/domain/workbook/Workbook.java @@ -0,0 +1,14 @@ +package com.ohdab.domain.workbook; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class Workbook { + + private String name; + private String description; + private int startingNumber; + private int endingNumber; +} diff --git a/teacher-module/teacher-persistence-adapter/build.gradle b/teacher-module/teacher-persistence-adapter/build.gradle new file mode 100644 index 00000000..895c58d8 --- /dev/null +++ b/teacher-module/teacher-persistence-adapter/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':teacher-module:teacher-application') + + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1' + runtimeOnly 'com.h2database:h2' + + testImplementation 'com.h2database:h2:2.1.214' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/teacher-module/teacher-persistence-adapter/src/test/resources/application.yml b/teacher-module/teacher-persistence-adapter/src/test/resources/application.yml new file mode 100644 index 00000000..b076decc --- /dev/null +++ b/teacher-module/teacher-persistence-adapter/src/test/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:test + jpa: + hibernate: + ddl-auto: create-drop + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + format_sql: true + use_sql_comments: true \ No newline at end of file diff --git a/teacher-module/teacher-web-adapter/build.gradle b/teacher-module/teacher-web-adapter/build.gradle new file mode 100644 index 00000000..c652c02c --- /dev/null +++ b/teacher-module/teacher-web-adapter/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':core-module') + implementation project(':teacher-module:teacher-application') + + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + + testImplementation 'com.h2database:h2:2.1.214' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/teacher-module/teacher-web-adapter/src/test/resources/application.yml b/teacher-module/teacher-web-adapter/src/test/resources/application.yml new file mode 100644 index 00000000..b076decc --- /dev/null +++ b/teacher-module/teacher-web-adapter/src/test/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:test + jpa: + hibernate: + ddl-auto: create-drop + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + format_sql: true + use_sql_comments: true \ No newline at end of file diff --git a/wronganswernote-module/build.gradle b/wronganswernote-module/build.gradle new file mode 100644 index 00000000..8a515155 --- /dev/null +++ b/wronganswernote-module/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/wronganswernote-module/wronganswernote-application/build.gradle b/wronganswernote-module/wronganswernote-application/build.gradle new file mode 100644 index 00000000..8a515155 --- /dev/null +++ b/wronganswernote-module/wronganswernote-application/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/WrongAnswerNote.java b/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/WrongAnswerNote.java new file mode 100644 index 00000000..bb0d14c5 --- /dev/null +++ b/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/WrongAnswerNote.java @@ -0,0 +1,18 @@ +package com.ohdab.domain; + +import com.ohdab.domain.student.Student; +import com.ohdab.domain.workbook.Workbook; +import com.ohdab.domain.wrongInfo.WrongInfo; +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class WrongAnswerNote { + + private Long id; + private Workbook workbook; + private Student student; + private List wrongInfos; +} diff --git a/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/student/Student.java b/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/student/Student.java new file mode 100644 index 00000000..15d9d243 --- /dev/null +++ b/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/student/Student.java @@ -0,0 +1,11 @@ +package com.ohdab.domain.student; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class Student { + + private String name; +} diff --git a/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/workbook/Workbook.java b/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/workbook/Workbook.java new file mode 100644 index 00000000..80d4501c --- /dev/null +++ b/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/workbook/Workbook.java @@ -0,0 +1,14 @@ +package com.ohdab.domain.workbook; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class Workbook { + + private String name; + private String description; + private int startingNumber; + private int endingNumber; +} diff --git a/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/wrongInfo/WrongInfo.java b/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/wrongInfo/WrongInfo.java new file mode 100644 index 00000000..39019941 --- /dev/null +++ b/wronganswernote-module/wronganswernote-application/src/main/java/com/ohdab/domain/wrongInfo/WrongInfo.java @@ -0,0 +1,12 @@ +package com.ohdab.domain.wrongInfo; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class WrongInfo { + + private int problemNumber; + private int wrongCount; +} diff --git a/wronganswernote-module/wronganswernote-persistence-adapter/build.gradle b/wronganswernote-module/wronganswernote-persistence-adapter/build.gradle new file mode 100644 index 00000000..87e9d7a2 --- /dev/null +++ b/wronganswernote-module/wronganswernote-persistence-adapter/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':wronganswernote-module:wronganswernote-application') + + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1' + runtimeOnly 'com.h2database:h2' + + testImplementation 'com.h2database:h2:2.1.214' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/wronganswernote-module/wronganswernote-persistence-adapter/src/test/resources/application.yml b/wronganswernote-module/wronganswernote-persistence-adapter/src/test/resources/application.yml new file mode 100644 index 00000000..b076decc --- /dev/null +++ b/wronganswernote-module/wronganswernote-persistence-adapter/src/test/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:test + jpa: + hibernate: + ddl-auto: create-drop + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + format_sql: true + use_sql_comments: true \ No newline at end of file diff --git a/wronganswernote-module/wronganswernote-web-adapter/build.gradle b/wronganswernote-module/wronganswernote-web-adapter/build.gradle new file mode 100644 index 00000000..10fc1c33 --- /dev/null +++ b/wronganswernote-module/wronganswernote-web-adapter/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' +} + +group 'org.example' +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':core-module') + implementation project(':wronganswernote-module:wronganswernote-application') + + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + + testImplementation 'com.h2database:h2:2.1.214' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/wronganswernote-module/wronganswernote-web-adapter/src/test/resources/application.yml b/wronganswernote-module/wronganswernote-web-adapter/src/test/resources/application.yml new file mode 100644 index 00000000..b076decc --- /dev/null +++ b/wronganswernote-module/wronganswernote-web-adapter/src/test/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:test + jpa: + hibernate: + ddl-auto: create-drop + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + format_sql: true + use_sql_comments: true \ No newline at end of file