├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── resources │ ├── templates │ │ ├── connect-logo.png │ │ ├── PrivacyPolicy.html │ │ └── UseTerm.html │ └── application.yml │ └── java │ └── com │ └── project │ └── qvick │ ├── global │ ├── security │ │ ├── jwt │ │ │ ├── enums │ │ │ │ └── JwtType.java │ │ │ ├── exception │ │ │ │ ├── TokenTypeException.java │ │ │ │ ├── TokenErrorException.java │ │ │ │ ├── TokenExpiredException.java │ │ │ │ ├── TokenNotSupportException.java │ │ │ │ └── error │ │ │ │ │ └── JwtTokenError.java │ │ │ ├── config │ │ │ │ └── JwtProperties.java │ │ │ ├── handler │ │ │ │ └── JwtAuthenticationEntryPoint.java │ │ │ ├── filter │ │ │ │ ├── JwtAuthenticationFilter.java │ │ │ │ └── JwtExceptionFilter.java │ │ │ ├── JwtProvider.java │ │ │ └── JwtExtract.java │ │ ├── auth │ │ │ └── CustomUserDetails.java │ │ └── config │ │ │ └── SecurityConfig.java │ ├── common │ │ ├── repository │ │ │ ├── UserSecurity.java │ │ │ └── UserSecurityImpl.java │ │ ├── config │ │ │ ├── OpenAPI30Config.java │ │ │ ├── QuerydslConfig.java │ │ │ ├── SwaggerConfig.java │ │ │ ├── WebMvcConfig.java │ │ │ └── RestTemplateConfig.java │ │ ├── client │ │ │ ├── dto │ │ │ │ ├── request │ │ │ │ │ └── PageRequest.java │ │ │ │ └── response │ │ │ │ │ ├── BaseResponse.java │ │ │ │ │ └── BaseResponseData.java │ │ │ └── controller │ │ │ │ └── TermController.java │ │ └── entity │ │ │ └── BaseTimeEntity.java │ ├── exception │ │ ├── error │ │ │ ├── ErrorProperty.java │ │ │ └── ErrorCode.java │ │ ├── BusinessException.java │ │ ├── BadRequestException.java │ │ └── handler │ │ │ └── ExceptionAdvice.java │ └── annotation │ │ ├── Jwt.java │ │ ├── Util.java │ │ ├── Mapper.java │ │ └── SecurityConfiguration.java │ ├── domain │ ├── check │ │ ├── client │ │ │ ├── dto │ │ │ │ ├── request │ │ │ │ │ └── CodeRequest.java │ │ │ │ └── response │ │ │ │ │ └── CheckCodeResponse.java │ │ │ └── api │ │ │ │ └── CheckController.java │ │ ├── application │ │ │ └── service │ │ │ │ ├── CheckCodeService.java │ │ │ │ └── CheckCodeServiceImpl.java │ │ ├── exception │ │ │ ├── CheckCodeError.java │ │ │ ├── CheckAlreadyExistsException.java │ │ │ ├── CheckCodeExpirationException.java │ │ │ └── error │ │ │ │ └── CheckError.java │ │ └── domain │ │ │ ├── mapper │ │ │ └── CheckCodeMapper.java │ │ │ ├── repository │ │ │ └── jpa │ │ │ │ └── CheckCodeRepository.java │ │ │ └── CheckCodeEntity.java │ ├── post │ │ ├── client │ │ │ ├── dto │ │ │ │ ├── request │ │ │ │ │ ├── PostDeleteRequest.java │ │ │ │ │ ├── PostRegisterRequest.java │ │ │ │ │ ├── PostEditRequest.java │ │ │ │ │ └── PostSearchRequest.java │ │ │ │ └── Post.java │ │ │ └── api │ │ │ │ └── PostController.java │ │ ├── domain │ │ │ ├── repository │ │ │ │ ├── jpa │ │ │ │ │ └── PostRepository.java │ │ │ │ └── query │ │ │ │ │ ├── PostQueryRepository.java │ │ │ │ │ └── PostQueryRepositoryImpl.java │ │ │ ├── PostEntity.java │ │ │ └── mapper │ │ │ │ └── PostMapper.java │ │ ├── exception │ │ │ ├── PostExistException.java │ │ │ ├── PostNotFoundException.java │ │ │ └── error │ │ │ │ └── PostError.java │ │ └── application │ │ │ ├── query │ │ │ ├── PostQueryService.java │ │ │ └── PostQueryServiceImpl.java │ │ │ ├── service │ │ │ ├── PostService.java │ │ │ └── PostServiceImpl.java │ │ │ └── util │ │ │ └── PostUtil.java │ ├── auth │ │ ├── client │ │ │ ├── dto │ │ │ │ ├── request │ │ │ │ │ ├── SignInRequest.java │ │ │ │ │ ├── AdminSignUpRequest.java │ │ │ │ │ ├── RefreshTokenRequest.java │ │ │ │ │ └── SignUpRequest.java │ │ │ │ └── response │ │ │ │ │ ├── RefreshTokenResponse.java │ │ │ │ │ └── JsonWebTokenResponse.java │ │ │ └── api │ │ │ │ └── AuthController.java │ │ └── service │ │ │ ├── AuthService.java │ │ │ └── AuthServiceImpl.java │ └── user │ │ ├── client │ │ ├── dto │ │ │ ├── request │ │ │ │ ├── AdminSetStatusRequest.java │ │ │ │ ├── UserSignUpRequest.java │ │ │ │ ├── PasswordEditRequest.java │ │ │ │ ├── AdminPasswordEditRequest.java │ │ │ │ ├── UserSearchRequest.java │ │ │ │ ├── StdIdEditRequest.java │ │ │ │ └── RoomEditRequest.java │ │ │ ├── response │ │ │ │ └── UserPageResponse.java │ │ │ └── User.java │ │ └── api │ │ │ ├── UserController.java │ │ │ └── UserAdminController.java │ │ ├── domain │ │ ├── enums │ │ │ └── UserRole.java │ │ ├── repository │ │ │ ├── jpa │ │ │ │ └── UserRepository.java │ │ │ └── query │ │ │ │ ├── UserQueryRepository.java │ │ │ │ └── UserQueryRepositoryImpl.java │ │ ├── UserEntity.java │ │ └── mapper │ │ │ └── UserMapper.java │ │ ├── exception │ │ ├── UserExistException.java │ │ ├── UserNotFoundException.java │ │ ├── PasswordWrongException.java │ │ └── error │ │ │ └── UserError.java │ │ └── application │ │ ├── query │ │ ├── UserQueryService.java │ │ └── UserQueryServiceImpl.java │ │ ├── service │ │ ├── UserService.java │ │ └── UserServiceImpl.java │ │ └── util │ │ └── UserUtil.java │ └── QvickApplication.java ├── Dockerfile ├── README.md ├── .gitignore ├── .github └── workflows │ └── deploy.yml ├── gradlew.bat └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'qvick' -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-C0nnect/qvick-server-v2/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/templates/connect-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-C0nnect/qvick-server-v2/HEAD/src/main/resources/templates/connect-logo.png -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/enums/JwtType.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.enums; 2 | 3 | public enum JwtType { 4 | 5 | ACCESS, REFRESH 6 | 7 | } -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/client/dto/request/CodeRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.client.dto.request; 2 | 3 | public record CodeRequest( 4 | String code 5 | ){} -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | ARG JAR_FILE=build/libs/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | ENV TZ=Asia/Seoul 5 | ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod","/app.jar","-Duser.timezone=Asia/Seoul"] -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/client/dto/request/PostDeleteRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.client.dto.request; 2 | 3 | public record PostDeleteRequest( 4 | Long postId 5 | ){} -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/auth/client/dto/request/SignInRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.auth.client.dto.request; 2 | 3 | public record SignInRequest( 4 | String email, 5 | String password 6 | ){} 7 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/client/dto/request/PostRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.client.dto.request; 2 | 3 | public record PostRegisterRequest( 4 | String title, 5 | String content 6 | ){} 7 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/client/dto/request/PostEditRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.client.dto.request; 2 | 3 | public record PostEditRequest( 4 | Long postId, 5 | String title, 6 | String content 7 | ){} 8 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/client/dto/response/CheckCodeResponse.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.client.dto.response; 2 | 3 | import lombok.Builder; 4 | 5 | @Builder 6 | public record CheckCodeResponse( 7 | String code 8 | ){} -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/repository/UserSecurity.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.repository; 2 | 3 | import com.project.qvick.domain.user.client.dto.User; 4 | 5 | public interface UserSecurity { 6 | 7 | User getUser(); 8 | 9 | } -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/auth/client/dto/request/AdminSignUpRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.auth.client.dto.request; 2 | 3 | public record AdminSignUpRequest( 4 | String name, 5 | String email, 6 | String password 7 | ){} 8 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/exception/error/ErrorProperty.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.exception.error; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | public interface ErrorProperty { 6 | HttpStatus getStatus(); 7 | String getMessage(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/auth/client/dto/request/RefreshTokenRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.auth.client.dto.request; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | 5 | public record RefreshTokenRequest( 6 | @NotBlank String refreshToken 7 | ){} -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/dto/request/AdminSetStatusRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.dto.request; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class AdminSetStatusRequest { 7 | private String email; 8 | private Long status; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/dto/request/UserSignUpRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.dto.request; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class UserSignUpRequest { 9 | 10 | private Long id; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/auth/client/dto/request/SignUpRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.auth.client.dto.request; 2 | 3 | public record SignUpRequest( 4 | String name, 5 | String email, 6 | String password, 7 | String stdId, 8 | String room 9 | ){} 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qvick V2 2 | 3 | ## 🐱 깃 컨벤션 4 | 5 | feat : 기능 개발

6 | fix : 코드 수정

7 | build : 배포 작업

8 | delete : 코드 삭제

9 | merge : 브랜치 병합 작업

10 | 11 | ## 오픈소스 기여 시 주의사항 12 | repository를 fork후 pr을 반드시 한 후에 해주세요.

13 | 가급적 올리기 전에 connect 메일이나 개발자 개인 연락처로 연락 후에 해주세요. (개발 시에 혼선 방지를 위해) 14 | 15 | ** 개발팀의 충분한 검토 후에 병합이 이루어집니다 참고해 주세요! 16 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/dto/request/PasswordEditRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.dto.request; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class PasswordEditRequest { 9 | 10 | private String oldPassword; 11 | private String newPassword; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/dto/request/AdminPasswordEditRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.dto.request; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class AdminPasswordEditRequest { 9 | 10 | private String newPassword; 11 | private String email; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/application/service/CheckCodeService.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.application.service; 2 | 3 | import com.project.qvick.domain.check.client.dto.response.CheckCodeResponse; 4 | 5 | import java.util.concurrent.CompletableFuture; 6 | 7 | public interface CheckCodeService { 8 | 9 | CompletableFuture generate(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/auth/client/dto/response/RefreshTokenResponse.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.auth.client.dto.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | 7 | @Builder 8 | @JsonInclude(JsonInclude.Include.NON_EMPTY) 9 | public record RefreshTokenResponse( 10 | String accessToken 11 | ){} 12 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/client/dto/request/PostSearchRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.client.dto.request; 2 | 3 | import com.project.qvick.global.common.client.dto.request.PageRequest; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | public class PostSearchRequest extends PageRequest { 10 | 11 | private String title; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/dto/request/UserSearchRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.dto.request; 2 | 3 | import com.project.qvick.global.common.client.dto.request.PageRequest; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | public class UserSearchRequest extends PageRequest { 10 | 11 | private String name; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/exception/BusinessException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.exception; 2 | 3 | import com.project.qvick.global.exception.error.ErrorProperty; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | 7 | @Getter 8 | @RequiredArgsConstructor 9 | public class BusinessException extends RuntimeException { 10 | 11 | private final ErrorProperty error; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/domain/enums/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.domain.enums; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | 6 | @Getter 7 | @RequiredArgsConstructor 8 | public enum UserRole { 9 | 10 | ADMIN("ROLE_ADMIN"), 11 | TEACHER("ROLE_TEACHER"), 12 | GUEST("ROLE_GUEST"), 13 | USER("ROLE_USER"); 14 | 15 | private final String key; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/exception/BadRequestException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.exception; 2 | 3 | import com.project.qvick.global.exception.error.ErrorCode; 4 | 5 | public class BadRequestException extends BusinessException { 6 | 7 | public static final BadRequestException EXCEPTION = new BadRequestException(); 8 | 9 | private BadRequestException(){ 10 | super(ErrorCode.BAD_REQUEST); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/auth/client/dto/response/JsonWebTokenResponse.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.auth.client.dto.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.project.qvick.domain.user.domain.enums.UserRole; 5 | import lombok.Builder; 6 | 7 | @Builder 8 | @JsonInclude(JsonInclude.Include.NON_EMPTY) 9 | public record JsonWebTokenResponse( 10 | String accessToken, 11 | String refreshToken, 12 | UserRole userRole 13 | ){} -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/dto/response/UserPageResponse.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.dto.response; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class UserPageResponse { 15 | 16 | private Long id; 17 | private String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/annotation/Jwt.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.annotation; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | @Component 11 | @Target(ElementType.TYPE) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface Jwt { 14 | //Jwt 정의 annotation 클래스 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/annotation/Util.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.annotation; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | @Component 11 | @Target(ElementType.TYPE) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface Util { 14 | //Util 정의 annotation 클래스 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/domain/repository/jpa/PostRepository.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.domain.repository.jpa; 2 | 3 | import com.project.qvick.domain.post.domain.PostEntity; 4 | import jakarta.transaction.Transactional; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface PostRepository extends JpaRepository { 8 | 9 | @Transactional(rollbackOn = Exception.class) 10 | void deleteById(Long id); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/annotation/Mapper.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.annotation; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | @Component 11 | @Target(ElementType.TYPE) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface Mapper { 14 | // Mapper 정의 annotation 클래스 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/exception/CheckCodeError.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.exception; 2 | 3 | import com.project.qvick.domain.check.exception.error.CheckError; 4 | import com.project.qvick.global.exception.BusinessException; 5 | 6 | public class CheckCodeError extends BusinessException { 7 | 8 | public static final CheckCodeError EXCEPTION = new CheckCodeError(); 9 | 10 | private CheckCodeError() { 11 | super(CheckError.CHECK_ERROR); 12 | } 13 | 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/exception/PostExistException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.exception; 2 | 3 | import com.project.qvick.domain.post.exception.error.PostError; 4 | import com.project.qvick.global.exception.BusinessException; 5 | 6 | public class PostExistException extends BusinessException { 7 | 8 | public static final PostExistException EXCEPTION = new PostExistException(); 9 | 10 | private PostExistException() { 11 | super(PostError.POST_EXIST); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/exception/UserExistException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.exception; 2 | 3 | import com.project.qvick.domain.user.exception.error.UserError; 4 | import com.project.qvick.global.exception.BusinessException; 5 | 6 | public class UserExistException extends BusinessException { 7 | 8 | public static final UserExistException EXCEPTION = new UserExistException(); 9 | 10 | private UserExistException(){ 11 | super(UserError.USER_EXIST); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/exception/PostNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.exception; 2 | 3 | import com.project.qvick.domain.post.exception.error.PostError; 4 | import com.project.qvick.global.exception.BusinessException; 5 | 6 | public class PostNotFoundException extends BusinessException { 7 | 8 | public static final PostNotFoundException EXCEPTION = new PostNotFoundException(); 9 | 10 | private PostNotFoundException() { 11 | super(PostError.POST_NOT_FOUND); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/exception/UserNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.exception; 2 | 3 | import com.project.qvick.domain.user.exception.error.UserError; 4 | import com.project.qvick.global.exception.BusinessException; 5 | 6 | public class UserNotFoundException extends BusinessException { 7 | 8 | public static final UserNotFoundException EXCEPTION = new UserNotFoundException(); 9 | 10 | private UserNotFoundException(){ 11 | super(UserError.USER_NOT_FOUND); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/exception/PasswordWrongException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.exception; 2 | 3 | import com.project.qvick.domain.user.exception.error.UserError; 4 | import com.project.qvick.global.exception.BusinessException; 5 | 6 | public class PasswordWrongException extends BusinessException { 7 | 8 | public static final PasswordWrongException EXCEPTION = new PasswordWrongException(); 9 | 10 | private PasswordWrongException() { 11 | super(UserError.PASSWORD_WRONG); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/exception/error/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.exception.error; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.http.HttpStatus; 6 | 7 | @Getter 8 | @RequiredArgsConstructor 9 | public enum ErrorCode implements ErrorProperty { 10 | 11 | BAD_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."), 12 | NOT_FOUND(HttpStatus.NOT_FOUND, "리소스를 찾을 수 없습니다."); 13 | 14 | private final HttpStatus status; 15 | private final String message; 16 | 17 | } -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/application/query/PostQueryService.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.application.query; 2 | 3 | import com.project.qvick.domain.post.client.dto.Post; 4 | import com.project.qvick.domain.post.client.dto.request.PostSearchRequest; 5 | import com.project.qvick.global.common.client.dto.request.PageRequest; 6 | 7 | import java.util.List; 8 | 9 | public interface PostQueryService { 10 | List postList(PageRequest pageRequest); 11 | 12 | List postSearch(PostSearchRequest postSearchRequest); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/domain/repository/query/PostQueryRepository.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.domain.repository.query; 2 | 3 | import com.project.qvick.domain.post.client.dto.Post; 4 | import com.project.qvick.domain.post.client.dto.request.PostSearchRequest; 5 | import com.project.qvick.global.common.client.dto.request.PageRequest; 6 | 7 | import java.util.List; 8 | 9 | public interface PostQueryRepository { 10 | List postList(PageRequest request); 11 | 12 | ListpostSearch(PostSearchRequest request); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/dto/request/StdIdEditRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.dto.request; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import jakarta.validation.constraints.NotBlank; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import org.hibernate.validator.constraints.Length; 8 | 9 | @Getter 10 | @Setter 11 | public class StdIdEditRequest { 12 | 13 | @Schema(description = "수정할 학번") 14 | @NotBlank 15 | @Length(max = 4, min = 4) 16 | private String stdId; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/config/OpenAPI30Config.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.config; 2 | 3 | import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; 4 | import io.swagger.v3.oas.annotations.security.SecurityScheme; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | @SecurityScheme( 9 | name = "BearerAuthentication", 10 | type = SecuritySchemeType.HTTP, 11 | bearerFormat = "JWT", 12 | scheme = "Bearer" 13 | ) 14 | public class OpenAPI30Config { 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/exception/TokenTypeException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.exception; 2 | 3 | import com.project.qvick.global.security.jwt.exception.error.JwtTokenError; 4 | import com.project.qvick.global.exception.BusinessException; 5 | 6 | public class TokenTypeException extends BusinessException { 7 | 8 | public static final TokenTypeException EXCEPTION = new TokenTypeException(); 9 | 10 | private TokenTypeException() { 11 | super(JwtTokenError.JWT_TOKEN_ERROR); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/exception/CheckAlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.exception; 2 | 3 | import com.project.qvick.domain.check.exception.error.CheckError; 4 | import com.project.qvick.global.exception.BusinessException; 5 | 6 | public class CheckAlreadyExistsException extends BusinessException { 7 | 8 | public static final CheckAlreadyExistsException EXCEPTION = new CheckAlreadyExistsException(); 9 | 10 | private CheckAlreadyExistsException() { 11 | super(CheckError.CHECK_CONFLICT); 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/exception/TokenErrorException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.exception; 2 | 3 | import com.project.qvick.global.exception.BusinessException; 4 | import com.project.qvick.global.security.jwt.exception.error.JwtTokenError; 5 | 6 | public class TokenErrorException extends BusinessException { 7 | 8 | public static final TokenErrorException EXCEPTION = new TokenErrorException(); 9 | 10 | private TokenErrorException() { 11 | super(JwtTokenError.JWT_TOKEN_ERROR); 12 | } 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/exception/TokenExpiredException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.exception; 2 | 3 | import com.project.qvick.global.exception.BusinessException; 4 | import com.project.qvick.global.security.jwt.exception.error.JwtTokenError; 5 | 6 | public class TokenExpiredException extends BusinessException { 7 | 8 | public static final TokenExpiredException EXCEPTION = new TokenExpiredException(); 9 | 10 | private TokenExpiredException() { 11 | super(JwtTokenError.JWT_EXPIRED); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/client/dto/request/PageRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.client.dto.request; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * 페이징 처리 설정 8 | */ 9 | @Getter 10 | @Setter 11 | public class PageRequest { 12 | 13 | private int page; 14 | private int size; 15 | 16 | public PageRequest() { 17 | page = 1; 18 | size = 15; 19 | } 20 | 21 | public PageRequest(int page, int size) { 22 | this.page = page; 23 | this.size = size; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/exception/CheckCodeExpirationException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.exception; 2 | 3 | import com.project.qvick.domain.check.exception.error.CheckError; 4 | import com.project.qvick.global.exception.BusinessException; 5 | 6 | public class CheckCodeExpirationException extends BusinessException { 7 | 8 | public static final CheckCodeExpirationException EXCEPTION = new CheckCodeExpirationException(); 9 | 10 | private CheckCodeExpirationException(){ 11 | super(CheckError.CHECK_CODE_EXPIRATION); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/dto/request/RoomEditRequest.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.dto.request; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import jakarta.validation.constraints.NotBlank; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import org.hibernate.validator.constraints.Length; 8 | 9 | @Getter 10 | @Setter 11 | public class RoomEditRequest { 12 | 13 | @Schema(description = "수정할 호실") 14 | @NotBlank 15 | @Length(max = 4, min = 4) 16 | private String room; 17 | private String stdId; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/exception/TokenNotSupportException.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.exception; 2 | 3 | import com.project.qvick.global.exception.BusinessException; 4 | import com.project.qvick.global.security.jwt.exception.error.JwtTokenError; 5 | 6 | public class TokenNotSupportException extends BusinessException { 7 | 8 | public static final TokenNotSupportException EXCEPTION = new TokenNotSupportException(); 9 | 10 | private TokenNotSupportException() { 11 | super(JwtTokenError.JWT_NOT_SUPPORT); 12 | } 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/QvickApplication.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 6 | import org.springframework.scheduling.annotation.EnableScheduling; 7 | 8 | @EnableJpaAuditing 9 | @SpringBootApplication 10 | @EnableScheduling 11 | public class QvickApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(QvickApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/exception/error/PostError.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.exception.error; 2 | 3 | import com.project.qvick.global.exception.error.ErrorProperty; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.http.HttpStatus; 7 | 8 | @Getter 9 | @RequiredArgsConstructor 10 | public enum PostError implements ErrorProperty { 11 | 12 | POST_NOT_FOUND(HttpStatus.NOT_FOUND, "게시글을 찾을 수 없습니다."), 13 | POST_EXIST(HttpStatus.CONFLICT, "이미 처리된 게시글입니다."); 14 | 15 | private final HttpStatus status; 16 | private final String message; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/annotation/SecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.annotation; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | @Configuration 12 | @EnableWebSecurity 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface SecurityConfiguration { 16 | //SecurityConfig 정의 annotation 클래스 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/application/service/PostService.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.application.service; 2 | 3 | import com.project.qvick.domain.post.client.dto.Post; 4 | import com.project.qvick.domain.post.client.dto.request.PostDeleteRequest; 5 | import com.project.qvick.domain.post.client.dto.request.PostEditRequest; 6 | import com.project.qvick.domain.post.client.dto.request.PostRegisterRequest; 7 | 8 | public interface PostService { 9 | 10 | void postRegister(PostRegisterRequest request); 11 | 12 | Post postFind(Long postId); 13 | 14 | void postEdit(PostEditRequest request); 15 | 16 | void postDelete(PostDeleteRequest request); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/domain/repository/jpa/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.domain.repository.jpa; 2 | 3 | import com.project.qvick.domain.user.domain.UserEntity; 4 | import jakarta.transaction.Transactional; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | import java.util.Optional; 8 | 9 | /** 유저 Repository */ 10 | public interface UserRepository extends JpaRepository { 11 | 12 | Optional findByEmail(String email); 13 | 14 | Optional findByStdId(String stdId); 15 | 16 | @Transactional(rollbackOn = Exception.class) 17 | void deleteByEmail(String email); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/domain/mapper/CheckCodeMapper.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.domain.mapper; 2 | 3 | import com.project.qvick.domain.check.domain.CheckCodeEntity; 4 | import com.project.qvick.global.annotation.Mapper; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.UUID; 8 | 9 | @Mapper 10 | public class CheckCodeMapper { 11 | 12 | public CheckCodeEntity createCheckCodeEntity(final Long userId) { 13 | return CheckCodeEntity.builder() 14 | .userId(userId) 15 | .code(UUID.randomUUID().toString().replace("-", "")) 16 | .valid(true) 17 | .build(); 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/exception/error/UserError.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.exception.error; 2 | 3 | import com.project.qvick.global.exception.error.ErrorProperty; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.http.HttpStatus; 7 | 8 | @Getter 9 | @RequiredArgsConstructor 10 | public enum UserError implements ErrorProperty { 11 | 12 | USER_NOT_FOUND(HttpStatus.NOT_FOUND, "유저를 찾을 수 없습니다."), 13 | PASSWORD_WRONG(HttpStatus.BAD_REQUEST, "비밀번호가 맞지 않습니다."), 14 | USER_EXIST(HttpStatus.CONFLICT, "이미 존재하는 유저입니다."); 15 | 16 | private final HttpStatus status; 17 | private final String message; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | /src/main/resources/application-local.yml 8 | /src/main/resources/logback.xml 9 | .DS_Store 10 | 11 | ### STS ### 12 | .apt_generated 13 | .classpath 14 | .factorypath 15 | .project 16 | .settings 17 | .springBeans 18 | .sts4-cache 19 | bin/ 20 | !**/src/main/**/bin/ 21 | !**/src/test/**/bin/ 22 | 23 | ### IntelliJ IDEA ### 24 | .idea 25 | *.iws 26 | *.iml 27 | *.ipr 28 | out/ 29 | !**/src/main/**/out/ 30 | !**/src/test/**/out/ 31 | 32 | ### NetBeans ### 33 | /nbproject/private/ 34 | /nbbuild/ 35 | /dist/ 36 | /nbdist/ 37 | /.nb-gradle/ 38 | 39 | ### VS Code ### 40 | .vscode/ 41 | test/ -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/exception/error/CheckError.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.exception.error; 2 | 3 | import com.project.qvick.global.exception.error.ErrorProperty; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.http.HttpStatus; 7 | 8 | @Getter 9 | @RequiredArgsConstructor 10 | public enum CheckError implements ErrorProperty { 11 | 12 | CHECK_CONFLICT(HttpStatus.CONFLICT, "이미 출석 체크가 완료된 회원입니다."), 13 | CHECK_CODE_EXPIRATION(HttpStatus.BAD_REQUEST,"만료된 QR코드입니다."), 14 | CHECK_ERROR(HttpStatus.BAD_REQUEST, "잘못된 QR코드입니다"); 15 | 16 | private final HttpStatus status; 17 | private final String message; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/config/JwtProperties.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.config; 2 | 3 | 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import org.springframework.boot.context.properties.ConfigurationProperties; 7 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Getter 11 | @Setter 12 | @Configuration 13 | @EnableConfigurationProperties 14 | @ConfigurationProperties(prefix = "application.jwt") 15 | public class JwtProperties { 16 | 17 | private String secretKey; 18 | private long expiration; 19 | private long refreshExpiration; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/client/dto/Post.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.client.dto; 2 | 3 | import com.project.qvick.global.common.entity.BaseTimeEntity; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | @Getter 13 | @Setter 14 | @Builder 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class Post { 18 | 19 | private Long id; 20 | private String title; 21 | private String content; 22 | private String author; 23 | private LocalDateTime createDateTime; 24 | private LocalDateTime modifiedDateTime; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/repository/UserSecurityImpl.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.repository; 2 | 3 | import com.project.qvick.domain.user.client.dto.User; 4 | import com.project.qvick.global.security.auth.CustomUserDetails; 5 | import org.springframework.security.core.context.SecurityContextHolder; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public class UserSecurityImpl implements UserSecurity{ 10 | 11 | @Override 12 | public User getUser() { 13 | return ((CustomUserDetails) SecurityContextHolder 14 | .getContext() 15 | .getAuthentication() 16 | .getPrincipal()) 17 | .getUser(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/exception/error/JwtTokenError.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.exception.error; 2 | 3 | import com.project.qvick.global.exception.error.ErrorProperty; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.http.HttpStatus; 7 | 8 | 9 | @Getter 10 | @RequiredArgsConstructor 11 | public enum JwtTokenError implements ErrorProperty { 12 | 13 | JWT_TOKEN_ERROR(HttpStatus.BAD_REQUEST, "잘못된 타입"), 14 | JWT_EXPIRED(HttpStatus.GONE,"만료된 토큰"), 15 | JWT_ERROR(HttpStatus.BAD_REQUEST,"잘못된 토큰"), 16 | JWT_NOT_SUPPORT(HttpStatus.BAD_REQUEST,"지원하지 않는 토큰"); 17 | 18 | private final HttpStatus status; 19 | private final String message; 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/config/QuerydslConfig.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.config; 2 | 3 | import com.querydsl.jpa.JPQLTemplates; 4 | import com.querydsl.jpa.impl.JPAQueryFactory; 5 | import jakarta.persistence.EntityManager; 6 | import jakarta.persistence.PersistenceContext; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** Querydsl 설정 */ 11 | @Configuration 12 | public class QuerydslConfig { 13 | 14 | @PersistenceContext 15 | public EntityManager entityManager; 16 | 17 | @Bean 18 | public JPAQueryFactory jpaQueryFactory() { 19 | return new JPAQueryFactory(JPQLTemplates.DEFAULT, entityManager); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/auth/service/AuthService.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.auth.service; 2 | 3 | import com.project.qvick.domain.auth.client.dto.request.SignInRequest; 4 | import com.project.qvick.domain.auth.client.dto.request.SignUpRequest; 5 | import com.project.qvick.domain.auth.client.dto.response.JsonWebTokenResponse; 6 | import com.project.qvick.domain.auth.client.dto.response.RefreshTokenResponse; 7 | 8 | public interface AuthService { 9 | 10 | 11 | void signUp(SignUpRequest request); 12 | 13 | void adminSignUp(SignUpRequest request); 14 | 15 | void teacherSignUp(SignUpRequest request); 16 | 17 | JsonWebTokenResponse signIn(SignInRequest request); 18 | 19 | RefreshTokenResponse refresh(String token); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/domain/repository/query/UserQueryRepository.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.domain.repository.query; 2 | 3 | 4 | import com.project.qvick.domain.user.client.dto.User; 5 | import com.project.qvick.domain.user.client.dto.request.UserSearchRequest; 6 | import com.project.qvick.global.common.client.dto.request.PageRequest; 7 | 8 | import java.util.List; 9 | 10 | public interface UserQueryRepository { 11 | 12 | List userList(PageRequest request); 13 | 14 | ListuserSearch(UserSearchRequest request); 15 | 16 | ListstudentList(PageRequest request); 17 | 18 | List checkUsers(PageRequest request); 19 | 20 | List nonCheckUsers(PageRequest request); 21 | 22 | void updateChecked(); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/dto/User.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.dto; 2 | 3 | import com.project.qvick.domain.user.domain.enums.UserRole; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | @Getter 13 | @Setter 14 | @Builder 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class User { 18 | 19 | private Long id; 20 | private String name; 21 | private String email; 22 | private String password; 23 | private String stdId; 24 | private String room; 25 | private UserRole userRole; 26 | private boolean isChecked; 27 | private LocalDateTime checkedDate; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/domain/repository/jpa/CheckCodeRepository.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.domain.repository.jpa; 2 | 3 | import com.project.qvick.domain.check.domain.CheckCodeEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Modifying; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.data.repository.query.Param; 8 | 9 | public interface CheckCodeRepository extends JpaRepository { 10 | 11 | @Modifying 12 | @Query("UPDATE CheckCodeEntity c SET c.valid=false WHERE c.userId=:userId") 13 | void updateAllInvalidCheckCode(@Param("userId") Long userId); 14 | 15 | boolean existsByCodeAndValid(String code, boolean valid); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/client/dto/response/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.client.dto.response; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | import org.springframework.http.HttpStatus; 6 | 7 | @Getter 8 | @Builder 9 | public class BaseResponse { 10 | 11 | private int status; 12 | private String message; 13 | 14 | // public static BaseResponse of(HttpStatus status, String message) { 15 | // return new BaseResponse(status.value(), message); 16 | // } 17 | 18 | public static BaseResponse ok(String message) { 19 | return new BaseResponse(HttpStatus.OK.value(), message); 20 | } 21 | 22 | public static BaseResponse created(String message) { 23 | return new BaseResponse(HttpStatus.CREATED.value(), message); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.config; 2 | 3 | import io.swagger.v3.oas.models.Components; 4 | import io.swagger.v3.oas.models.OpenAPI; 5 | import io.swagger.v3.oas.models.info.Info; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | /** swagger 설정 파일*/ 10 | @Configuration 11 | public class SwaggerConfig { 12 | 13 | @Bean 14 | public OpenAPI openAPI() { 15 | return new OpenAPI() 16 | .components(new Components()) 17 | .info(apiInfo()); 18 | } 19 | 20 | private Info apiInfo() { 21 | return new Info() 22 | .title("Qvick v2") 23 | .description("Qvick API Document") 24 | .version("1.0.0"); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/handler/JwtAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.handler; 2 | 3 | import com.project.qvick.global.annotation.Jwt; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.security.core.AuthenticationException; 7 | import org.springframework.security.web.AuthenticationEntryPoint; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.io.IOException; 11 | 12 | @Jwt 13 | public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { 14 | 15 | @Override 16 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { 17 | response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/client/controller/TermController.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.client.controller; 2 | 3 | import io.swagger.v3.oas.annotations.Operation; 4 | import io.swagger.v3.oas.annotations.tags.Tag; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | 9 | @Controller 10 | @Tag(name = "약관", description = "약관 API") 11 | @RequestMapping("/terms") 12 | public class TermController { 13 | 14 | @GetMapping("/privacy-policy") 15 | @Operation(summary = "개인정보처리약관", description = "개인정보처리약관을 불러옵니다") 16 | public String privacyPolicy(){ 17 | return "PrivacyPolicy"; 18 | } 19 | 20 | @GetMapping("/use-term") 21 | @Operation(summary = "이용약관", description = "이용약관을 불러옵니다") 22 | public String useTerm(){ 23 | return "UseTerm"; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/application/query/UserQueryService.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.application.query; 2 | 3 | import com.project.qvick.domain.user.client.dto.User; 4 | import com.project.qvick.domain.user.client.dto.request.UserSearchRequest; 5 | import com.project.qvick.global.common.client.dto.request.PageRequest; 6 | import org.springframework.scheduling.annotation.Scheduled; 7 | import org.springframework.transaction.annotation.Transactional; 8 | 9 | import java.util.List; 10 | 11 | public interface UserQueryService { 12 | 13 | List userList(PageRequest pageRequest); 14 | 15 | List userSearch(UserSearchRequest searchRequest); 16 | 17 | List studentList(PageRequest pageRequest); 18 | 19 | List checkUsers(PageRequest pageRequest); 20 | 21 | @Transactional 22 | @Scheduled(cron = "0 0 1 * * *") // 매일 오후 8시에 실행 23 | void updateChecked(); 24 | 25 | List nonCheckUsers(PageRequest pageRequest); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/client/dto/response/BaseResponseData.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.client.dto.response; 2 | 3 | import lombok.Getter; 4 | import org.springframework.http.HttpStatus; 5 | 6 | @Getter 7 | public class BaseResponseData extends BaseResponse { 8 | 9 | private final T data; 10 | 11 | private BaseResponseData(HttpStatus status, String message, T data) { 12 | super(status.value(), message); 13 | this.data = data; 14 | } 15 | 16 | public static BaseResponseData of(HttpStatus status, String message, T data) { 17 | return new BaseResponseData<>(status, message, data); 18 | } 19 | 20 | public static BaseResponseData ok(String message, T data) { 21 | return new BaseResponseData<>(HttpStatus.OK, message, data); 22 | } 23 | 24 | public static BaseResponseData created(String message, T data) { 25 | return new BaseResponseData<>(HttpStatus.CREATED, message, data); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/domain/PostEntity.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.domain; 2 | 3 | import com.project.qvick.global.common.entity.BaseTimeEntity; 4 | import jakarta.persistence.Column; 5 | import jakarta.persistence.Entity; 6 | import jakarta.persistence.GeneratedValue; 7 | import jakarta.persistence.GenerationType; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.Table; 10 | import lombok.AccessLevel; 11 | import lombok.Getter; 12 | import lombok.NoArgsConstructor; 13 | import lombok.experimental.SuperBuilder; 14 | 15 | @Entity 16 | @Getter 17 | @SuperBuilder 18 | @Table(name = "tb_post") 19 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 20 | public class PostEntity extends BaseTimeEntity { 21 | 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | private Long id; 25 | 26 | @Column(nullable = false) 27 | private String title; 28 | 29 | @Column(nullable = false) 30 | private String content; 31 | 32 | @Column(nullable = false) 33 | private String author; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/domain/CheckCodeEntity.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.domain; 2 | 3 | import com.project.qvick.global.common.entity.BaseTimeEntity; 4 | import jakarta.persistence.Column; 5 | import jakarta.persistence.Entity; 6 | import jakarta.persistence.GeneratedValue; 7 | import jakarta.persistence.GenerationType; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.Table; 10 | import lombok.AccessLevel; 11 | import lombok.Getter; 12 | import lombok.NoArgsConstructor; 13 | import lombok.experimental.SuperBuilder; 14 | 15 | @Entity 16 | @Getter 17 | @SuperBuilder 18 | @Table(name = "tb_check_code") 19 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 20 | public class CheckCodeEntity extends BaseTimeEntity { 21 | 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | private Long id; 25 | 26 | @Column(nullable = false) 27 | private Long userId; 28 | 29 | @Column(unique = true, nullable = false, length = 50) 30 | private String code; 31 | 32 | private boolean valid; 33 | 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/application/query/PostQueryServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.application.query; 2 | 3 | import com.project.qvick.domain.post.client.dto.Post; 4 | import com.project.qvick.domain.post.client.dto.request.PostSearchRequest; 5 | import com.project.qvick.domain.post.domain.repository.query.PostQueryRepository; 6 | import com.project.qvick.global.common.client.dto.request.PageRequest; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | 12 | @Service 13 | @RequiredArgsConstructor 14 | public class PostQueryServiceImpl implements PostQueryService { 15 | 16 | private final PostQueryRepository postQueryRepository; 17 | 18 | @Override 19 | public List postList(PageRequest pageRequest) { 20 | return postQueryRepository.postList(pageRequest); 21 | } 22 | 23 | @Override 24 | public List postSearch(PostSearchRequest postSearchRequest) { 25 | return postQueryRepository.postSearch(postSearchRequest); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/domain/mapper/PostMapper.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.domain.mapper; 2 | 3 | import com.project.qvick.domain.post.client.dto.Post; 4 | import com.project.qvick.domain.post.domain.PostEntity; 5 | import com.project.qvick.global.annotation.Mapper; 6 | 7 | @Mapper 8 | public class PostMapper { 9 | 10 | public PostEntity toEntity(Post post) { 11 | return PostEntity.builder() 12 | .id(post.getId()) 13 | .title(post.getTitle()) 14 | .content(post.getContent()) 15 | .author(post.getAuthor()) 16 | .createdDateTime(post.getCreateDateTime()) 17 | .build(); 18 | } 19 | 20 | public Post toPost(PostEntity postEntity) { 21 | return Post.builder() 22 | .id(postEntity.getId()) 23 | .title(postEntity.getTitle()) 24 | .content(postEntity.getContent()) 25 | .author(postEntity.getAuthor()) 26 | .createDateTime(postEntity.getCreatedDateTime()) 27 | .build(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/entity/BaseTimeEntity.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import jakarta.persistence.EntityListeners; 5 | import jakarta.persistence.MappedSuperclass; 6 | import lombok.AccessLevel; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.experimental.SuperBuilder; 10 | import org.springframework.data.annotation.CreatedDate; 11 | import org.springframework.data.annotation.LastModifiedDate; 12 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 13 | 14 | import java.time.LocalDateTime; 15 | 16 | @Getter 17 | @EntityListeners(AuditingEntityListener.class) 18 | @MappedSuperclass 19 | @SuperBuilder 20 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 21 | public abstract class BaseTimeEntity { 22 | 23 | @CreatedDate 24 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 25 | protected LocalDateTime createdDateTime; 26 | 27 | @LastModifiedDate 28 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 29 | protected LocalDateTime modifiedDateTime; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/exception/handler/ExceptionAdvice.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.exception.handler; 2 | 3 | import com.project.qvick.global.exception.BusinessException; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | 11 | @RestControllerAdvice 12 | public class ExceptionAdvice { 13 | 14 | @Getter 15 | @Builder 16 | @RequiredArgsConstructor 17 | private static class ErrorResponse { 18 | private final int status; 19 | private final String message; 20 | } 21 | 22 | @ExceptionHandler({BusinessException.class}) 23 | public ResponseEntity handleException(BusinessException ex) { 24 | ErrorResponse response = ErrorResponse.builder() 25 | .status(ex.getError().getStatus().value()) 26 | .message(ex.getError().getMessage()) 27 | .build(); 28 | return new ResponseEntity(response, ex.getError().getStatus()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/application/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.application.service; 2 | 3 | import com.project.qvick.domain.check.client.dto.request.CodeRequest; 4 | import com.project.qvick.domain.user.client.dto.User; 5 | import com.project.qvick.domain.user.client.dto.request.AdminPasswordEditRequest; 6 | import com.project.qvick.domain.user.client.dto.request.AdminSetStatusRequest; 7 | import com.project.qvick.domain.user.client.dto.request.PasswordEditRequest; 8 | import com.project.qvick.domain.user.client.dto.request.RoomEditRequest; 9 | import com.project.qvick.domain.user.client.dto.request.StdIdEditRequest; 10 | 11 | 12 | public interface UserService { 13 | 14 | void editUserStdId(StdIdEditRequest request); 15 | 16 | void deleteUser(); 17 | 18 | void editRoom(RoomEditRequest request); 19 | 20 | User findUser(); 21 | 22 | void check(CodeRequest request); 23 | 24 | void editPassword(PasswordEditRequest request); 25 | 26 | void adminEditPassword(AdminPasswordEditRequest request); 27 | 28 | void adminDeleteUser(String email); 29 | 30 | boolean isChecked(); 31 | 32 | void fixStatus(AdminSetStatusRequest setStatusRequest); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | spring: 5 | profiles: 6 | active: prod 7 | datasource: 8 | hikari: 9 | max-lifetime: 170000 # 170초 10 | url: ${secrets.RDS_PATH} 11 | username: ${secrets.DB_USERNAME} 12 | password: ${secrets.DB_PASSWORD} 13 | driver-class-name: com.mysql.cj.jdbc.Driver 14 | 15 | security: 16 | user: 17 | name: ${secrets.SECURITY_USER_NAME} 18 | password: ${secrets.SECURITY_USER_PASSWORD} 19 | 20 | jpa: 21 | database: mysql 22 | database-platform: org.hibernate.dialect.MySQL8Dialect 23 | properties: 24 | hibernate: 25 | dialect: org.hibernate.dialect.MySQL8Dialect 26 | format_sql: true 27 | hibernate: 28 | ddl-auto: update 29 | show-sql: true 30 | 31 | application: 32 | jwt: 33 | secretKey: ${secrets.JWT_SECRET_KEY} 34 | expiration: 172800000 # 48시간 35 | refreshExpiration: 604800000 # 7일 36 | 37 | springdoc: 38 | api-docs: 39 | enabled: true 40 | version: openapi_3_0 41 | path: /v3/api-docs 42 | default-consumes-media-type: application/json 43 | auto-tag-classes: true 44 | swagger-ui: 45 | operationsSorter: method 46 | path: /swagger-ui.html 47 | 48 | logging: 49 | discord: 50 | webhook-url: ${secrets.DISCORD_WEBHOOK_URL} 51 | config: classpath:logback.xml -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/config/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | 8 | @Configuration 9 | public class WebMvcConfig implements WebMvcConfigurer { 10 | 11 | @Override 12 | public void addCorsMappings(CorsRegistry registry) { 13 | registry.addMapping("/**") 14 | .allowedOriginPatterns("*") // 필요한 출처를 명시 15 | .allowedMethods("*") 16 | .allowedHeaders("*") 17 | .allowCredentials(true) 18 | .maxAge(3600); 19 | } 20 | 21 | @Bean 22 | public WebMvcConfigurer corsConfigurer() { 23 | return new WebMvcConfigurer() { 24 | @Override 25 | public void addCorsMappings(CorsRegistry registry) { 26 | registry.addMapping("/**") 27 | .allowedOriginPatterns("*") 28 | .allowedMethods("*") 29 | .allowedHeaders("*") 30 | .allowCredentials(true) 31 | .maxAge(3600); 32 | } 33 | }; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/filter/JwtAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.filter; 2 | 3 | import com.project.qvick.global.annotation.Jwt; 4 | import com.project.qvick.global.security.jwt.JwtExtract; 5 | import io.jsonwebtoken.ExpiredJwtException; 6 | import jakarta.servlet.FilterChain; 7 | import jakarta.servlet.ServletException; 8 | import jakarta.servlet.http.HttpServletRequest; 9 | import jakarta.servlet.http.HttpServletResponse; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.security.core.context.SecurityContextHolder; 12 | import org.springframework.web.filter.OncePerRequestFilter; 13 | 14 | import java.io.IOException; 15 | 16 | @Jwt 17 | @RequiredArgsConstructor 18 | public class JwtAuthenticationFilter extends OncePerRequestFilter { 19 | 20 | private final JwtExtract jwtExtractor; 21 | 22 | @Override 23 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 24 | throws ServletException, IOException, ExpiredJwtException { 25 | String token = jwtExtractor.extractTokenFromRequest(request); 26 | if (token != null) { 27 | SecurityContextHolder.getContext().setAuthentication(jwtExtractor.getAuthentication(token)); 28 | } 29 | filterChain.doFilter(request, response); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/application/service/CheckCodeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.application.service; 2 | 3 | import com.project.qvick.domain.check.client.dto.response.CheckCodeResponse; 4 | import com.project.qvick.domain.check.domain.CheckCodeEntity; 5 | import com.project.qvick.domain.check.domain.mapper.CheckCodeMapper; 6 | import com.project.qvick.domain.check.domain.repository.jpa.CheckCodeRepository; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | import java.util.concurrent.CompletableFuture; 12 | 13 | @Service 14 | @RequiredArgsConstructor 15 | @Transactional(rollbackFor = Exception.class) 16 | public class CheckCodeServiceImpl implements CheckCodeService { 17 | 18 | private final CheckCodeRepository checkCodeRepository; 19 | private final CheckCodeMapper checkCodeMapper; 20 | 21 | @Override 22 | public CompletableFuture generate() { 23 | checkCodeRepository.updateAllInvalidCheckCode(1L); 24 | CheckCodeEntity checkCodeEntity = checkCodeRepository 25 | .save(checkCodeMapper.createCheckCodeEntity(1L)); 26 | return CompletableFuture.completedFuture( 27 | CheckCodeResponse.builder() 28 | .code(checkCodeEntity.getCode()) 29 | .build() 30 | ); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/application/util/PostUtil.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.application.util; 2 | 3 | import com.project.qvick.domain.post.client.dto.Post; 4 | import com.project.qvick.domain.post.client.dto.request.PostRegisterRequest; 5 | import com.project.qvick.domain.post.domain.mapper.PostMapper; 6 | import com.project.qvick.domain.post.domain.repository.jpa.PostRepository; 7 | import com.project.qvick.domain.post.exception.PostNotFoundException; 8 | import com.project.qvick.domain.user.application.util.UserUtil; 9 | import com.project.qvick.global.annotation.Util; 10 | import lombok.RequiredArgsConstructor; 11 | 12 | @Util 13 | @RequiredArgsConstructor 14 | public class PostUtil { 15 | 16 | private final PostRepository postRepository; 17 | private final PostMapper postMapper; 18 | private final UserUtil userUtil; 19 | 20 | public Post findPost(Long postId) { 21 | return postRepository 22 | .findById(postId) 23 | .map(postMapper::toPost) 24 | .orElseThrow(()-> PostNotFoundException.EXCEPTION); 25 | } 26 | 27 | public void savePost(PostRegisterRequest request){ 28 | Post post = Post.builder() 29 | .title(request.title()) 30 | .content(request.content()) 31 | .author(userUtil.getUser().getName()) 32 | .build(); 33 | postRepository.save(postMapper.toEntity(post)); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/common/config/RestTemplateConfig.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.common.config; 2 | 3 | import org.apache.hc.client5.http.classic.HttpClient; 4 | import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; 5 | import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; 9 | import org.springframework.web.client.RestTemplate; 10 | 11 | @Configuration 12 | public class RestTemplateConfig { 13 | 14 | @Bean 15 | HttpClient httpClient() { 16 | return HttpClientBuilder.create() 17 | .setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create() 18 | .setMaxConnPerRoute(100) 19 | .setMaxConnTotal(300) 20 | .build()) 21 | .build(); 22 | } 23 | 24 | @Bean 25 | HttpComponentsClientHttpRequestFactory factory(HttpClient httpClient) { 26 | HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); 27 | factory.setConnectTimeout(1500); 28 | factory.setHttpClient(httpClient); 29 | return factory; 30 | } 31 | 32 | @Bean 33 | RestTemplate restTemplate(HttpComponentsClientHttpRequestFactory factory) { 34 | return new RestTemplate(factory); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/check/client/api/CheckController.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.check.client.api; 2 | 3 | import com.project.qvick.domain.check.application.service.CheckCodeService; 4 | import com.project.qvick.domain.check.client.dto.response.CheckCodeResponse; 5 | import com.project.qvick.global.common.client.dto.response.BaseResponseData; 6 | import io.swagger.v3.oas.annotations.Operation; 7 | import io.swagger.v3.oas.annotations.security.SecurityRequirement; 8 | import io.swagger.v3.oas.annotations.tags.Tag; 9 | import lombok.RequiredArgsConstructor; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.util.concurrent.CompletableFuture; 15 | import java.util.concurrent.ExecutionException; 16 | 17 | @RestController 18 | @RequiredArgsConstructor 19 | @RequestMapping("/attendance") 20 | @Tag(name = "출석", description = "출석 API") 21 | @SecurityRequirement(name = "BearerAuthentication") 22 | public class CheckController { 23 | 24 | private final CheckCodeService checkCodeService; 25 | 26 | @PostMapping("/code") 27 | @Operation(summary = "출석 코드 생성", description = "출석 코드 생성합니다") 28 | public BaseResponseData generateCheckCode() throws ExecutionException, InterruptedException { 29 | CompletableFuture codeResponseFuture = checkCodeService.generate(); 30 | CheckCodeResponse codes = codeResponseFuture.get(); 31 | return BaseResponseData.created( 32 | "출석 코드 생성 성공", 33 | codes); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/application/service/PostServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.application.service; 2 | 3 | import com.project.qvick.domain.post.application.util.PostUtil; 4 | import com.project.qvick.domain.post.client.dto.Post; 5 | import com.project.qvick.domain.post.client.dto.request.PostDeleteRequest; 6 | import com.project.qvick.domain.post.client.dto.request.PostEditRequest; 7 | import com.project.qvick.domain.post.client.dto.request.PostRegisterRequest; 8 | import com.project.qvick.domain.post.domain.mapper.PostMapper; 9 | import com.project.qvick.domain.post.domain.repository.jpa.PostRepository; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.stereotype.Service; 12 | 13 | @Service 14 | @RequiredArgsConstructor 15 | public class PostServiceImpl implements PostService{ 16 | 17 | private final PostRepository postRepository; 18 | private final PostMapper postMapper; 19 | private final PostUtil postUtil; 20 | 21 | @Override 22 | public void postRegister(PostRegisterRequest request) { 23 | postUtil.savePost(request); 24 | } 25 | 26 | @Override 27 | public Post postFind(Long postId) { 28 | return postUtil.findPost(postId); 29 | } 30 | 31 | @Override 32 | public void postEdit(PostEditRequest request){ 33 | Post post = postUtil.findPost(request.postId()); 34 | post.setTitle(request.title()); 35 | post.setContent(request.content()); 36 | postRepository.save(postMapper.toEntity(post)); 37 | } 38 | 39 | @Override 40 | public void postDelete(PostDeleteRequest request){ 41 | postRepository.deleteById(request.postId()); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/filter/JwtExceptionFilter.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt.filter; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.project.qvick.global.annotation.Jwt; 5 | import jakarta.servlet.FilterChain; 6 | import jakarta.servlet.ServletException; 7 | import jakarta.servlet.http.HttpServletRequest; 8 | import jakarta.servlet.http.HttpServletResponse; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.filter.OncePerRequestFilter; 12 | 13 | import java.io.IOException; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | @Jwt 18 | public class JwtExceptionFilter extends OncePerRequestFilter { 19 | 20 | @Override 21 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 22 | throws IOException { 23 | try { 24 | filterChain.doFilter(request, response); 25 | } catch (IllegalArgumentException e) { 26 | setErrorResponse(HttpStatus.UNAUTHORIZED, response, e); 27 | } catch (ServletException e) { 28 | setErrorResponse(HttpStatus.BAD_REQUEST, response, e); 29 | } 30 | } 31 | 32 | public void setErrorResponse(HttpStatus status, HttpServletResponse response, Throwable ex) throws IOException { 33 | response.setContentType("application/json;charset=UTF-8"); 34 | response.setStatus(status.value()); 35 | ObjectMapper mapper = new ObjectMapper(); 36 | Map map = new HashMap<>(); 37 | map.put("status", String.valueOf(status.value())); 38 | map.put("message", ex.getMessage()); 39 | response.getWriter().write(mapper.writeValueAsString(map)); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/application/util/UserUtil.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.application.util; 2 | 3 | import com.project.qvick.domain.user.client.dto.User; 4 | import com.project.qvick.domain.user.domain.mapper.UserMapper; 5 | import com.project.qvick.domain.user.domain.repository.jpa.UserRepository; 6 | import com.project.qvick.domain.user.exception.UserExistException; 7 | import com.project.qvick.domain.user.exception.UserNotFoundException; 8 | import com.project.qvick.global.annotation.Util; 9 | import com.project.qvick.global.common.repository.UserSecurity; 10 | import lombok.RequiredArgsConstructor; 11 | 12 | @Util 13 | @RequiredArgsConstructor 14 | public class UserUtil { 15 | 16 | private final UserRepository userRepository; 17 | private final UserSecurity userSecurity; 18 | private final UserMapper userMapper; 19 | 20 | public void userExistCheck(String email){ 21 | if (userRepository.findByEmail(email).isPresent()){ 22 | throw UserExistException.EXCEPTION; 23 | } 24 | } 25 | 26 | public User getUser(){ 27 | return userRepository 28 | .findById(userSecurity.getUser().getId()) 29 | .map(userMapper::toUser) 30 | .orElseThrow(()-> UserNotFoundException.EXCEPTION); 31 | } 32 | 33 | public User findUserByStdId(String stdId){ 34 | return userRepository 35 | .findByStdId(stdId) 36 | .map(userMapper::toUser) 37 | .orElseThrow(()-> UserNotFoundException.EXCEPTION); 38 | } 39 | 40 | public User findUserByEmail(String email){ 41 | return userRepository 42 | .findByEmail(email) 43 | .map(userMapper::toUser) 44 | .orElseThrow(()-> UserNotFoundException.EXCEPTION); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/JwtProvider.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt; 2 | 3 | import com.project.qvick.domain.user.domain.enums.UserRole; 4 | import com.project.qvick.global.annotation.Jwt; 5 | import com.project.qvick.global.security.jwt.config.JwtProperties; 6 | import com.project.qvick.global.security.jwt.enums.JwtType; 7 | import io.jsonwebtoken.Header; 8 | import io.jsonwebtoken.Jwts; 9 | import io.jsonwebtoken.SignatureAlgorithm; 10 | import lombok.RequiredArgsConstructor; 11 | 12 | import java.util.Date; 13 | 14 | @Jwt 15 | @RequiredArgsConstructor 16 | public class JwtProvider { 17 | 18 | private final JwtProperties jwtProperties; 19 | 20 | public String generateAccessToken(final String email, final UserRole userRole) { 21 | return Jwts.builder() 22 | .setHeaderParam(Header.JWT_TYPE, JwtType.ACCESS) 23 | .setSubject(email) 24 | .claim("authority", userRole) 25 | .setIssuedAt(new Date(System.currentTimeMillis())) 26 | .setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration())) 27 | .signWith(SignatureAlgorithm.HS256, jwtProperties.getSecretKey()) 28 | .compact(); 29 | } 30 | 31 | public String generateRefreshToken(final String email, final UserRole userRole) { 32 | return Jwts.builder() 33 | .setHeaderParam(Header.JWT_TYPE, JwtType.REFRESH) 34 | .setSubject(email) 35 | .claim("authority", userRole) 36 | .setIssuedAt(new Date(System.currentTimeMillis())) 37 | .setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getRefreshExpiration())) 38 | .signWith(SignatureAlgorithm.HS256, jwtProperties.getSecretKey()) 39 | .compact(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/auth/CustomUserDetails.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.auth; 2 | 3 | import com.project.qvick.domain.user.client.dto.User; 4 | import lombok.Getter; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.userdetails.UserDetails; 8 | 9 | import java.util.Collection; 10 | import java.util.Collections; 11 | 12 | @Getter 13 | @Slf4j 14 | public class CustomUserDetails implements UserDetails { 15 | 16 | private final User user; 17 | private final Collection authorities; 18 | 19 | private CustomUserDetails(final User user, final Collection authorities) { 20 | this.user = user; 21 | this.authorities = authorities; 22 | } 23 | 24 | public CustomUserDetails(final User user) { 25 | this.user = user; 26 | this.authorities = Collections.singleton(() -> user.getUserRole().getKey()); 27 | } 28 | 29 | public static CustomUserDetails create(User user) { 30 | return new CustomUserDetails(user, Collections.singleton((GrantedAuthority) user.getUserRole()::getKey)); 31 | } 32 | 33 | @Override 34 | public Collection getAuthorities() { 35 | return Collections.singleton(() -> user.getUserRole().getKey()); 36 | // return authorities; 37 | } 38 | 39 | @Override 40 | public String getPassword() { 41 | return null; 42 | } 43 | 44 | @Override 45 | public String getUsername() { 46 | return user.getEmail(); 47 | } 48 | 49 | @Override 50 | public boolean isAccountNonExpired() { 51 | return true; 52 | } 53 | 54 | @Override 55 | public boolean isAccountNonLocked() { 56 | return true; 57 | } 58 | 59 | @Override 60 | public boolean isCredentialsNonExpired() { 61 | return true; 62 | } 63 | 64 | @Override 65 | public boolean isEnabled() { 66 | return true; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/domain/UserEntity.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.domain; 2 | 3 | import com.project.qvick.domain.user.domain.enums.UserRole; 4 | import com.project.qvick.global.common.entity.BaseTimeEntity; 5 | import jakarta.persistence.Column; 6 | import jakarta.persistence.Entity; 7 | import jakarta.persistence.EnumType; 8 | import jakarta.persistence.Enumerated; 9 | import jakarta.persistence.GeneratedValue; 10 | import jakarta.persistence.GenerationType; 11 | import jakarta.persistence.Id; 12 | import jakarta.persistence.Table; 13 | import lombok.AccessLevel; 14 | import lombok.Getter; 15 | import lombok.NoArgsConstructor; 16 | import lombok.experimental.SuperBuilder; 17 | import org.hibernate.annotations.DynamicUpdate; 18 | import org.springframework.scheduling.annotation.Scheduled; 19 | 20 | import java.time.LocalDateTime; 21 | 22 | /** 유저 Entity */ 23 | @Entity 24 | @Getter 25 | @SuperBuilder 26 | @DynamicUpdate 27 | @Table(name = "tb_user") 28 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 29 | public class UserEntity extends BaseTimeEntity { 30 | 31 | @Id 32 | @GeneratedValue(strategy = GenerationType.IDENTITY) 33 | private Long id; 34 | 35 | @Column(nullable = false) 36 | private String name; 37 | 38 | @Column(nullable = false, 39 | unique = true) 40 | private String email; 41 | 42 | @Column(nullable = false) 43 | private String password; 44 | 45 | @Column(nullable = false, 46 | unique = true, 47 | length = 4) 48 | private String stdId; 49 | 50 | @Column(nullable = false, 51 | length = 3) 52 | private String room; 53 | 54 | @Column(nullable = false) 55 | @Enumerated(EnumType.STRING) 56 | private UserRole userRole; 57 | 58 | @Column(nullable = false) 59 | private boolean isChecked; 60 | 61 | @Column(nullable = false) 62 | private LocalDateTime checkedDate; 63 | 64 | @Scheduled(cron = "0 0 7 * * *") 65 | public void dailyUpdate() { 66 | // 매일 업데이트할 값 설정 67 | isChecked = false; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/application/query/UserQueryServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.application.query; 2 | 3 | import com.project.qvick.domain.user.client.dto.User; 4 | import com.project.qvick.domain.user.client.dto.request.UserSearchRequest; 5 | import com.project.qvick.domain.user.domain.repository.query.UserQueryRepository; 6 | import com.project.qvick.global.common.client.dto.request.PageRequest; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.scheduling.annotation.Scheduled; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import java.util.List; 13 | 14 | @Service 15 | @RequiredArgsConstructor 16 | public class UserQueryServiceImpl implements UserQueryService{ 17 | 18 | private final UserQueryRepository userQueryRepository; 19 | 20 | @Transactional(readOnly = true) 21 | @Override 22 | public List userList(PageRequest pageRequest){ 23 | return userQueryRepository.userList(pageRequest); 24 | } 25 | 26 | @Transactional(readOnly = true) 27 | @Override 28 | public List userSearch(UserSearchRequest searchRequest){ 29 | return userQueryRepository.userSearch(searchRequest); 30 | } 31 | 32 | @Transactional(readOnly = true) 33 | @Override 34 | public List studentList(PageRequest pageRequest){ 35 | return userQueryRepository.studentList(pageRequest); 36 | } 37 | 38 | @Transactional(readOnly = true) 39 | @Override 40 | public List checkUsers(PageRequest pageRequest) { 41 | return userQueryRepository.checkUsers(pageRequest); 42 | } 43 | 44 | @Override 45 | @Transactional 46 | @Scheduled(cron = "0 0 1 * * *") // 매일 오후 8시에 실행 47 | public void updateChecked() { 48 | userQueryRepository.updateChecked(); 49 | } 50 | 51 | @Transactional(readOnly = true) 52 | @Override 53 | public List nonCheckUsers(PageRequest pageRequest) { 54 | return userQueryRepository.nonCheckUsers(pageRequest); 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: CI/CD using github actions & docker 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] # 해당 branch에 푸쉬 발생 시 업데이트 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | CI-CD: 12 | runs-on: ubuntu-latest 13 | steps: 14 | 15 | - uses: actions/checkout@v3 16 | - name: Set up JDK 17 17 | uses: actions/setup-java@v2 18 | with: 19 | java-version: '17' 20 | distribution: 'temurin' 21 | 22 | - name: set yml file 23 | uses: microsoft/variable-substitution@v1 24 | with: 25 | files: src/main/resources/application.yml 26 | env: 27 | spring.datasource.url: ${{ secrets.RDS_PATH }} 28 | spring.datasource.username: ${{ secrets.DB_USERNAME }} 29 | spring.datasource.password: ${{ secrets.DB_PASSWORD }} 30 | spring.security.user.name: ${{ secrets.SECURITY_USER_NAME }} 31 | spring.security.user.password: ${{ secrets.SECURITY_USER_PASSWORD }} 32 | application.jwt.secretKey: ${{ secrets.JWT_SECRET_KEY }} 33 | logging.discord.webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} 34 | 35 | - name: logback.xml set 36 | run: | 37 | echo "${{ secrets.LOGBACK_XML }}" | base64 --decode > src/main/resources/logback.xml 38 | 39 | - name: set chmod 40 | run: chmod +x ./gradlew 41 | 42 | - name: Build with Gradle 43 | run: ./gradlew bootJar 44 | 45 | - name: Docker build & push to prod 46 | run: | 47 | docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} 48 | docker build -f Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/qvick:1.0.0 . 49 | docker push ${{ secrets.DOCKER_USERNAME }}/qvick:1.0.0 50 | 51 | - name: Deploy to prod 52 | uses: appleboy/ssh-action@master 53 | id: deploy-prod 54 | with: 55 | host: ${{ secrets.HOST_PROD }} # EC2 퍼블릭 IPv4 DNS 56 | username: ubuntu 57 | key: ${{ secrets.PRIVATE_KEY }} # EC2 private key 58 | envs: GITHUB_SHA 59 | script: | 60 | docker stop qvick 61 | docker rm qvick 62 | docker rmi ${{ secrets.DOCKER_USERNAME }}/qvick:1.0.0 63 | docker pull ${{ secrets.DOCKER_USERNAME }}/qvick:1.0.0 64 | docker run -d -p 8080:8080 --name qvick ${{ secrets.DOCKER_USERNAME }}/qvick:1.0.0 -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/domain/repository/query/PostQueryRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.domain.repository.query; 2 | 3 | import com.project.qvick.domain.post.client.dto.Post; 4 | import com.project.qvick.domain.post.client.dto.request.PostSearchRequest; 5 | import com.project.qvick.global.common.client.dto.request.PageRequest; 6 | import com.project.qvick.global.exception.BadRequestException; 7 | import com.querydsl.core.types.ConstructorExpression; 8 | import com.querydsl.core.types.Projections; 9 | import com.querydsl.core.types.dsl.BooleanExpression; 10 | import com.querydsl.jpa.impl.JPAQueryFactory; 11 | import lombok.RequiredArgsConstructor; 12 | import org.springframework.stereotype.Repository; 13 | 14 | import java.util.List; 15 | 16 | import static com.project.qvick.domain.post.domain.QPostEntity.postEntity; 17 | import static com.project.qvick.domain.user.domain.QUserEntity.userEntity; 18 | 19 | @Repository 20 | @RequiredArgsConstructor 21 | public class PostQueryRepositoryImpl implements PostQueryRepository { 22 | 23 | private final JPAQueryFactory jpaQueryFactory; 24 | 25 | @Override 26 | public List postList(PageRequest request){ 27 | return jpaQueryFactory 28 | .select(postListConstructorExpression()) 29 | .from(postEntity) 30 | .offset((long) (request.getPage() - 1) * request.getSize()) 31 | .limit(request.getSize()) 32 | .orderBy(postEntity.id.asc()) 33 | .fetch(); 34 | } 35 | 36 | @Override 37 | public ListpostSearch(PostSearchRequest request){ 38 | return jpaQueryFactory 39 | .select(postListConstructorExpression()) 40 | .from(userEntity) 41 | .where(eqTitle(request.getTitle())) 42 | .offset((long) (request.getPage() - 1) * request.getSize()) 43 | .limit(request.getSize()) 44 | .orderBy(userEntity.id.asc()) 45 | .fetch(); 46 | } 47 | 48 | private ConstructorExpression postListConstructorExpression(){ 49 | return Projections.constructor(Post.class, 50 | postEntity.id, 51 | postEntity.title, 52 | postEntity.content, 53 | postEntity.author 54 | ); 55 | } 56 | 57 | private BooleanExpression eqTitle(String title) { 58 | if(title.isEmpty()){ 59 | throw BadRequestException.EXCEPTION; 60 | } 61 | return userEntity.name.eq(title); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/auth/client/api/AuthController.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.auth.client.api; 2 | 3 | import com.project.qvick.domain.auth.client.dto.request.RefreshTokenRequest; 4 | import com.project.qvick.domain.auth.client.dto.request.SignInRequest; 5 | import com.project.qvick.domain.auth.client.dto.request.SignUpRequest; 6 | import com.project.qvick.domain.auth.client.dto.response.JsonWebTokenResponse; 7 | import com.project.qvick.domain.auth.client.dto.response.RefreshTokenResponse; 8 | import com.project.qvick.domain.auth.service.AuthService; 9 | import com.project.qvick.global.common.client.dto.response.BaseResponse; 10 | import com.project.qvick.global.common.client.dto.response.BaseResponseData; 11 | import io.swagger.v3.oas.annotations.Operation; 12 | import io.swagger.v3.oas.annotations.tags.Tag; 13 | import lombok.RequiredArgsConstructor; 14 | import org.springframework.validation.annotation.Validated; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.RequestBody; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RestController; 19 | 20 | @RestController 21 | @RequiredArgsConstructor 22 | @RequestMapping("/auth") 23 | @Tag(name = "인증", description = "인증 API") 24 | public class AuthController { 25 | 26 | private final AuthService authService; 27 | 28 | @PostMapping("/sign-up") 29 | @Operation(summary = "유저 회원가입", description = "유저 회원가입") 30 | public BaseResponse signUp(@Validated @RequestBody SignUpRequest signUpRequest){ 31 | authService.signUp(signUpRequest); 32 | return BaseResponse.created("회원가입이 완료되었습니다."); 33 | } 34 | 35 | @PostMapping("/sign-up/admin") 36 | @Operation(summary = "관리자 회원가입", description = "관리자 회원가입") 37 | public BaseResponse adminSignUp(@Validated @RequestBody SignUpRequest signUpRequest){ 38 | authService.adminSignUp(signUpRequest); 39 | return BaseResponse.created("회원가입이 완료되었습니다."); 40 | } 41 | 42 | @PostMapping("/sign-up/teacher") 43 | @Operation(summary = "선생님 회원가입", description = "선생님 회원가입") 44 | public BaseResponse teacherSignUp(@Validated @RequestBody SignUpRequest signUpRequest){ 45 | authService.teacherSignUp(signUpRequest); 46 | return BaseResponse.created("회원가입이 완료되었습니다."); 47 | } 48 | 49 | @PostMapping("/sign-in") 50 | @Operation(summary = "로그인", description = "로그인") 51 | public BaseResponseData signIn(@Validated @RequestBody SignInRequest signInRequest){ 52 | return BaseResponseData.ok( 53 | "로그인 성공", 54 | authService.signIn(signInRequest)); 55 | } 56 | 57 | @PostMapping("/refresh") 58 | @Operation(summary = "토큰 재발급", description = "access 토큰을 재발급 합니다") 59 | public BaseResponseData refresh(RefreshTokenRequest request){ 60 | return BaseResponseData.ok( 61 | "토큰 재발급 성공", 62 | authService.refresh(request.refreshToken())); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if %ERRORLEVEL% equ 0 goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | set EXIT_CODE=%ERRORLEVEL% 84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 86 | exit /b %EXIT_CODE% 87 | 88 | :mainEnd 89 | if "%OS%"=="Windows_NT" endlocal 90 | 91 | :omega -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/domain/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.domain.mapper; 2 | 3 | import com.project.qvick.domain.auth.client.dto.request.SignUpRequest; 4 | import com.project.qvick.domain.user.client.dto.User; 5 | import com.project.qvick.domain.user.domain.UserEntity; 6 | import com.project.qvick.domain.user.domain.enums.UserRole; 7 | import com.project.qvick.global.annotation.Mapper; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | @Mapper 13 | public class UserMapper { 14 | 15 | public User toUser(UserEntity entity){ 16 | return User.builder() 17 | .id(entity.getId()) 18 | .name(entity.getName()) 19 | .password(entity.getPassword()) 20 | .userRole(entity.getUserRole()) 21 | .email(entity.getEmail()) 22 | .stdId(entity.getStdId()) 23 | .room(entity.getRoom()) 24 | .isChecked(entity.isChecked()) 25 | .checkedDate(entity.getCheckedDate()) 26 | .build(); 27 | } 28 | 29 | public UserEntity toCreate(SignUpRequest signUpRequest, String password){ 30 | return UserEntity.builder() 31 | .name(signUpRequest.name()) 32 | .email(signUpRequest.email()) 33 | .password(password) 34 | .stdId(signUpRequest.stdId()) 35 | .room(signUpRequest.room()) 36 | .userRole(UserRole.USER) 37 | .isChecked(false) 38 | .checkedDate(LocalDateTime.now()) 39 | .build(); 40 | } 41 | 42 | public UserEntity toCreateAdmin(SignUpRequest signUpRequest, String password){ 43 | return UserEntity.builder() 44 | .name(signUpRequest.name()) 45 | .email(signUpRequest.email()) 46 | .password(password) 47 | .stdId(signUpRequest.stdId()) 48 | .room(signUpRequest.room()) 49 | .userRole(UserRole.ADMIN) 50 | .isChecked(true) 51 | .checkedDate(null) 52 | .build(); 53 | } 54 | 55 | public UserEntity toCreateTeacher(SignUpRequest signUpRequest, String password){ 56 | return UserEntity.builder() 57 | .name(signUpRequest.name()) 58 | .email(signUpRequest.email()) 59 | .password(password) 60 | .stdId(signUpRequest.stdId()) 61 | .room(signUpRequest.room()) 62 | .userRole(UserRole.TEACHER) 63 | .isChecked(true) 64 | .checkedDate(null) 65 | .build(); 66 | } 67 | 68 | public UserEntity toEdit(User user){ 69 | return UserEntity.builder() 70 | .id(user.getId()) 71 | .name(user.getName()) 72 | .email(user.getEmail()) 73 | .password(user.getPassword()) 74 | .stdId(user.getStdId()) 75 | .room(user.getRoom()) 76 | .userRole(user.getUserRole()) 77 | .isChecked(user.isChecked()) 78 | .checkedDate(user.getCheckedDate()) 79 | .build(); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/api/UserController.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.api; 2 | 3 | import com.project.qvick.domain.check.client.dto.request.CodeRequest; 4 | import com.project.qvick.domain.user.application.service.UserService; 5 | import com.project.qvick.domain.user.client.dto.User; 6 | import com.project.qvick.domain.user.client.dto.request.PasswordEditRequest; 7 | import com.project.qvick.domain.user.client.dto.request.StdIdEditRequest; 8 | import com.project.qvick.global.common.client.dto.response.BaseResponse; 9 | import com.project.qvick.global.common.client.dto.response.BaseResponseData; 10 | import io.swagger.v3.oas.annotations.Operation; 11 | import io.swagger.v3.oas.annotations.tags.Tag; 12 | import lombok.RequiredArgsConstructor; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.validation.annotation.Validated; 15 | import org.springframework.web.bind.annotation.DeleteMapping; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.bind.annotation.PatchMapping; 18 | import org.springframework.web.bind.annotation.PostMapping; 19 | import org.springframework.web.bind.annotation.RequestBody; 20 | import org.springframework.web.bind.annotation.RequestMapping; 21 | import org.springframework.web.bind.annotation.ResponseStatus; 22 | import org.springframework.web.bind.annotation.RestController; 23 | 24 | @RestController 25 | @RequiredArgsConstructor 26 | @RequestMapping("/user") 27 | @Tag(name = "유저", description = "유저 API") 28 | public class UserController { 29 | 30 | private final UserService userService; 31 | 32 | @PostMapping("/attendance") 33 | @Operation(summary = "출석체크", description = "출석 체크를 진행합니다.") 34 | public BaseResponse check(@RequestBody CodeRequest request){ 35 | userService.check(request); 36 | return BaseResponse.ok("출석이 완료되었습니다."); 37 | } 38 | 39 | @GetMapping("/status") 40 | @Operation(summary = "상태 확인", description = "출석 상태를 확인합니다.") 41 | public BaseResponseData isChecked() { 42 | return userService.isChecked() ? 43 | BaseResponseData.of(HttpStatus.OK,"출석",HttpStatus.OK) : 44 | BaseResponseData.of(HttpStatus.BAD_REQUEST,"미출석",HttpStatus.BAD_REQUEST); 45 | } 46 | 47 | @GetMapping("") 48 | @Operation(summary = "유저 조회", description = "현재 로그인한 유저 정보를 조회합니다") 49 | public BaseResponseData findUser(){ 50 | return BaseResponseData.ok( 51 | "유저 정보를 성공적으로 조회하였습니다.", 52 | userService.findUser()); 53 | } 54 | 55 | @PatchMapping("/stdId") 56 | @Operation(summary = "회원 학번 수정", description = "회원 학번을 수정합니다") 57 | @ResponseStatus(HttpStatus.OK) 58 | public BaseResponse editUser(@Validated @RequestBody StdIdEditRequest request){ 59 | userService.editUserStdId(request); 60 | return BaseResponse.ok("학번을 성공적으로 수정하였습니다."); 61 | } 62 | 63 | @PatchMapping("/password") 64 | @Operation(summary = "비밀번호 변경", description = "현재 로그인한 유저의 비밀번호를 변경합니다") 65 | public BaseResponse editPassword(PasswordEditRequest request){ 66 | userService.editPassword(request); 67 | return BaseResponse.ok("비밀번호가 성공적으로 변경되었습니다."); 68 | } 69 | 70 | @DeleteMapping("") 71 | @Operation(summary = "회원탈퇴", description = "회원 탈퇴를 진행합니다") 72 | public BaseResponse deleteUser(){ 73 | userService.deleteUser(); 74 | return BaseResponse.ok("회원탈퇴가 완료되었습니다."); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/jwt/JwtExtract.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.jwt; 2 | 3 | import com.project.qvick.domain.user.client.dto.User; 4 | import com.project.qvick.domain.user.domain.mapper.UserMapper; 5 | import com.project.qvick.domain.user.domain.repository.jpa.UserRepository; 6 | import com.project.qvick.domain.user.exception.UserNotFoundException; 7 | import com.project.qvick.global.annotation.Jwt; 8 | import com.project.qvick.global.security.auth.CustomUserDetails; 9 | import com.project.qvick.global.security.jwt.config.JwtProperties; 10 | import com.project.qvick.global.security.jwt.enums.JwtType; 11 | import com.project.qvick.global.security.jwt.exception.TokenErrorException; 12 | import com.project.qvick.global.security.jwt.exception.TokenExpiredException; 13 | import com.project.qvick.global.security.jwt.exception.TokenNotSupportException; 14 | import com.project.qvick.global.security.jwt.exception.TokenTypeException; 15 | import io.jsonwebtoken.Claims; 16 | import io.jsonwebtoken.ExpiredJwtException; 17 | import io.jsonwebtoken.Header; 18 | import io.jsonwebtoken.Jws; 19 | import io.jsonwebtoken.Jwts; 20 | import io.jsonwebtoken.UnsupportedJwtException; 21 | import jakarta.servlet.http.HttpServletRequest; 22 | import lombok.RequiredArgsConstructor; 23 | import org.springframework.http.HttpHeaders; 24 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 25 | import org.springframework.security.core.Authentication; 26 | import org.springframework.util.StringUtils; 27 | 28 | @Jwt 29 | @RequiredArgsConstructor 30 | public class JwtExtract { 31 | 32 | private final JwtProperties jwtProperties; 33 | private final UserRepository userRepository; 34 | private final UserMapper userMapper; 35 | 36 | public Jws getClaims(final String token) { 37 | try { 38 | return Jwts.parser().setSigningKey(jwtProperties.getSecretKey()).parseClaimsJws(token); 39 | } catch (ExpiredJwtException e) { 40 | throw TokenExpiredException.EXCEPTION; 41 | } catch (UnsupportedJwtException e) { 42 | throw TokenNotSupportException.EXCEPTION; 43 | } catch (IllegalArgumentException e) { 44 | throw TokenErrorException.EXCEPTION; 45 | } 46 | } 47 | 48 | public Authentication getAuthentication(final String token) { 49 | final Jws claims = getClaims(token); 50 | 51 | if (isWrongType(claims, JwtType.ACCESS)) { 52 | throw TokenTypeException.EXCEPTION; 53 | } 54 | 55 | User user = userRepository.findByEmail(claims 56 | .getBody() 57 | .getSubject()) 58 | .map(userMapper::toUser) 59 | .orElseThrow(() -> UserNotFoundException.EXCEPTION); 60 | 61 | final CustomUserDetails details = new CustomUserDetails(user); 62 | 63 | return new UsernamePasswordAuthenticationToken(details, null, details.getAuthorities()); 64 | } 65 | 66 | public String extractTokenFromRequest(HttpServletRequest request) { 67 | return extractToken(request.getHeader(HttpHeaders.AUTHORIZATION)); 68 | } 69 | 70 | public String extractToken(final String token) { 71 | if (StringUtils.hasText(token) && token.startsWith("Bearer ")) { 72 | return token.substring(7); 73 | } 74 | return token; 75 | } 76 | 77 | public boolean isWrongType(final Jws claims, final JwtType jwtType) { 78 | return !(claims.getHeader().get(Header.JWT_TYPE).equals(jwtType.toString())); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/auth/service/AuthServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.auth.service; 2 | 3 | import com.project.qvick.domain.auth.client.dto.request.SignInRequest; 4 | import com.project.qvick.domain.auth.client.dto.request.SignUpRequest; 5 | import com.project.qvick.domain.auth.client.dto.response.JsonWebTokenResponse; 6 | import com.project.qvick.domain.auth.client.dto.response.RefreshTokenResponse; 7 | import com.project.qvick.domain.user.application.util.UserUtil; 8 | import com.project.qvick.domain.user.client.dto.User; 9 | import com.project.qvick.domain.user.domain.enums.UserRole; 10 | import com.project.qvick.domain.user.domain.mapper.UserMapper; 11 | import com.project.qvick.domain.user.domain.repository.jpa.UserRepository; 12 | import com.project.qvick.domain.user.exception.PasswordWrongException; 13 | import com.project.qvick.global.security.jwt.JwtExtract; 14 | import com.project.qvick.global.security.jwt.JwtProvider; 15 | import com.project.qvick.global.security.jwt.enums.JwtType; 16 | import com.project.qvick.global.security.jwt.exception.TokenTypeException; 17 | import io.jsonwebtoken.Claims; 18 | import io.jsonwebtoken.Jws; 19 | import lombok.RequiredArgsConstructor; 20 | import org.springframework.security.crypto.password.PasswordEncoder; 21 | import org.springframework.stereotype.Service; 22 | 23 | @Service 24 | @RequiredArgsConstructor 25 | public class AuthServiceImpl implements AuthService { 26 | 27 | private final UserRepository userRepository; 28 | private final UserMapper userMapper; 29 | private final UserUtil userUtil; 30 | private final PasswordEncoder encoder; 31 | private final JwtProvider jwtProvider; 32 | private final JwtExtract jwtExtract; 33 | 34 | @Override 35 | public void signUp(SignUpRequest request) { 36 | userUtil.userExistCheck(request.email()); 37 | userRepository.save(userMapper.toCreate( 38 | request, 39 | encoder.encode(request.password())) 40 | ); 41 | } 42 | 43 | @Override 44 | public void adminSignUp(SignUpRequest request) { 45 | userUtil.userExistCheck(request.email()); 46 | userRepository.save(userMapper.toCreateAdmin( 47 | request, 48 | encoder.encode(request.password())) 49 | ); 50 | } 51 | 52 | @Override 53 | public void teacherSignUp(SignUpRequest request) { 54 | userUtil.userExistCheck(request.email()); 55 | userRepository.save(userMapper.toCreateTeacher( 56 | request, 57 | encoder.encode(request.password())) 58 | ); 59 | } 60 | 61 | @Override 62 | public JsonWebTokenResponse signIn(SignInRequest request) { 63 | User user = userUtil.findUserByEmail(request.email()); 64 | String password = user.getPassword(); 65 | if (!encoder.matches(request.password(), password)) 66 | throw PasswordWrongException.EXCEPTION; 67 | return JsonWebTokenResponse.builder() 68 | .accessToken(jwtProvider.generateAccessToken(request.email(),user.getUserRole())) 69 | .refreshToken(jwtProvider.generateRefreshToken(request.email(), user.getUserRole())) 70 | .userRole(user.getUserRole()) 71 | .build(); 72 | } 73 | 74 | @Override 75 | public RefreshTokenResponse refresh(String token) { 76 | Jws claims = jwtExtract.getClaims(jwtExtract.extractToken(token)); 77 | if (jwtExtract.isWrongType(claims, JwtType.REFRESH)) { 78 | throw TokenTypeException.EXCEPTION; 79 | } 80 | return RefreshTokenResponse.builder() 81 | .accessToken(jwtProvider.generateAccessToken(claims.getBody().getSubject(), 82 | (UserRole) claims.getHeader().get("authority"))).build(); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/post/client/api/PostController.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.post.client.api; 2 | 3 | import com.project.qvick.domain.post.application.query.PostQueryService; 4 | import com.project.qvick.domain.post.application.service.PostService; 5 | import com.project.qvick.domain.post.client.dto.Post; 6 | import com.project.qvick.domain.post.client.dto.request.PostDeleteRequest; 7 | import com.project.qvick.domain.post.client.dto.request.PostEditRequest; 8 | import com.project.qvick.domain.post.client.dto.request.PostRegisterRequest; 9 | import com.project.qvick.domain.post.client.dto.request.PostSearchRequest; 10 | import com.project.qvick.global.common.client.dto.request.PageRequest; 11 | import com.project.qvick.global.common.client.dto.response.BaseResponse; 12 | import com.project.qvick.global.common.client.dto.response.BaseResponseData; 13 | import io.swagger.v3.oas.annotations.Operation; 14 | import io.swagger.v3.oas.annotations.tags.Tag; 15 | import lombok.RequiredArgsConstructor; 16 | import org.springframework.http.HttpStatus; 17 | import org.springframework.web.bind.annotation.DeleteMapping; 18 | import org.springframework.web.bind.annotation.GetMapping; 19 | import org.springframework.web.bind.annotation.ModelAttribute; 20 | import org.springframework.web.bind.annotation.PatchMapping; 21 | import org.springframework.web.bind.annotation.PostMapping; 22 | import org.springframework.web.bind.annotation.RequestBody; 23 | import org.springframework.web.bind.annotation.RequestMapping; 24 | import org.springframework.web.bind.annotation.RequestParam; 25 | import org.springframework.web.bind.annotation.ResponseStatus; 26 | import org.springframework.web.bind.annotation.RestController; 27 | 28 | import java.util.List; 29 | 30 | @RestController 31 | @RequiredArgsConstructor 32 | @RequestMapping("/post") 33 | @Tag(name = "공지사항", description = "공지사항 API") 34 | public class PostController { 35 | 36 | private final PostService postService; 37 | private final PostQueryService postQueryService; 38 | 39 | @PostMapping("") 40 | @ResponseStatus(HttpStatus.CREATED) 41 | @Operation(summary = "공시사항 등록", description = "공지사항을 등록합니다.") 42 | public BaseResponse postRegister(@RequestBody PostRegisterRequest request){ 43 | postService.postRegister(request); 44 | return BaseResponse.created("공지사항이 등록되었습니다."); 45 | } 46 | 47 | @GetMapping("") 48 | @Operation(summary = "공지사항 조회", description = "하나의 공지사항을 ID를 기준으로 조회합니다.") 49 | public BaseResponseData postFind(@RequestParam Long postId){ 50 | return BaseResponseData.ok( 51 | "공지사항 조회 성공", 52 | postService.postFind(postId)); 53 | } 54 | 55 | @GetMapping("/list") 56 | @Operation(summary = "공지사항 목록", description = "등록된 모든 공지사항 목록을 표시합니다.") 57 | public BaseResponseData> postList(@ModelAttribute PageRequest pageRequest){ 58 | return BaseResponseData.ok( 59 | "전체 공지사항 목록을 성공적으로 불러왔습니다.", 60 | postQueryService.postList(pageRequest)); 61 | } 62 | 63 | @GetMapping("/search") 64 | @Operation(summary = "공지사항 검색", description = "제목을 기준으로 검색된 공지사항 목록을 표시합니다.") 65 | public BaseResponseData> postSearch(@ModelAttribute PostSearchRequest postSearchRequest){ 66 | return BaseResponseData.ok( 67 | "검색 목록을 성공적으로 불러왔습니다.", 68 | postQueryService.postSearch(postSearchRequest)); 69 | } 70 | 71 | @PatchMapping("") 72 | @Operation(summary = "공지사항 수정", description = "공지사항의 제목과 내용을 수정합니다.") 73 | public BaseResponse postEdit(@RequestBody PostEditRequest request){ 74 | postService.postEdit(request); 75 | return BaseResponse.ok("제목 및 내용 수정 완료"); 76 | } 77 | 78 | @DeleteMapping("") 79 | @Operation(summary = "공지사항 삭제", description = "공지사항을 삭제합니다.") 80 | public BaseResponse postDelete(@RequestBody PostDeleteRequest request){ 81 | postService.postDelete(request); 82 | return BaseResponse.ok("공지사항이 삭제 되었습니다."); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/application/service/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.application.service; 2 | 3 | import com.project.qvick.domain.check.client.dto.request.CodeRequest; 4 | import com.project.qvick.domain.check.domain.repository.jpa.CheckCodeRepository; 5 | import com.project.qvick.domain.check.exception.CheckAlreadyExistsException; 6 | import com.project.qvick.domain.check.exception.CheckCodeError; 7 | import com.project.qvick.domain.user.application.util.UserUtil; 8 | import com.project.qvick.domain.user.client.dto.User; 9 | import com.project.qvick.domain.user.client.dto.request.AdminPasswordEditRequest; 10 | import com.project.qvick.domain.user.client.dto.request.AdminSetStatusRequest; 11 | import com.project.qvick.domain.user.client.dto.request.PasswordEditRequest; 12 | import com.project.qvick.domain.user.client.dto.request.RoomEditRequest; 13 | import com.project.qvick.domain.user.client.dto.request.StdIdEditRequest; 14 | import com.project.qvick.domain.user.domain.mapper.UserMapper; 15 | import com.project.qvick.domain.user.domain.repository.jpa.UserRepository; 16 | import com.project.qvick.domain.user.exception.PasswordWrongException; 17 | import com.project.qvick.domain.user.exception.UserNotFoundException; 18 | import lombok.RequiredArgsConstructor; 19 | import org.springframework.security.crypto.password.PasswordEncoder; 20 | import org.springframework.stereotype.Service; 21 | 22 | @Service 23 | @RequiredArgsConstructor 24 | public class UserServiceImpl implements UserService { 25 | 26 | private final UserRepository userRepository; 27 | private final UserMapper userMapper; 28 | private final UserUtil userUtil; 29 | private final CheckCodeRepository checkCodeRepository; 30 | private final PasswordEncoder encoder; 31 | 32 | @Override 33 | public void editUserStdId(StdIdEditRequest request) { 34 | User user = userUtil.getUser(); 35 | user.setStdId(request.getStdId()); 36 | userRepository.save(userMapper.toEdit(user)); 37 | } 38 | 39 | @Override 40 | public void deleteUser() { 41 | userRepository.deleteById(userUtil.getUser().getId()); 42 | } 43 | 44 | @Override 45 | public void editRoom(RoomEditRequest request) { 46 | User user = userUtil.findUserByStdId(request.getStdId()); 47 | user.setRoom(request.getRoom()); 48 | userRepository.save(userMapper.toEdit(user)); 49 | } 50 | 51 | @Override 52 | public User findUser() { 53 | return userUtil.getUser(); 54 | } 55 | 56 | @Override 57 | public void check(CodeRequest request) { 58 | User user = userUtil.getUser(); 59 | if (user.isChecked()) 60 | throw CheckAlreadyExistsException.EXCEPTION; 61 | if (!checkCodeRepository.existsByCodeAndValid(request.code(), true)) 62 | throw CheckCodeError.EXCEPTION; 63 | user.setChecked(true); 64 | userRepository.save(userMapper.toEdit(user)); 65 | } 66 | 67 | @Override 68 | public void editPassword(PasswordEditRequest request) { 69 | User user = userUtil.getUser(); 70 | if (!encoder.matches(request.getOldPassword(), user.getPassword())) 71 | throw PasswordWrongException.EXCEPTION; 72 | user.setPassword(encoder.encode(request.getNewPassword())); 73 | userRepository.save(userMapper.toEdit(user)); 74 | } 75 | 76 | @Override 77 | public void adminEditPassword(AdminPasswordEditRequest request) { 78 | User user = userUtil.findUserByEmail(request.getEmail()); 79 | user.setPassword(encoder.encode(request.getNewPassword())); 80 | userRepository.save(userMapper.toEdit(user)); 81 | } 82 | 83 | @Override 84 | public void adminDeleteUser(String email) { 85 | if (userRepository.findByEmail(email).isEmpty()) 86 | throw UserNotFoundException.EXCEPTION; 87 | userRepository.deleteByEmail(email); 88 | } 89 | 90 | @Override 91 | public boolean isChecked() { 92 | User user = userUtil.getUser(); 93 | return user.isChecked(); 94 | } 95 | 96 | @Override 97 | public void fixStatus(AdminSetStatusRequest setStatusRequest) { 98 | User user = userUtil.findUserByEmail(setStatusRequest.getEmail()); 99 | user.setChecked(setStatusRequest.getStatus() != 1); 100 | userRepository.save(userMapper.toEdit(user)); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/domain/repository/query/UserQueryRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.domain.repository.query; 2 | 3 | import com.project.qvick.domain.user.client.dto.User; 4 | import com.project.qvick.domain.user.client.dto.request.UserSearchRequest; 5 | import com.project.qvick.domain.user.domain.enums.UserRole; 6 | import com.project.qvick.global.common.client.dto.request.PageRequest; 7 | import com.project.qvick.global.exception.BadRequestException; 8 | import com.querydsl.core.types.ConstructorExpression; 9 | import com.querydsl.core.types.Projections; 10 | import com.querydsl.core.types.dsl.BooleanExpression; 11 | import com.querydsl.jpa.impl.JPAQueryFactory; 12 | import jakarta.validation.constraints.NotNull; 13 | import lombok.RequiredArgsConstructor; 14 | import org.springframework.stereotype.Repository; 15 | 16 | import java.util.List; 17 | 18 | import static com.project.qvick.domain.user.domain.QUserEntity.userEntity; 19 | 20 | @Repository 21 | @RequiredArgsConstructor 22 | public class UserQueryRepositoryImpl implements UserQueryRepository{ 23 | 24 | private final JPAQueryFactory jpaQueryFactory; 25 | 26 | @Override 27 | public List userList(PageRequest request){ 28 | return jpaQueryFactory 29 | .select(userListConstructorExpression()) 30 | .from(userEntity) 31 | .offset((long) (request.getPage() - 1) * request.getSize()) 32 | .limit(request.getSize()) 33 | .orderBy(userEntity.id.asc()) 34 | .fetch(); 35 | } 36 | 37 | @Override 38 | public ListuserSearch(UserSearchRequest request){ 39 | return jpaQueryFactory 40 | .select(userListConstructorExpression()) 41 | .from(userEntity) 42 | .where(eqName(request.getName())) 43 | .offset((long) (request.getPage() - 1) * request.getSize()) 44 | .limit(request.getSize()) 45 | .orderBy(userEntity.id.asc()) 46 | .fetch(); 47 | } 48 | 49 | @Override 50 | public ListstudentList(PageRequest request){ 51 | return jpaQueryFactory 52 | .select(userListConstructorExpression()) 53 | .from(userEntity) 54 | .where(userEntity.userRole.eq(UserRole.USER)) 55 | .offset((request.getPage() - 1) * request.getSize()) 56 | .limit(request.getSize()) 57 | .orderBy(userEntity.id.asc()) 58 | .fetch(); 59 | } 60 | 61 | @Override 62 | public List checkUsers(PageRequest request) { 63 | return jpaQueryFactory 64 | .select(userListConstructorExpression()) 65 | .from(userEntity) 66 | .where(userEntity.isChecked.eq(true)) 67 | .offset((request.getPage() - 1) * request.getSize()) 68 | .limit(request.getSize()) 69 | .orderBy(userEntity.id.asc()) 70 | .fetch(); 71 | } 72 | 73 | @Override 74 | public void updateChecked(){ 75 | jpaQueryFactory 76 | .update(userEntity) 77 | .set(userEntity.isChecked, false) 78 | .execute(); 79 | } 80 | 81 | @Override 82 | public List nonCheckUsers(PageRequest request) { 83 | return jpaQueryFactory 84 | .select(userListConstructorExpression()) 85 | .from(userEntity) 86 | .where(userEntity.isChecked.eq(false)) 87 | .offset((request.getPage() - 1) * request.getSize()) 88 | .limit(request.getSize()) 89 | .orderBy(userEntity.id.asc()) 90 | .fetch(); 91 | } 92 | 93 | private ConstructorExpression userListConstructorExpression(){ 94 | return Projections.constructor(User.class, 95 | userEntity.id, 96 | userEntity.name, 97 | userEntity.email, 98 | userEntity.password, 99 | userEntity.stdId, 100 | userEntity.room, 101 | userEntity.userRole, 102 | userEntity.isChecked, 103 | userEntity.checkedDate 104 | ); 105 | } 106 | 107 | private BooleanExpression eqName(String name) { 108 | if(name.isBlank()){ 109 | throw BadRequestException.EXCEPTION; 110 | } 111 | return userEntity.name.eq(name); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/global/security/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.global.security.config; 2 | 3 | import com.project.qvick.global.annotation.SecurityConfiguration; 4 | import com.project.qvick.global.security.jwt.filter.JwtAuthenticationFilter; 5 | import com.project.qvick.global.security.jwt.filter.JwtExceptionFilter; 6 | import com.project.qvick.global.security.jwt.handler.JwtAuthenticationEntryPoint; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; 11 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 12 | import org.springframework.security.crypto.password.PasswordEncoder; 13 | import org.springframework.security.web.SecurityFilterChain; 14 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 15 | import org.springframework.web.cors.CorsConfigurationSource; 16 | 17 | import static org.springframework.http.HttpMethod.DELETE; 18 | import static org.springframework.http.HttpMethod.GET; 19 | import static org.springframework.http.HttpMethod.PATCH; 20 | import static org.springframework.http.HttpMethod.POST; 21 | 22 | @SecurityConfiguration 23 | @RequiredArgsConstructor 24 | public class SecurityConfig { 25 | 26 | private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; 27 | private final JwtAuthenticationFilter jwtAuthenticationFilter; 28 | private final JwtExceptionFilter jwtExceptionFilter; 29 | 30 | private static final String USER = "ROLE_USER"; 31 | private static final String TEACHER = "ROLE_TEACHER"; 32 | private static final String ADMIN = "ROLE_ADMIN"; 33 | 34 | @Bean 35 | public PasswordEncoder passwordEncoder() { 36 | return new BCryptPasswordEncoder(); 37 | } 38 | 39 | @Bean 40 | public SecurityFilterChain securityFilterChain(HttpSecurity http, CorsConfigurationSource corsConfigurationSource) throws Exception { 41 | http 42 | .csrf(AbstractHttpConfigurer::disable) 43 | .cors(cors -> cors.configurationSource(corsConfigurationSource)) 44 | .exceptionHandling(handlingConfigures -> handlingConfigures.authenticationEntryPoint(jwtAuthenticationEntryPoint)) 45 | .authorizeHttpRequests( 46 | authorize -> authorize 47 | .requestMatchers("/swagger-ui/**", "/v3/**").permitAll() 48 | .requestMatchers("/terms/**").permitAll() 49 | .requestMatchers("/auth/**").permitAll() 50 | .requestMatchers(POST,"/attendance/code").permitAll() 51 | .requestMatchers(DELETE,"/user").permitAll() 52 | 53 | .requestMatchers("/outing-admin/**").hasAnyAuthority(ADMIN,TEACHER) 54 | .requestMatchers("/sleepover-admin/**").hasAnyAuthority(ADMIN,TEACHER) 55 | .requestMatchers(GET,"/attendance/check").hasAnyAuthority(ADMIN,TEACHER) 56 | .requestMatchers(GET,"/user-admin/non-check").hasAnyAuthority(ADMIN,TEACHER) 57 | .requestMatchers(GET,"/user-admin/check").hasAnyAuthority(ADMIN,TEACHER) 58 | .requestMatchers(GET,"/user-admin/find-all").hasAnyAuthority(ADMIN,TEACHER) 59 | .requestMatchers(GET,"/user-admin/search").hasAnyAuthority(ADMIN,TEACHER) 60 | .requestMatchers(PATCH, "/user-admin/fix-status").hasAuthority(ADMIN) 61 | 62 | .requestMatchers(POST,"/post").hasAuthority(TEACHER) 63 | .requestMatchers(PATCH,"/post").hasAuthority(TEACHER) 64 | .requestMatchers(DELETE,"/post").hasAuthority(TEACHER) 65 | 66 | .requestMatchers(POST,"/attendance").hasAuthority(USER) 67 | .requestMatchers(POST,"/outing").hasAuthority(USER) 68 | .requestMatchers(POST,"/sleepover").hasAuthority(USER) 69 | .requestMatchers(PATCH,"/user/stdId").hasAuthority(USER) 70 | .requestMatchers(PATCH,"/user/room").hasAuthority(USER) 71 | 72 | .anyRequest().authenticated() 73 | ) 74 | .addFilterAfter(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) 75 | .addFilterBefore(jwtExceptionFilter, JwtAuthenticationFilter.class); 76 | return http.build(); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/project/qvick/domain/user/client/api/UserAdminController.java: -------------------------------------------------------------------------------- 1 | package com.project.qvick.domain.user.client.api; 2 | 3 | import com.project.qvick.domain.user.application.query.UserQueryService; 4 | import com.project.qvick.domain.user.application.service.UserService; 5 | import com.project.qvick.domain.user.client.dto.User; 6 | import com.project.qvick.domain.user.client.dto.request.AdminPasswordEditRequest; 7 | import com.project.qvick.domain.user.client.dto.request.AdminSetStatusRequest; 8 | import com.project.qvick.domain.user.client.dto.request.RoomEditRequest; 9 | import com.project.qvick.domain.user.client.dto.request.UserSearchRequest; 10 | import com.project.qvick.global.common.client.dto.request.PageRequest; 11 | import com.project.qvick.global.common.client.dto.response.BaseResponse; 12 | import com.project.qvick.global.common.client.dto.response.BaseResponseData; 13 | import io.swagger.v3.oas.annotations.Operation; 14 | import io.swagger.v3.oas.annotations.tags.Tag; 15 | import lombok.RequiredArgsConstructor; 16 | import org.springframework.validation.annotation.Validated; 17 | import org.springframework.web.bind.annotation.DeleteMapping; 18 | import org.springframework.web.bind.annotation.GetMapping; 19 | import org.springframework.web.bind.annotation.ModelAttribute; 20 | import org.springframework.web.bind.annotation.PatchMapping; 21 | import org.springframework.web.bind.annotation.RequestBody; 22 | import org.springframework.web.bind.annotation.RequestMapping; 23 | import org.springframework.web.bind.annotation.RequestParam; 24 | import org.springframework.web.bind.annotation.RestController; 25 | 26 | import java.util.List; 27 | 28 | @RestController 29 | @RequiredArgsConstructor 30 | @RequestMapping("/user-admin") 31 | @Tag(name = "유저 관리자", description = "유저 관리자 API") 32 | public class UserAdminController { 33 | 34 | private final UserQueryService userQueryService; 35 | private final UserService userService; 36 | 37 | @GetMapping("/find-all") 38 | @Operation(summary = "전체 유저 조회", description = "전체 유저를 조회합니다") 39 | public BaseResponseData> userList(@ModelAttribute PageRequest pageRequest){ 40 | return BaseResponseData.ok( 41 | "전체 유저 목록을 성공적으로 불러왔습니다.", 42 | userQueryService.userList(pageRequest)); 43 | } 44 | 45 | @GetMapping("/student-all") 46 | @Operation(summary = "전체 학생 조회", description = "전체 학생을 조회합니다") 47 | public BaseResponseData>studentList(@ModelAttribute PageRequest pageRequest){ 48 | return BaseResponseData.ok( 49 | "전체 학생 목록을 성공적으로 불러왔습니다.", 50 | userQueryService.studentList(pageRequest)); 51 | } 52 | 53 | @GetMapping("/search") 54 | @Operation(summary = "유저 검색", description = "특정 유저를 이름을 기준으로 검색합니다") 55 | public BaseResponseData>userSearch(@ModelAttribute UserSearchRequest searchRequest){ 56 | return BaseResponseData.ok( 57 | "검색 결과를 성공적으로 불러왔습니다.", 58 | userQueryService.userSearch(searchRequest)); 59 | } 60 | 61 | @GetMapping("/check") 62 | @Operation(summary = "출석 명단 조회", description = "출석 확인자 명단을 조회합니다.") 63 | public BaseResponseData>checkList(@ModelAttribute PageRequest pageRequest){ 64 | return BaseResponseData.ok( 65 | "출석 명단을 성공적으로 불러왔습니다.", 66 | userQueryService.checkUsers(pageRequest)); 67 | } 68 | 69 | @GetMapping("/non-check") 70 | @Operation(summary = "미출석 명단 조회", description = "미출석자 명단을 조회합니다.") 71 | public BaseResponseData>nonCheckList(@ModelAttribute PageRequest pageRequest){ 72 | return BaseResponseData.ok( 73 | "미출석 명단을 성공적으로 불러왔습니다.", 74 | userQueryService.nonCheckUsers(pageRequest)); 75 | } 76 | 77 | @PatchMapping("") 78 | @Operation(summary = "비밀번호 변경", description = "해당 이메일을 가진 유저의 비밀번호를 변경합니다") 79 | public BaseResponse editPassword(AdminPasswordEditRequest request){ 80 | userService.adminEditPassword(request); 81 | return BaseResponse.ok("비밀번호가 변경되었습니다."); 82 | } 83 | 84 | @PatchMapping("/room") 85 | @Operation(summary = "회원 호실 수정", description = "회원 호실을 수정합니다") 86 | public BaseResponse editUser(@Validated @RequestBody RoomEditRequest request){ 87 | userService.editRoom(request); 88 | return BaseResponse.ok("호실을 성공적으로 수정하였습니다."); 89 | } 90 | 91 | @DeleteMapping("") 92 | @Operation(summary = "회원 삭제", description = "해당 이메일을 가진 유저를 삭제합니다.") 93 | public BaseResponse deleteUser(@RequestParam String email){ 94 | userService.adminDeleteUser(email); 95 | return BaseResponse.ok("회원이 삭제되었습니다."); 96 | } 97 | 98 | @PatchMapping("/fix-status") 99 | public BaseResponse fixStatus(@RequestBody AdminSetStatusRequest setStatusRequest){ 100 | userService.fixStatus(setStatusRequest); 101 | return BaseResponse.ok("회원 출석 상태 수정이 완료되었습니다."); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/resources/templates/PrivacyPolicy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 개인정보처리약관 6 | 26 | 31 | 32 | 33 |

34 |

Qvick 개인정보처리약관

35 |
36 |

제1조 목적

37 |

Team C0nnect(이하 운영진)는 대구소프트웨어마이스터고등학교(이하 학교)의 기숙사 관리 온라인 플랫폼 Qvick(이하 서비스) 이용을 위해 개인정보를 수집 38 | 및 관리하고 있습니다.

39 |
40 |

제2조 수집과 이용목적

41 |

운영진은 다음과 같은 개인정보를 유저에게서 수집합니다.

42 |

1) 전자메일(e-mail)

43 |

2) 유저의 주민등록등본 상의 실명

44 |

3) 유저가 등록한 비밀번호

45 |

4) 유저의 현재 학번과 호실

46 |

5) 유저의 기숙사 출석 여부

47 |

유저는 해당 정보를 제공함에 있어 허위/과장/도용 된 정보가 없어야 하며, 발각 시에는 즉각 서비스 이용 중지 및 추후 학교에서 정하는 교칙과 관련 대한민국 법령에 48 | 의거하여 처리합니다.

49 |

개인정보 수집 이용목적 (사용 목적에 변경사항이 발생할 경우 유저에게 해당 사실을 사전에 공지합니다.)

50 |

1) 이메일, 비밀번호를 통한 신원 확인 및 중복 가입 방지

51 |

2) 부정 이용 방지 및 서비스 악용 방지

52 |

3) 기숙사 출석체크 서비스 이용 시에 학생 개개인의 식별

53 |

4) 그 외에 개인 맞춤 서비스 제공을 위해

54 |
55 |

제3조 수집방법

56 |

유저에게 회원가입 시에 제2조에 명시되어있는 1,2,3,4번 항목의 해당하는 정보를 기입받아 수집합니다. 5번 항목은 서버에서 자동으로 수집합니다. 57 | 유저는 수집 방법에 대한 공개를 요청할 있으며 운영진은 해당 행위가 개인정보보호법과 관련 법령을 저해하거나 침해하지 않는 한 공개하여야 합니다.

58 |
59 |

제4조 개인정보 보관 및 기간

60 |

운영진은 제2조에 명시된 목적을 위하여 유저의 서비스 이용 기간 동안 개인정보를 수집, 보관합니다. 그러나 아래에 이유로 유저의 회원탈퇴 이후 30일간 61 | 유저의 전자메일과 비밀번호를 보관합니다. 해당 기간에는 서비스 이용 및 재가입이 불가능합니다.

62 |

1) 유저의 빈번한 탈퇴와 가입으로 인한 서비스 장애 초래 방지

63 |

2) 중복 가입 및 악의적인 정보 이용 방지

64 |

회원탈퇴라 함은 자의로 탈퇴를 진행하였거나 혹은 이용약관에 의거하여 서비스 이용이 중지/제한된 것을 말합니다.

65 |
66 |

제5조 개인정보의 파기 및 절차

67 |

운영진은 유저의 모든 서비스 이용 및 개인정보 보관 기간이 만료된 직후 그 즉시 해당하는 유저의 모든 개인정보를 파기 처리하는 것을 원칙으로 합니다. 파기 절차는 기술적으로 68 | 추후 복구나 기록을 재생할 수 없는 기술적인 방법을 이용해 삭제 처리합니다. 해당 작업은 이행된 이후 회귀될 수 없으며 이에 대한 책임은 운영진이 지지 않습니다.

69 |
70 |

제6조 개인정보의 제공 및 위탁

71 |

운영진은 유저의 개인정보를 이용약관에 명시된 제3자를 제외한 그 어떤 업체나 개인에게 제공하지 않는 것을 원칙으로 합니다. 그러나 해당 유저가 사전에 동의한 경우나, 72 | 관련 법령에 의거하여 적법한 수사 절차를 위한 수사 기관의 공개 요청이 있을 경우에는 예외로 합니다. 운영진은 그 어떠한 업체에게도 개인정보를 위탁하지 않습니다.

73 |
74 |

제7조 유저 및 법정대리인의 권리와 그 행사방법

75 |

이용자 및 법정 대리인은 언제든지 등록되어 있는 자신의 개인정보를 조회하거나 수정할 수 있으며 가입해지를 요청할 수도 있습니다. 76 | 이용자의 개인정보 조회, 수정을 위해서는 ‘개인정보변경’(또는 ‘회원정보수정’ 등)을, 가입해지(동의철회)를 위해서는 “회원탈퇴”를 77 | 클릭하여 본인 확인 후 직접 열람, 정정 또는 탈퇴가 가능합니다. 혹은 개인정보관리책임자에게 서면, 전화 또는 이메일로 연락하시면 지체 없이 조치하겠습니다. 78 | 이용자가 개인정보의 오류에 대한 정정을 요청하신 경우에는 정정을 완료하기 전까지 당해 개인정보를 이용 또는 제공하지 않습니다.

79 |
80 |

제8조 개인정보 자동수집 장치의 설치, 운영 및 그 거부에 관한 사항

81 |

쿠키는 웹사이트를 운영하는데 이용되는 서버가 이용자의 브라우저에 보내는 아주 작은 텍스트 파일로서 이용자의 컴퓨터에 저장됩니다. 82 | 보다 빠르고 편리한 웹사이트 사용을 지원하고 맞춤형 서비스를 제공하기 위해 사용됩니다. 유저가 선호하는 설정 등을 저장하여 83 | 보다 빠른 웹 환경을 지원하며, 편리한 이용을 위해 서비스 개선에 활용합니다. 유저는 쿠키 설치에 대한 선택권을 가지고 있습니다. 84 | 따라서, 이용자는 웹 브라우저에서 옵션을 설정함으로써 모든 쿠키를 허용하거나, 쿠키가 저장될 때마다 확인을 거치거나, 85 | 모든 쿠키의 저장을 거부할 수도 있습니다. 다만, 쿠키의 저장을 거부할 경우에는 로그인이 필요한 일부 서비스는 이용에 어려움이 있을 수 있습니다.

86 |
87 |

제9조 개인정보 관리를 위한 기술적 대책

88 |

운영진은 유저의 개인정보를 취급함에 있어 개인정보가 분실, 도난, 89 | 유출, 변조 또는 훼손되지 않도록 안정성 확보를 위해 다음과 같은 기술적, 관리적 대책을 강구하고 있습니다.

90 |

1) 이용자의 개인정보를 암호화된 통신구간을 이용하여 전송하고, 비밀번호 등 중요정보는 암호화하여 보관하고 있습니다.

91 |

2) 해킹이나 컴퓨터 바이러스 등에 의해 유저의 개인정보가 유출되거나 훼손되는 것을 막기 위해 외부로부터 접근이 통제된 구역에 시스템을 설치하고 있습니다. 92 | 해커 등의 침입을 탐지하고 차단할 수 있는 시스템을 설치하여 24시간 감시하고 있으며, 93 | 백신 프로그램을 설치하여 시스템이 최신 악성코드나 바이러스에 감염되지 않도록 노력하고 있습니다.

94 |

3) 유저가 사용하는 아이디와 비밀번호는 원칙적으로 유저만이 사용할 수 있도록 되어 있습니다. 95 | 운영진은 유저의 개인적인 부주의로 아이디, 비밀번호 등 개인정보가 유출되어 발생한 문제와 기본적인 인터넷의 위험성 때문에 일어나는 일들에 대해 책임을 지지 않습니다. 96 | 비밀번호에 대한 보안의식을 가지고 비밀번호를 자주 변경하며, 타인이 알기 쉬운 비밀번호를 사용하거나, 공용 PC 에서의 로그인시 개인정보가 누출되지 않도록 각별한 주의를 기울여 주시기 바랍니다.

97 |
98 |

제10조 개인정보 관련 민원서비스

99 |

유저의 개인정보를 보호하고 개인정보와 관련한 불만을 처리하기 위하여 아래와 같이 개인정보관리책임자를 지정하고 있습니다. 100 | 유저는 서비스를 이용하며 발생하는 모든 개인정보보호 관련 민원을 개인정보 관리책임자에게 신고하실 수 있습니다.

101 |
102 |

개인정보관리책임자:

103 |

성명 :

104 |

Tel :

105 |

메일 : teamc0nnect3306@gmail.com

106 |
107 |

기타 개인정보침해에 대한 신고나 상담이 필요하신 경우에는 아래 기관에 문의하시기 바랍니다.

108 |

개인정보침해신고센터 (privacy.kisa.or.kr / 국번없이 118)

109 |

대검찰청 사이버수사과 (www.spo.go.kr / 국번없이 1301)

110 |

경찰청 사이버안전국 (cyberbureau.police.go.kr / 국번없이 182)

111 |
112 |

부칙

113 |

이 개인정보처리방침은 2024년 5월 30일부터 적용되며 법령, 정책 또는 보안기술의 변경에 따라 내용의 추가, 114 | 삭제 및 수정이 있을 시에는 변경사항의 시행일의 3일 전부터 Qvick 사이트와 모바일 플랫폼의 알림판을 통하여 고지할 것입니다.

115 | 116 |
117 | 118 | 119 | -------------------------------------------------------------------------------- /src/main/resources/templates/UseTerm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 이용약관 6 | 26 | 31 | 32 | 33 |
34 |

Qvick 이용약관

35 |

36 |

제1조 목적

37 |

Team C0nnect(이하 운영진)는 이용자(이하 유저)에게 기숙사 온라인 출석체크 서비스 "Qvick" (이하 서비스)를 이용하기 위한 약관과 그 정의를 서술하고 있습니다.

38 |
39 |

제2조 이용 조건

40 |

유저는 대구소프트웨어마이스터고등학교(이하 학교)에 재학중이며, 기숙사 시설을 이용 중이거나 이용 예정인 자여야 합니다. 또한 운영진은 아래의 사항에 해당하지 않는 자에게 41 | 합당한 사유가 없는 한 서비스 이용을 수락, 제공해야 합니다.

42 |

1) 유저가 학교 재학생이 아닌 경우, 이는 자퇴 / 퇴학 / 졸업 등 현재 학교 서류 상으로 재학 중이지 않은 경우를 모두 포괄한다.

43 |

2) 유저가 현재 학교에 기숙사 시설을 이용 중이지 않을 경우, 시설 이용자라 함은 기숙사에 숙박하며 이용하는 것을 말한다.

44 |

3) 유저 정보를 허위/과장하여 작성하거나 타인의 개인정보를 도용하였을 경우. 이미 이용 중인 유저더라도 허위/과장된 정보 또는 도용 사실이 밝혀질 경우 즉시 45 | 회원 탈퇴 조치된다.

46 |
47 |

제3조 약관 효력 및 권리

48 |

유저의 회원가입 시 약관 동의 후 즉시 효력이 생기며, 유저는 해당 약관 동의를 거부할 수 있습니다. 그러나 동의하지 않을 경우 서비스 이용이 불가능함을 알립니다. 49 | 운영진은 약관의 내용을 관련 법령이 제정하는 범위에 한하여 변경할 수 있으며 이를 유저에게 공지하어야 합니다. 유저는 관련 내용을 확인 후 언제든 동의를 해지할 수 있으며, 50 | 이에 따라 서비스 이용은 즉각 중지됩니다.

51 |

**약관 해지 의사를 밝히지 않은 경우 동의한 것으로 간주합니다.

52 |
53 |

제4조 회원가입 또는 이용신청

54 |

유저는 회원가입(또는 이용신청이라 칭함)할 시에 아래 각 호에서 정의한 정보를 입력 후, 개인정보처리방침/이용약관에 동의하어야 가입(신청)을 정상적으로 완료할 수 있습니다.

55 |

1) 유저 실명 (주민등록등본에 기재된 실명을 기준으로 한다).

56 |

2) 유저 e-mail(전자메일), 이는 학교에서 제공한 전자메일로 한하며 이는 서비스 관리 및 유지보수의 편의성을 위함이다.

57 |

3) 비밀번호, 이는 유저가 운영진이 정한 규칙에 따라 유저가 정한 비밀번호를 입력하어야 한다.

58 |

4) 학번, 유저는 학교에서 매년 주어지는 4자리의 학번을 입력하어야 한다. 이는 수정될 수 있으며, 허위 정보를 기재할 경우 제3조에 따라 서비스 이용이 중지된다.

59 |

5) 호실, 유저는 항시 본인이 현재 숙박 중인 호실의 호수를 제공하어야 하며 이는 서비스의 본 목적인 "기숙사 관리"를 위함이다.

60 |

**기타 수집/이용하는 개인정보는 개인정보처리방침에 기재합니다.

61 |
62 |

제5조 유저 정보의 수정

63 |

유저가 개인정보처리방침에서 기재하는 개인정보를 수정하고자 하거나, 수정해야할 필요가 있을 경우 즉시 수정하여야 합니다. 이를 수정하지 않아서 발생한 피해/불이익은 64 | 유저 개인이 집니다. 그러나 전자메일, 실명 등 유저 고유의 정보는 아래 사항에 해당하는 경우를 제외하고는 변경될 수 없습니다.

65 |

1) 학교에서 해당 유저의 전자메일 변경/삭제한 경우.

66 |

2) 유저가 관련 법령에 따라 합법적인 절차로 개명을 실시한 경우.

67 |
68 |

제6조 서비스 이용

69 |

이용진이 제공하는 서비스 이용을 위해서는 제4조에서 명시하고 있는 회원가입을 진행하어야 합니다. 회원가입이 되지 않는 유저는 서비스 이용을 할 수 없습니다. 70 | 서비스의 이용 시간은 온라인 플랫폼으로, 24시간 연중무휴임을 명시합니다. 운영진은 아래 각 호에 해당하는 경우 직권으로 유저의 서비스 이용을 제한/중지할 수 있습니다.

71 |

1) 서비스 설비의 점검 및 유지보수 또는 공사

72 |

2) 국가비상사태, 서비스 설비의 장애 또는 서비스 이용의 폭주 등으로 서비스 이용에 지장이 있는 경우

73 |

3) 국가 또는 관계기관의 명령으로 인해 일부 서비스를 제한해야 할 경우

74 |

4) 기타 중대한 사유로 인해 서비스의 이용을 지속하는 것이 업무상 및 기술상 불가능할 경우 또는 운영상 서비스 제한이나 중지가 불가피하다고 판단되는 경우

75 |

운영진은 효율적이고 안전한 서비스 운영을 위하여 이용 수칙을 정할 수 있으며 이를 유저에게 공지합니다, 또한 유저는 해당 수칙을 따라야합니다.

76 |

학교 또는 관련 기관에서 유저의 서비스 이용 중지를 요청할 경우 운영진은 해당 요청을 특별한 사유가 없는 한 받아드리는 것을 원칙으로 합니다.

77 |

운영진은 일정 기간동안 접속 이력이 없는 회원에 대하여 로그인시 본인인증을 거치도록 하는 등의 절차를 둘 수 있습니다.

78 |
79 |

회원이 서비스 내에 게시하거나 전달하는 모든 내용물이 다음 각 호에 해당한다고 판단될 경우 운영진은 사전 통보 없이 게시중단, 이동, 삭제 등의 조치를 취할 수 있으며 80 | 필요한 경우 해당 회원의 서비스 이용자격을 일정 기간 제한하거나 영구 중지할 수 있습니다.

81 |

1) 회원 또는 제3자에 대한 인신공격, 비하, 비방, 욕설, 중상모략, 허위사실 유포, 명예훼손 등의 내용이 포함된 경우

82 |

2) 타인을 고의적으로 기만하거나 부정하게 영리적, 업무적 기타 개인적인 이익을 얻을 목적임이 확인되는 경우

83 |

3) 자신의 종교적 신념을 강요하거나 타인의 종교를 비하한 경우

84 |

4) 공공질서 및 미풍양속에 위반되는 내용인 경우

85 |

5) 범죄적 행위에 결부된다고 인정되는 내용인 경우

86 |

6) 회원 또는 제3자의 저작권이나 초상권 등 기타 권리를 침해하는 내용인 경우

87 |

7) 정보통신설비의 오작동이나 정보 등의 파괴를 유발시키는 컴퓨터바이러스 프로그램 등을 유포하는 경우

88 |

8) 스토킹, 불필요한 특수문자 과다사용, 반복적인 게시물 붙여넣기 등 다른 이용자의 이용을 방해하는 경우

89 |

9) 혐오감, 또는 공포심을 조장하거나 그럴 가능성이 다분한 용어나 파일 등을 게시하여 타 이용자에게 피해를 준 경우

90 |

9) 특정 집단에 대한 차별적 내용으로서 해당 집단이나 그 구성원들에게 굴욕감이나 불이익을 현저하게 초래하는 경우

91 |

11) 기타 관계법령에 위반되거나 운영진에서 정한 각 서비스의 목적에 따른 이용규칙에 어긋나는 경우

92 |

회원의 공개된 게시물 등에 대하여 다른 이용자 혹은 제3자의 법률상 권리 침해를 근거로 게시중단 요청을 받은 경우 운영진은 93 | 게시물을 삭제하거나 게시물 차단 등의 임시조치를 할 수 있으며 게시중단 요청자와 게시물 등록 회원간의 합의 또는 법적조치의 결과 등이 접수되면 이를 따릅니다.

94 |

운영진은 서비스 내에 공개된 게시물 등이 사생활 침해 또는 명예훼손 등 제3자의 권리를 침해한다고 인정하는 경우 전항의 게시중단 요청이 없어도 운영진의 직권으로 95 | 해당 게시물을 게시중단 할 수 있습니다.

96 |
97 |

제7조 저작물 이용

98 |

서비스 내에서 게시된 게시물 등의 저작권은 해당 게시물의 저작자에게 귀속됩니다. 그러나 다음 각 호에 해당하는 범위 내에서 도담도담은 회원이 등록한 게시물을 이용할 수 있습니다.

99 |

1) 서비스 내에서 게시물의 복제, 전송, 전시, 배포 및 이를 위해 게시물의 제목 및 내용을 변경하거나 수정 또는 이동할 수 있습니다.

100 |

2) 게시판의 용도에 적합하지 않거나 이용 규칙에 위배되는 경우, 게시물을 수정하거나 게시판의 위치를 변경, 또는 삭제할 수 있습니다.

101 |

3) 회원이 스크랩 등의 기능을 사용하여 게시물의 제목 및 링크를 이용할 수 있습니다.

102 |

4) 검색 등 향상된 서비스를 위해 관련 제휴사에게 게시물의 제목 및 내용, 게시자의 ID, 닉네임 등 필요한 정보를 제공할 수 있습니다. 103 | 단 이 경우 제공된 정보는 지정된 목적 이외에는 사용되지 않으며, 성명, 이메일 등 회원의 개인정보는 제공되지 않습니다.

104 |
105 |

제8조 운영진의 의무

106 |

1) 운영진은 관련 법령과 이 약관이 정하는 사항을 준수하며, 지속적이고 안정적인 서비스를 위해 최선을 다합니다.

107 |

2) 운영진은 회원의 회원정보를 보호하며, 개인정보처리방침과 개인정보 보호법을 공시하고 준수합니다.

108 |

3) 운영진은 서비스 제공과 관련해서 알고 있는 회원의 신상 정보를 본인의 승낙 없이 제3자에게 누설하거나 배포하지 않습니다. 109 | 단, 전기통신기본법 등 법률의 규정에 의해 국가기관의 요구가 있는 경우, 범죄에 대한 수사상의 목적이 있거나 또는 기타 관계법령에서 정한 절차에 의한 요청이 있을 경우에는 110 | 그러하지 아니합니다.

111 |

4) 운영진은 회원 수신 동의를 하지 않은 영리목적의 광고성 전자우편, SMS 문자서비스 등을 발송하지 아니합니다.

112 |
113 |

제9조 유저의 책임

114 |

1) 유저는 자신의 전자메일, 비밀번호 등 개인정보에 대한 관리책임을 가집니다.

115 |

2) 유저가 작성한 게시물 등에 대한 모든 권리와 책임은 이를 작성한 유저에게 있습니다.

116 |

3) 서비스를 통해 얻은 정보를 그 정보 권리자의 동의없이 수집, 복제, 배포할 수 없습니다.

117 |

4) 서비스를 이용하여 해킹, 불법자료의 배포 및 기타 불법행위를 하여서는 아니되며, 118 | 이를 위반하여 발생한 영업활동의 결과 및 손실, 관계기관에 의한 법적조치 등에 관하여서는 그 유저가 책임을 집니다.

119 |

5) 유저는 운영진이 정한 약관 및 이용규칙을 숙지하고 준수하여야 합니다.

120 |
121 |

제10조 회원탈퇴 및 이용중지

122 |

유저가 회원가입을 통한 이용계약을 해지하고자 하는 때에는 회원 본인이 인터넷을 통하여 해지신청을 하여야 합니다. 123 | 단, 유관기관의 요청이 있는 경우 본인이 직접 탈퇴하지 않아도 이용계약 해지가 가능할 수 있습니다. 유저 개인정보는 회원 탈퇴 30일 후 자동 삭제되며, 124 | 이 기간동안 재가입이 제한됩니다. 이용규칙 또는 약관 등을 위반하여 징계 중인 상태에서 탈퇴할 경우 재가입할 수 없으며, 125 | 만일 재가입 후 징계사실이 확인되면 이용이 제한되거나 이전 회원조치이력을 승계할 수 있습니다.

126 |
127 |

제11조 3자 정보 제공 동의

128 |

운영진은 본 서비스의 기본 목적인 "기숙사 관리"를 위하여 학교에서 지정하는 학생안전부, 기숙사 사감 선생님(이하 제3자라 칭함)등에게 학생의 개인정보를 양도/공개할 수 있습니다. 129 | 그러나 아래 각 호 중 하나라도 해당되는 경우 공개하지 아니합니다. 이미 제공 중인 정보일 경우 운영진 직권으로 그 즉시 정보의 제공을 중단/폐기합니다.

130 |

1) 양도된 정보가 개인정보보호법과 관련 법령을 위반하는 행위에 악용될 여지가 있는 경우.

131 |

2) 정보 양도/공유의 행위가 심각한 정보 유출을 야기할 수 있는 경우.

132 |

3) 기타 운영진의 판단 하에 제공되지 아니해야 하다고 판단될 경우

133 |
134 |

제3자에게 양도되는 정보는 기숙사 운영 및 관리를 위한 최소한의 정보이며 유저는 특별한 경우가 아니라면 이를 제공하는 것에 동의해야 합니다. 또한 아래 기재한 정보가 135 | 아니라고 하여도 기타 필요하다고 생각되는 상황에는 제3자에게 제공될 수 있음을 알립니다.

136 |

1) 유저의 출석 여부

137 |

2) 유저의 실명/전자메일

138 |

3) 유저의 현재 학번/호실

139 |
140 |

운영진은 정보를 제3자에게 제공할 경우 반드시 운영진 내에서 규정한 보안 절차와 비밀번호 암호화 과정을 거치며, 해당 정보의 유출/탈취를 방지하는 것에 최선을 다해야 141 | 합니다. 유저는 원할 경우 정보 제공 방식의 공개 및 수정을 요청할 수 있으며 운영진은 아래 각 호에 해당하지 않는 경우에는 이를 수락하어야 합니다.

142 |

1) 개인정보보호법과 관련 법령에 의거하여 정보 제공 방식의 공개가 이를 위반할 여지가 있는 경우.

143 |

2) 유저가 제안하는 정보 제공 방식의 수정안이 기존 방식보다 보안 또는 기타 기술적인 사유로 부적합할 경우.

144 |
145 |

제12조 양도 금지

146 |

유저는 서비스의 이용권한, 기타 이용계약상의 지위를 타인에게 양도, 증여할 수 없으며, 이를 담보로 제공할 수 없습니다.

147 |
148 |

제13조 손해배상

149 |

무료로 제공되는 서비스와 관련하여 회원에게 어떠한 손해가 발생하더라도 동 손해가 운영진의 150 | 고의 또는 중대한 과실로 인한 경우를 제외하고 이에 대하여 책임을 부담하지 아니합니다.

151 |
152 |

제14조 운영진 면책 조항

153 |

1) 천재지변, 전쟁 또는 기타 이에 준하는 불가항력으로 인하여 서비스를 제공할 수 없는 경우에는 서비스 제공에 관한 책임이 면제됩니다.

154 |

2) 서비스용 설비의 보수, 교체, 정기점검, 공사 등 부득이한 사유로 발생한 손해에 대한 책임이 면제됩니다.

155 |

3) 유저의 귀책사유로 인한 서비스 이용의 장애에 대하여 책임을 지지 않습니다

156 |

4) 서비스를 이용하여 기대하는 이익이나 서비스를 통하여 얻는 자료로 인한 손해에 관하여 책임을 지지 않습니다.

157 |

5) 타 유저가 서비스에 게재한 정보, 자료, 사실의 신뢰도, 정확성 등의 내용에 관하여는 책임을 지지 않습니다.

158 |
159 |

제15조 법적 소재

160 |

운영진과 유저는 서비스에 관하여 발생한 분쟁을 원만하게 해결하기 위하여 필요한 모든 노력을 하여야 합니다. 또한 법적 소재지는 해당 서비스가 이용중인 161 | 학교의 소재지와 동일합니다.

162 |
163 |

제16조 약관 이외의 준칙

164 |

이 약관에서 정하지 아니한 사항이나 해석에 대해서는 관계법령 또는 상관례에 따릅니다.

165 |
166 |

제17조 시행일

167 |

이 약관은 2024년 5월 30일부터 시행합니다.

168 | 169 |
170 | 171 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright © 2015-2021 the original authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | ############################################################################## 19 | # 20 | # Gradle start up script for POSIX generated by Gradle. 21 | # 22 | # Important for running: 23 | # 24 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 25 | # noncompliant, but you have some other compliant shell such as ksh or 26 | # bash, then to run this script, type that shell name before the whole 27 | # command line, like: 28 | # 29 | # ksh Gradle 30 | # 31 | # Busybox and similar reduced shells will NOT work, because this script 32 | # requires all of these POSIX shell features: 33 | # * functions; 34 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 35 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 36 | # * compound commands having a testable exit status, especially «case»; 37 | # * various built-in commands including «command», «set», and «ulimit». 38 | # 39 | # Important for patching: 40 | # 41 | # (2) This script targets any POSIX shell, so it avoids extensions provided 42 | # by Bash, Ksh, etc; in particular arrays are avoided. 43 | # 44 | # The "traditional" practice of packing multiple parameters into a 45 | # space-separated string is a well documented source of bugs and security 46 | # problems, so this is (mostly) avoided, by progressively accumulating 47 | # options in "$@", and eventually passing that to Java. 48 | # 49 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 50 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 51 | # see the in-line comments for details. 52 | # 53 | # There are tweaks for specific operating systems such as AIX, CygWin, 54 | # Darwin, MinGW, and NonStop. 55 | # 56 | # (3) This script is generated from the Groovy template 57 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 58 | # within the Gradle project. 59 | # 60 | # You can find Gradle at https://github.com/gradle/gradle/. 61 | # 62 | ############################################################################## 63 | 64 | # Attempt to set APP_HOME 65 | 66 | # Resolve links: $0 may be a link 67 | app_path=$0 68 | 69 | # Need this for daisy-chained symlinks. 70 | while 71 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 72 | [ -h "$app_path" ] 73 | do 74 | ls=$( ls -ld "$app_path" ) 75 | link=${ls#*' -> '} 76 | case $link in #( 77 | /*) app_path=$link ;; #( 78 | *) app_path=$APP_HOME$link ;; 79 | esac 80 | done 81 | 82 | # This is normally unused 83 | # shellcheck disable=SC2034 84 | APP_BASE_NAME=${0##*/} 85 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 86 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | if ! command -v java >/dev/null 2>&1 134 | then 135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 136 | 137 | Please set the JAVA_HOME variable in your environment to match the 138 | location of your Java installation." 139 | fi 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC2039,SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC2039,SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 201 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 202 | 203 | # Collect all arguments for the java command: 204 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 205 | # and any embedded shellness will be escaped. 206 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 207 | # treated as '${Hostname}' itself on the command line. 208 | 209 | set -- \ 210 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 211 | -classpath "$CLASSPATH" \ 212 | org.gradle.wrapper.GradleWrapperMain \ 213 | "$@" 214 | 215 | # Stop when "xargs" is not available. 216 | if ! command -v xargs >/dev/null 2>&1 217 | then 218 | die "xargs is not available" 219 | fi 220 | 221 | # Use "xargs" to parse quoted args. 222 | # 223 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 224 | # 225 | # In Bash we could simply go: 226 | # 227 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 228 | # set -- "${ARGS[@]}" "$@" 229 | # 230 | # but POSIX shell has neither arrays nor command substitution, so instead we 231 | # post-process each arg (as a line of input to sed) to backslash-escape any 232 | # character that might be a shell metacharacter, then use eval to reverse 233 | # that process (while maintaining the separation between arguments), and wrap 234 | # the whole thing up as a single "set" statement. 235 | # 236 | # This will of course break if any of these variables contains a newline or 237 | # an unmatched quote. 238 | # 239 | 240 | eval "set -- $( 241 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 242 | xargs -n1 | 243 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 244 | tr '\n' ' ' 245 | )" '"$@"' 246 | 247 | exec "$JAVACMD" "$@" 248 | --------------------------------------------------------------------------------