├── 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 extends GrantedAuthority> authorities;
18 |
19 | private CustomUserDetails(final User user, final Collection extends GrantedAuthority> 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 extends GrantedAuthority> 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 |
--------------------------------------------------------------------------------