├── settings.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── Dockerfile ├── src ├── main │ ├── kotlin │ │ └── com │ │ │ └── dsm │ │ │ └── clematis │ │ │ ├── domain │ │ │ ├── account │ │ │ │ ├── controller │ │ │ │ │ ├── response │ │ │ │ │ │ └── AccountNameResponse.kt │ │ │ │ │ ├── request │ │ │ │ │ │ ├── AccountNameModificationRequest.kt │ │ │ │ │ │ ├── AccountPasswordModificationRequest.kt │ │ │ │ │ │ └── JoinRequest.kt │ │ │ │ │ └── AccountController.kt │ │ │ │ ├── repository │ │ │ │ │ └── AccountRepository.kt │ │ │ │ ├── exception │ │ │ │ │ ├── AccountNotFoundException.kt │ │ │ │ │ ├── AlreadyExistAccountException.kt │ │ │ │ │ └── PasswordMismatchException.kt │ │ │ │ ├── service │ │ │ │ │ ├── AccountDeletionService.kt │ │ │ │ │ ├── AccountValidationService.kt │ │ │ │ │ ├── AccountCreationService.kt │ │ │ │ │ └── AccountModificationService.kt │ │ │ │ └── domain │ │ │ │ │ └── Account.kt │ │ │ ├── project │ │ │ │ ├── controller │ │ │ │ │ ├── response │ │ │ │ │ │ ├── ProjectCreationResponse.kt │ │ │ │ │ │ ├── ProjectSearchDetailResponse.kt │ │ │ │ │ │ └── ProjectSearchAllResponse.kt │ │ │ │ │ ├── request │ │ │ │ │ │ ├── ProjectModificationRequest.kt │ │ │ │ │ │ └── ProjectCreationRequest.kt │ │ │ │ │ └── ProjectController.kt │ │ │ │ ├── repository │ │ │ │ │ └── ProjectRepository.kt │ │ │ │ ├── exception │ │ │ │ │ ├── ProjectNotFoundException.kt │ │ │ │ │ └── AlreadyExistProjectException.kt │ │ │ │ ├── service │ │ │ │ │ ├── ProjectDeletionService.kt │ │ │ │ │ ├── ProjectSearchService.kt │ │ │ │ │ ├── ProjectModificationService.kt │ │ │ │ │ └── ProjectCreationService.kt │ │ │ │ └── domain │ │ │ │ │ └── Project.kt │ │ │ ├── template │ │ │ │ ├── exception │ │ │ │ │ ├── TemplateSearchException.kt │ │ │ │ │ ├── TemplateCreationException.kt │ │ │ │ │ ├── TemplateNotFoundException.kt │ │ │ │ │ └── AlreadyExistTemplateException.kt │ │ │ │ ├── controller │ │ │ │ │ ├── response │ │ │ │ │ │ ├── TemplateCreationResponse.kt │ │ │ │ │ │ ├── TemplateSearchDetailResponse.kt │ │ │ │ │ │ └── TemplateSearchAllResponse.kt │ │ │ │ │ └── request │ │ │ │ │ │ └── TemplateRequest.kt │ │ │ │ ├── repository │ │ │ │ │ └── TemplateRepository.kt │ │ │ │ ├── service │ │ │ │ │ ├── TemplateSearchService.kt │ │ │ │ │ ├── TemplateDeletionService.kt │ │ │ │ │ ├── TemplateModificationService.kt │ │ │ │ │ └── TemplateCreationService.kt │ │ │ │ └── domain │ │ │ │ │ └── Template.kt │ │ │ ├── authentication │ │ │ │ ├── controller │ │ │ │ │ ├── response │ │ │ │ │ │ ├── TokenResponse.kt │ │ │ │ │ │ └── LoginResponse.kt │ │ │ │ │ ├── request │ │ │ │ │ │ ├── LogoutRequest.kt │ │ │ │ │ │ ├── LoginRequest.kt │ │ │ │ │ │ └── ReissueTokenRequest.kt │ │ │ │ │ └── AuthenticationController.kt │ │ │ │ ├── repository │ │ │ │ │ └── RedisRepository.kt │ │ │ │ ├── domain │ │ │ │ │ └── RefreshToken.kt │ │ │ │ ├── exception │ │ │ │ │ └── TokenNotFoundException.kt │ │ │ │ └── service │ │ │ │ │ ├── AuthenticationDeletionService.kt │ │ │ │ │ ├── AuthenticationCreationService.kt │ │ │ │ │ └── AuthenticationValidationService.kt │ │ │ ├── group │ │ │ │ ├── controller │ │ │ │ │ ├── response │ │ │ │ │ │ ├── MultipleGroupResponse.kt │ │ │ │ │ │ └── SingleGroupResponse.kt │ │ │ │ │ └── request │ │ │ │ │ │ └── GroupRequest.kt │ │ │ │ ├── exception │ │ │ │ │ ├── GroupNotFoundException.kt │ │ │ │ │ └── AlreadyExistGroupException.kt │ │ │ │ ├── repository │ │ │ │ │ └── TargetGroupRepository.kt │ │ │ │ ├── service │ │ │ │ │ ├── GroupDeletionService.kt │ │ │ │ │ ├── GroupModificationService.kt │ │ │ │ │ ├── GroupSearchService.kt │ │ │ │ │ └── GroupCreationService.kt │ │ │ │ └── domain │ │ │ │ │ └── TargetGroup.kt │ │ │ ├── target │ │ │ │ ├── controller │ │ │ │ │ ├── request │ │ │ │ │ │ ├── TargetUnregisterRequest.kt │ │ │ │ │ │ ├── TargetModificationRequest.kt │ │ │ │ │ │ └── TargetRegistrationAllRequest.kt │ │ │ │ │ └── response │ │ │ │ │ │ └── TargetSearchAllResponse.kt │ │ │ │ ├── exception │ │ │ │ │ ├── AlreadyExistTargetException.kt │ │ │ │ │ └── TargetNotFoundException.kt │ │ │ │ ├── repository │ │ │ │ │ └── TargetRepository.kt │ │ │ │ ├── service │ │ │ │ │ ├── TargetSearchService.kt │ │ │ │ │ ├── TargetModificationService.kt │ │ │ │ │ └── TargetRegistrationService.kt │ │ │ │ └── domain │ │ │ │ │ └── Target.kt │ │ │ ├── affiliation │ │ │ │ ├── exception │ │ │ │ │ ├── AlreadyExistAffiliationException.kt │ │ │ │ │ └── AffiliationNotFoundException.kt │ │ │ │ ├── controller │ │ │ │ │ ├── request │ │ │ │ │ │ ├── TargetOfUngroupingRequest.kt │ │ │ │ │ │ └── TargetOfGroupingRequest.kt │ │ │ │ │ └── AffiliationController.kt │ │ │ │ ├── service │ │ │ │ │ ├── AffiliationSearchService.kt │ │ │ │ │ ├── TargetUngroupingService.kt │ │ │ │ │ └── TargetGroupingService.kt │ │ │ │ ├── repository │ │ │ │ │ └── TargetAffiliationRepository.kt │ │ │ │ └── domain │ │ │ │ │ └── TargetAffiliation.kt │ │ │ └── push │ │ │ │ ├── exception │ │ │ │ └── FirebasePushNotificationException.kt │ │ │ │ ├── controller │ │ │ │ ├── response │ │ │ │ │ ├── PushNotificationHistoryDetailResponse.kt │ │ │ │ │ └── PushNotificationHistoryResponse.kt │ │ │ │ └── request │ │ │ │ │ ├── TemplatePushRequest.kt │ │ │ │ │ └── PushRequest.kt │ │ │ │ ├── repository │ │ │ │ ├── PushResultRepository.kt │ │ │ │ └── PushNotificationHistoryRepository.kt │ │ │ │ ├── external │ │ │ │ ├── FirebasePushNotificationMessage.kt │ │ │ │ └── FirebaseConnection.kt │ │ │ │ ├── service │ │ │ │ ├── PushNotificationCreationService.kt │ │ │ │ └── PushNotificationSearchService.kt │ │ │ │ ├── domain │ │ │ │ ├── PushResult.kt │ │ │ │ └── PushNotificationHistory.kt │ │ │ │ └── scheduler │ │ │ │ └── ReservationPushNotificationScheduler.kt │ │ │ ├── global │ │ │ ├── security │ │ │ │ ├── provider │ │ │ │ │ ├── ProjectCodeProvider.kt │ │ │ │ │ ├── RandomProjectCodeProvider.kt │ │ │ │ │ ├── AuthenticationProvider.kt │ │ │ │ │ └── TokenProvider.kt │ │ │ │ ├── filter │ │ │ │ │ ├── LogFilter.kt │ │ │ │ │ └── AuthenticationFilter.kt │ │ │ │ └── configuration │ │ │ │ │ └── SecurityConfiguration.kt │ │ │ ├── exception │ │ │ │ ├── response │ │ │ │ │ └── CommonExceptionResponse.kt │ │ │ │ ├── CommonException.kt │ │ │ │ ├── InvalidTokenException.kt │ │ │ │ ├── InvalidRequestException.kt │ │ │ │ ├── NonExistPushStatusException.kt │ │ │ │ ├── entrypoint │ │ │ │ │ └── InvalidTokenExceptionEntryPoint.kt │ │ │ │ └── handler │ │ │ │ │ └── ExceptionHandler.kt │ │ │ ├── attribute │ │ │ │ ├── PushStatus.kt │ │ │ │ └── Token.kt │ │ │ ├── configuration │ │ │ │ ├── PasswordEncoderConfiguration.kt │ │ │ │ ├── ObjectMapperConfiguration.kt │ │ │ │ ├── CrossOriginResourceSharingConfiguration.kt │ │ │ │ ├── FirebaseConfiguration.kt │ │ │ │ ├── DatabaseConfiguration.kt │ │ │ │ ├── RedisConfiguration.kt │ │ │ │ └── SwaggerConfiguration.kt │ │ │ ├── validation │ │ │ │ ├── NotDuplicate.kt │ │ │ │ └── NotDuplicateValidator.kt │ │ │ └── converter │ │ │ │ └── PushStatusConverter.kt │ │ │ └── ClematisApplication.kt │ └── resources │ │ ├── application.yml │ │ └── firebase │ │ └── kkoribyeol_firebase_secret.json └── test │ ├── resources │ ├── application.yml │ └── data.sql │ └── kotlin │ └── com │ └── dsm │ └── clematis │ ├── domain │ ├── account │ │ ├── repository │ │ │ └── AccountRepositoryTest.kt │ │ └── service │ │ │ ├── AccountDeletionServiceTest.kt │ │ │ ├── AccountCreationServiceTest.kt │ │ │ ├── AccountValidationServiceTest.kt │ │ │ └── AccountModificationServiceTest.kt │ ├── project │ │ ├── repository │ │ │ └── ProjectRepositoryTest.kt │ │ └── service │ │ │ ├── ProjectDeletionServiceTest.kt │ │ │ ├── ProjectModificationServiceTest.kt │ │ │ └── ProjectSearchServiceTest.kt │ ├── authentication │ │ ├── service │ │ │ ├── AuthenticationDeletionServiceTest.kt │ │ │ └── AuthenticationCreationServiceTest.kt │ │ └── repository │ │ │ └── TestRedisRepository.kt │ ├── push │ │ └── service │ │ │ └── TestPushNotificationCreationService.kt │ ├── template │ │ ├── repository │ │ │ └── TemplateRepositoryTest.kt │ │ └── service │ │ │ ├── TemplateDeletionServiceTest.kt │ │ │ ├── TemplateModificationServiceTest.kt │ │ │ ├── TemplateCreationServiceTest.kt │ │ │ └── TemplateSearchServiceTest.kt │ ├── affiliation │ │ ├── service │ │ │ └── AffiliationSearchServiceTest.kt │ │ └── repository │ │ │ └── TargetAffiliationRepositoryTest.kt │ ├── group │ │ ├── service │ │ │ ├── GroupModificationServiceTest.kt │ │ │ └── GroupDeletionServiceTest.kt │ │ └── repository │ │ │ └── TargetGroupRepositoryTest.kt │ └── target │ │ ├── service │ │ ├── TargetModificationServiceTest.kt │ │ └── TargetSearchServiceTest.kt │ │ └── repository │ │ └── TargetRepositoryTest.kt │ └── global │ ├── configuration │ ├── TestPasswordEncoderConfiguration.kt │ ├── TestDatabaseConfiguration.kt │ └── TestRedisConfiguration.kt │ └── security │ └── provider │ └── TestTokenProvider.kt ├── .github └── workflows │ └── CICD.yml ├── gradlew.bat └── .gitignore /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "clematis" 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KKoribyeol/Backend-Clematis/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:12-alpine 2 | COPY ./build/libs/*.jar kkoribyeol.jar 3 | ENTRYPOINT ["java", "-Xmx100m", "-jar", "-Duser.timezone=Asia/Seoul", "/kkoribyeol.jar"] -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/account/controller/response/AccountNameResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.account.controller.response 2 | 3 | data class AccountNameResponse(val name: String) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/security/provider/ProjectCodeProvider.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.security.provider 2 | 3 | interface ProjectCodeProvider { 4 | fun generateRandomCode(): String 5 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/project/controller/response/ProjectCreationResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.project.controller.response 2 | 3 | data class ProjectCreationResponse(val projectId: String) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/template/exception/TemplateSearchException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.template.exception 2 | 3 | class TemplateSearchException : RuntimeException("템플릿을 검색하는 중에 문제가 발생하였습니다.") -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/authentication/controller/response/TokenResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.authentication.controller.response 2 | 3 | data class TokenResponse( 4 | val token: String, 5 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/template/controller/response/TemplateCreationResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.template.controller.response 2 | 3 | data class TemplateCreationResponse(val creationNumber: Long) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/template/exception/TemplateCreationException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.template.exception 2 | 3 | class TemplateCreationException : RuntimeException("템플릿을 생성하는 중에 문제가 발생하였습니다.") -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/exception/response/CommonExceptionResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.exception.response 2 | 3 | data class CommonExceptionResponse( 4 | val code: String, 5 | val message: String, 6 | ) -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/authentication/controller/response/LoginResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.authentication.controller.response 2 | 3 | data class LoginResponse( 4 | val accessToken: String, 5 | val refreshToken: String, 6 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/attribute/PushStatus.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.attribute 2 | 3 | enum class PushStatus(val status: String, val isComplete: Boolean) { 4 | SUCCESS("success", true), 5 | FAILURE("failure", false), 6 | WAITING("waiting", false), 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/exception/CommonException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.exception 2 | 3 | import org.springframework.http.HttpStatus 4 | 5 | open class CommonException( 6 | val code: String, 7 | message: String, 8 | val status: HttpStatus, 9 | ) : RuntimeException(message) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/project/controller/response/ProjectSearchDetailResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.project.controller.response 2 | 3 | data class ProjectSearchDetailResponse( 4 | val projectCode: String, 5 | val projectName: String, 6 | val projectDescription: String?, 7 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/account/repository/AccountRepository.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.account.repository 2 | 3 | import com.dsm.clematis.domain.account.domain.Account 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | 6 | interface AccountRepository : JpaRepository -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/group/controller/response/MultipleGroupResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.group.controller.response 2 | 3 | data class MultipleGroupResponse( 4 | val groups: List, 5 | ) { 6 | 7 | data class GroupResponse( 8 | val name: String, 9 | ) 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/authentication/controller/request/LogoutRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.authentication.controller.request 2 | 3 | import javax.validation.constraints.NotBlank 4 | 5 | data class LogoutRequest( 6 | 7 | @get:NotBlank(message = " ") 8 | val token: String, 9 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/target/controller/request/TargetUnregisterRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.target.controller.request 2 | 3 | import javax.validation.constraints.NotEmpty 4 | 5 | data class TargetUnregisterRequest( 6 | 7 | @get:NotEmpty(message = " ") 8 | val tokens: List 9 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/exception/InvalidTokenException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.exception 2 | 3 | import org.springframework.http.HttpStatus 4 | 5 | class InvalidTokenException : CommonException( 6 | code = "INVALID_TOKEN", 7 | message = "유효하지 않은 토큰입니다.", 8 | status = HttpStatus.UNAUTHORIZED, 9 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/authentication/repository/RedisRepository.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.authentication.repository 2 | 3 | import com.dsm.clematis.domain.authentication.domain.RefreshToken 4 | import org.springframework.data.repository.CrudRepository 5 | 6 | interface RedisRepository : CrudRepository -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/project/repository/ProjectRepository.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.project.repository 2 | 3 | import com.dsm.clematis.domain.project.domain.Project 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | 6 | interface ProjectRepository : JpaRepository { 7 | fun existsByName(name: String): Boolean 8 | } -------------------------------------------------------------------------------- /src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jpa: 3 | database: h2 4 | database-platform: org.hibernate.dialect.H2Dialect 5 | generate-ddl: false 6 | show-sql: false 7 | h2: 8 | console: 9 | enabled: true 10 | path: /h2-console 11 | output: 12 | ansi: 13 | enabled: always 14 | server: 15 | address: 0.0.0.0 16 | port: 6180 -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/authentication/domain/RefreshToken.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.authentication.domain 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.redis.core.RedisHash 5 | 6 | @RedisHash("token") 7 | class RefreshToken( 8 | @Id 9 | val accountId: String, 10 | val refreshToken: String, 11 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/exception/InvalidRequestException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.exception 2 | 3 | import org.springframework.http.HttpStatus 4 | 5 | class InvalidRequestException( 6 | reason: String, 7 | ) : CommonException( 8 | code = "INVALID_REQUEST", 9 | message = "요청 검증에 실패하였습니다. [$reason]", 10 | status = HttpStatus.BAD_REQUEST, 11 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/group/controller/response/SingleGroupResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.group.controller.response 2 | 3 | data class SingleGroupResponse( 4 | val groupName: String, 5 | val targets: List, 6 | ) { 7 | 8 | data class TargetInGroup( 9 | val token: String, 10 | val nickname: String, 11 | ) 12 | } -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jpa: 3 | database: mysql 4 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect 5 | generate-ddl: false 6 | show-sql: false 7 | output: 8 | ansi: 9 | enabled: always 10 | server: 11 | address: 0.0.0.0 12 | port: 6180 13 | tomcat: 14 | threads: 15 | max: 100 16 | max-connections: 4000 -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/exception/NonExistPushStatusException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.exception 2 | 3 | import org.springframework.http.HttpStatus 4 | 5 | class NonExistPushStatusException( 6 | pushStatus: String, 7 | ) : CommonException( 8 | code = "NON_EXIST_STATUS", 9 | message = "존재하지 않는 푸시 상태입니다. [$pushStatus]", 10 | status = HttpStatus.BAD_REQUEST, 11 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/target/controller/response/TargetSearchAllResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.target.controller.response 2 | 3 | data class TargetSearchAllResponse( 4 | val targets: List, 5 | ) { 6 | 7 | data class TargetSearchResponse( 8 | val token: String, 9 | val nickname: String, 10 | val name: String?, 11 | ) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/project/controller/response/ProjectSearchAllResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.project.controller.response 2 | 3 | data class ProjectSearchAllResponse( 4 | val projects: List 5 | ) { 6 | 7 | data class ProjectSearchResponse( 8 | val code: String, 9 | val name: String, 10 | val description: String?, 11 | ) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/authentication/controller/request/LoginRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.authentication.controller.request 2 | 3 | import javax.validation.constraints.NotBlank 4 | 5 | data class LoginRequest( 6 | 7 | @get:NotBlank(message = "아이디를 작성해주세요.") 8 | val accountId: String, 9 | 10 | @get:NotBlank(message = "비밀번호를 작성해주세요.") 11 | val accountPassword: String, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/target/controller/request/TargetModificationRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.target.controller.request 2 | 3 | import javax.validation.constraints.Size 4 | 5 | data class TargetModificationRequest( 6 | 7 | @get:Size(min = 1, max = 255, message = "<1~255>") 8 | val nickname: String?, 9 | 10 | @get:Size(max = 12, message = "<~12>") 11 | val name: String?, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/target/exception/AlreadyExistTargetException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.target.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class AlreadyExistTargetException : CommonException( 7 | code = "ALREADY_EXIST_TARGET", 8 | message = "이미 존재하는 타겟입니다.", 9 | status = HttpStatus.BAD_REQUEST, 10 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/project/controller/request/ProjectModificationRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.project.controller.request 2 | 3 | import javax.validation.constraints.Size 4 | 5 | data class ProjectModificationRequest( 6 | 7 | @get:Size(min = 1, max = 20, message = "<1~20>") 8 | val name: String?, 9 | 10 | @get:Size(min = 0, max = 100, message = "<0~100>") 11 | val description: String?, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/attribute/Token.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.attribute 2 | 3 | enum class Token(val millisecondOfExpirationTime: Long, val kind: String) { 4 | ACCESS( 5 | millisecondOfExpirationTime = 1000 * 60 * 60 * 4, 6 | kind = "accessToken" 7 | ), 8 | REFRESH( 9 | millisecondOfExpirationTime = 1000 * 60 * 60 * 24 * 7 * 2, 10 | kind = "refreshToken" 11 | ), 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/template/controller/response/TemplateSearchDetailResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.template.controller.response 2 | 3 | import java.time.LocalDateTime 4 | 5 | data class TemplateSearchDetailResponse( 6 | val templateId: Long?, 7 | val templateTitle: String, 8 | val templateBody: String, 9 | val templateCreatedAt: LocalDateTime, 10 | val templateUpdatedAt: LocalDateTime, 11 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/authentication/controller/request/ReissueTokenRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.authentication.controller.request 2 | 3 | import javax.validation.constraints.NotBlank 4 | 5 | data class ReissueTokenRequest( 6 | 7 | @get:NotBlank(message = " ") 8 | val accessToken: String, 9 | 10 | @get:NotBlank(message = " ") 11 | val refreshToken: String, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/affiliation/exception/AlreadyExistAffiliationException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.affiliation.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class AlreadyExistAffiliationException : CommonException( 7 | code = "ALREADY_EXIST_AFFILIATION", 8 | message = "이미 존재하는 소속 정보입니다.", 9 | status = HttpStatus.BAD_REQUEST, 10 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/push/exception/FirebasePushNotificationException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.push.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class FirebasePushNotificationException : CommonException( 7 | code = "FIREBASE_PUSH_NOTIFICATION", 8 | message = "파이어베이스와 통신 중 문제가 발생하였습니다.", 9 | status = HttpStatus.INTERNAL_SERVER_ERROR, 10 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/target/exception/TargetNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.target.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class TargetNotFoundException( 7 | targetToken: String, 8 | ) : CommonException( 9 | code = "TARGET_NOT_FOUND", 10 | message = "타겟을 찾을 수 없습니다. [$targetToken]", 11 | status = HttpStatus.NOT_FOUND, 12 | ) -------------------------------------------------------------------------------- /src/test/kotlin/com/dsm/clematis/domain/account/repository/AccountRepositoryTest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.account.repository 2 | 3 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest 4 | import org.springframework.test.context.TestConstructor 5 | 6 | @DataJpaTest 7 | @TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) 8 | internal class AccountRepositoryTest( 9 | private val accountRepository: AccountRepository, 10 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/ClematisApplication.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing 6 | 7 | @EnableJpaAuditing 8 | @SpringBootApplication 9 | class ClematisApplication 10 | 11 | fun main(args: Array) { 12 | runApplication(*args) 13 | } 14 | -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/account/exception/AccountNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.account.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class AccountNotFoundException( 7 | accountId: String, 8 | ) : CommonException( 9 | code = "ACCOUNT_NOT_FOUND", 10 | message = "계정을 찾을 수 없습니다. [id = $accountId]", 11 | status = HttpStatus.NOT_FOUND, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/project/exception/ProjectNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.project.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class ProjectNotFoundException( 7 | projectCode: String, 8 | ) : CommonException( 9 | code = "PROJECT_NOT_FOUND", 10 | message = "프로젝트를 찾을 수 없습니다. [$projectCode]", 11 | status = HttpStatus.NOT_FOUND, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/configuration/PasswordEncoderConfiguration.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.configuration 2 | 3 | import org.springframework.context.annotation.Bean 4 | import org.springframework.context.annotation.Configuration 5 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder 6 | 7 | @Configuration 8 | class PasswordEncoderConfiguration { 9 | 10 | @Bean 11 | fun passwordEncoder() = BCryptPasswordEncoder() 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/account/exception/AlreadyExistAccountException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.account.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class AlreadyExistAccountException( 7 | accountId: String, 8 | ) : CommonException( 9 | code = "ALREADY_EXIST_ACCOUNT", 10 | message = "이미 존재하는 계정입니다. [$accountId]", 11 | status = HttpStatus.BAD_REQUEST, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/account/service/AccountDeletionService.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.account.service 2 | 3 | import com.dsm.clematis.domain.account.repository.AccountRepository 4 | import org.springframework.stereotype.Service 5 | 6 | @Service 7 | class AccountDeletionService( 8 | private val accountRepository: AccountRepository, 9 | ) { 10 | 11 | fun deleteAccount(accountId: String) = 12 | accountRepository.deleteById(accountId) 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/authentication/exception/TokenNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.authentication.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class TokenNotFoundException( 7 | accountId: String, 8 | ) : CommonException( 9 | code = "TOKEN_NOT_FOUND", 10 | message = "레디스에서 리프레시 토큰을 찾을 수 없습니다. [$accountId]", 11 | status = HttpStatus.NOT_FOUND, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/template/exception/TemplateNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.template.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class TemplateNotFoundException( 7 | templateId: Long 8 | ) : CommonException( 9 | code = "TEMPLATE_NOT_FOUND", 10 | message = "템플릿을 찾을 수 없습니다. [templateId = $templateId]", 11 | status = HttpStatus.NOT_FOUND, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/project/exception/AlreadyExistProjectException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.project.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class AlreadyExistProjectException( 7 | projectName: String, 8 | ) : CommonException( 9 | code = "ALREADY_EXIST_PROJECT", 10 | message = "이름이 같은 프로젝트가 이미 존재합니다. [$projectName]", 11 | status = HttpStatus.BAD_REQUEST, 12 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/push/controller/response/PushNotificationHistoryDetailResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.push.controller.response 2 | 3 | data class PushNotificationHistoryDetailResponse( 4 | val pageNumber: Int, 5 | val totalPageNumber: Int, 6 | val historyDetails: List, 7 | val isLastPage: Boolean, 8 | ) { 9 | 10 | data class HistoryDetail( 11 | val targetToken: String, 12 | val status: String, 13 | ) 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/account/controller/request/AccountNameModificationRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.account.controller.request 2 | 3 | import javax.validation.constraints.NotBlank 4 | import javax.validation.constraints.Pattern 5 | 6 | data class AccountNameModificationRequest( 7 | 8 | @get:NotBlank(message = " ") 9 | @get:Pattern(regexp = "^[a-zA-Zㄱ-ㅎ가-힣\\s]{1,12}$", message = "정규표현식 = ^[a-zA-Zㄱ-ㅎ가-힣\\s]{1,12}$") 10 | val newName: String, 11 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/group/controller/request/GroupRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.group.controller.request 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import javax.validation.constraints.NotBlank 5 | import javax.validation.constraints.Size 6 | 7 | data class GroupRequest( 8 | 9 | @JsonProperty("name") 10 | @get:Size(min = 1, max = 20, message = "<1~20>") 11 | @get:NotBlank(message = " ") 12 | val groupName: String?, 13 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/push/repository/PushResultRepository.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.push.repository 2 | 3 | import com.dsm.clematis.domain.push.domain.PushResult 4 | import org.springframework.data.domain.Page 5 | import org.springframework.data.domain.Pageable 6 | import org.springframework.data.jpa.repository.JpaRepository 7 | 8 | interface PushResultRepository : JpaRepository { 9 | fun findByHistoryId(historyId: Long, pageable: Pageable): Page 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/validation/NotDuplicate.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.validation 2 | 3 | import javax.validation.Constraint 4 | import kotlin.reflect.KClass 5 | 6 | @Target(AnnotationTarget.FIELD) 7 | @Retention(AnnotationRetention.RUNTIME) 8 | @Constraint(validatedBy = [NotDuplicateValidator::class]) 9 | annotation class NotDuplicate( 10 | val message: String = "중복된 값이 있을 수 없습니다.", 11 | val groups: Array> = [], 12 | val payload: Array> = [], 13 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/group/exception/GroupNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.group.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class GroupNotFoundException( 7 | projectCode: String, 8 | groupName: String, 9 | ) : CommonException( 10 | code = "GROUP_NOT_FOUND", 11 | message = "그룹을 찾을 수 없습니다. [projectCode: $projectCode, groupName: $groupName]", 12 | status = HttpStatus.NOT_FOUND, 13 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/group/exception/AlreadyExistGroupException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.group.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class AlreadyExistGroupException( 7 | projectCode: String, 8 | groupName: String, 9 | ) : CommonException( 10 | code = "ALREADY_EXIST_GROUP", 11 | message = "이미 존재하는 그룹입니다. [projectCode = $projectCode, groupName = $groupName]", 12 | status = HttpStatus.BAD_REQUEST, 13 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/project/controller/request/ProjectCreationRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.project.controller.request 2 | 3 | import javax.validation.constraints.NotBlank 4 | import javax.validation.constraints.Size 5 | 6 | data class ProjectCreationRequest( 7 | 8 | @get:NotBlank(message = " ") 9 | @get:Size(min = 1, max = 20, message = "<1~20>") 10 | val name: String, 11 | 12 | @get:Size(min = 0, max = 100, message = "<0~100>") 13 | val description: String?, 14 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/configuration/ObjectMapperConfiguration.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.configuration 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper 4 | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper 5 | import org.springframework.context.annotation.Bean 6 | import org.springframework.context.annotation.Configuration 7 | 8 | @Configuration 9 | class ObjectMapperConfiguration { 10 | 11 | @Bean 12 | fun objectMapper(): ObjectMapper = jacksonObjectMapper().findAndRegisterModules() 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/affiliation/exception/AffiliationNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.affiliation.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class AffiliationNotFoundException( 7 | groupName: String, 8 | targetToken: String, 9 | ) : CommonException( 10 | code = "AFFILIATION_NOT_FOUND", 11 | message = "소속 정보가 존재하지 않습니다. [GroupName: $groupName, TargetToken: $targetToken]", 12 | status = HttpStatus.NOT_FOUND, 13 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/template/exception/AlreadyExistTemplateException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.template.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class AlreadyExistTemplateException( 7 | templateTitle: String, 8 | templateBody: String, 9 | ) : CommonException( 10 | code = "ALREADY_EXIST_TEMPLATE", 11 | message = "이미 존재하는 템플릿입니다. [title = $templateTitle, body = $templateBody]", 12 | status = HttpStatus.BAD_REQUEST, 13 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/affiliation/controller/request/TargetOfUngroupingRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.affiliation.controller.request 2 | 3 | import javax.validation.constraints.NotBlank 4 | import javax.validation.constraints.Pattern 5 | 6 | data class TargetOfUngroupingRequest( 7 | 8 | @get:Pattern(regexp = "^[a-zA-Z0-9-]{1,20}$") 9 | @get:NotBlank(message = " ") 10 | val groupName: String, 11 | 12 | @get:NotBlank(message = " ") 13 | val targetToken: String, 14 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/template/controller/request/TemplateRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.template.controller.request 2 | 3 | import javax.validation.constraints.NotBlank 4 | import javax.validation.constraints.Size 5 | 6 | data class TemplateRequest( 7 | 8 | @get:NotBlank(message = " ") 9 | @get:Size(min = 1, max = 40, message = "<1~40>") 10 | val title: String, 11 | 12 | @get:NotBlank(message = " ") 13 | @get:Size(min = 1, max = 255, message = "<1~255>") 14 | val body: String, 15 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/affiliation/controller/request/TargetOfGroupingRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.affiliation.controller.request 2 | 3 | import javax.validation.constraints.NotBlank 4 | import javax.validation.constraints.NotEmpty 5 | import javax.validation.constraints.Pattern 6 | 7 | data class TargetOfGroupingRequest( 8 | 9 | @Pattern(regexp = "^[a-zA-Z0-9-]{1,20}$") 10 | @get:NotBlank(message = " ") 11 | val groupName: String, 12 | 13 | @get:NotBlank(message = " ") 14 | val targetToken: String, 15 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/security/provider/RandomProjectCodeProvider.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.security.provider 2 | 3 | import org.springframework.stereotype.Component 4 | import kotlin.random.Random 5 | 6 | @Component 7 | class RandomProjectCodeProvider : ProjectCodeProvider { 8 | private val codeCharacterPool = ('a'..'z') + ('A'..'Z') + ('0'..'9') 9 | 10 | override fun generateRandomCode() = 11 | (1..7) 12 | .map { Random.nextInt(0, codeCharacterPool.size) } 13 | .map { codeCharacterPool[it] } 14 | .joinToString("") 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/template/controller/response/TemplateSearchAllResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.template.controller.response 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | 5 | data class TemplateSearchAllResponse( 6 | val templates: List, 7 | ) { 8 | 9 | data class TemplateSearchResponse( 10 | @JsonProperty("id") 11 | val templateId: Long, 12 | @JsonProperty("title") 13 | val templateTitle: String, 14 | @JsonProperty("body") 15 | val templateBody: String, 16 | ) 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/authentication/service/AuthenticationDeletionService.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.authentication.service 2 | 3 | import com.dsm.clematis.domain.authentication.repository.RedisRepository 4 | import org.springframework.stereotype.Service 5 | import org.springframework.transaction.annotation.Transactional 6 | 7 | @Service 8 | class AuthenticationDeletionService( 9 | private val redisRepository: RedisRepository, 10 | ) { 11 | 12 | @Transactional 13 | fun deleteToken( 14 | accountId: String, 15 | ) = redisRepository.deleteById(accountId) 16 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/account/exception/PasswordMismatchException.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.account.exception 2 | 3 | import com.dsm.clematis.global.exception.CommonException 4 | import org.springframework.http.HttpStatus 5 | 6 | class PasswordMismatchException( 7 | password: String, 8 | confirmPassword: String? = null, 9 | ) : CommonException( 10 | code = "PASSWORD_MISMATCH", 11 | message = if (confirmPassword == null) "패스워드가 일치하지 않습니다. [$password]" 12 | else "패스워드가 일치하지 않습니다. [$password != $confirmPassword]", 13 | status = HttpStatus.BAD_REQUEST, 14 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/push/external/FirebasePushNotificationMessage.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.push.external 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties 4 | 5 | @JsonIgnoreProperties(ignoreUnknown = true) 6 | data class FirebasePushNotificationMessage( 7 | val validateOnly: Boolean, 8 | val message: FirebaseMessage, 9 | ) { 10 | 11 | data class FirebaseMessage( 12 | val token: String, 13 | val notification: FirebaseNotification, 14 | ) 15 | 16 | data class FirebaseNotification( 17 | val title: String, 18 | val body: String, 19 | ) 20 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/push/controller/response/PushNotificationHistoryResponse.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.push.controller.response 2 | 3 | import java.time.LocalDateTime 4 | 5 | data class PushNotificationHistoryResponse( 6 | val pageNumber: Int, 7 | val totalPageNumber: Int, 8 | val histories: List, 9 | val isLastPage: Boolean, 10 | ) { 11 | 12 | data class History( 13 | val id: Long, 14 | val title: String, 15 | val body: String, 16 | val createdAt: LocalDateTime, 17 | val reservedAt: LocalDateTime?, 18 | val completedAt: LocalDateTime?, 19 | ) 20 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/push/external/FirebaseConnection.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.push.external 2 | 3 | import com.dsm.clematis.domain.push.external.FirebasePushNotificationMessage.FirebaseMessage 4 | import retrofit2.Call 5 | import retrofit2.http.* 6 | 7 | interface FirebaseConnection { 8 | 9 | @Headers(value = ["accept: application/json", "content-type: application/json"]) 10 | @POST 11 | fun sendPushNotificationToFirebase( 12 | @Header("Authorization") authorization: String, 13 | @Url uri: String, 14 | @Body pushNotificationMessage: FirebasePushNotificationMessage, 15 | ): Call 16 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/group/repository/TargetGroupRepository.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.group.repository 2 | 3 | import com.dsm.clematis.domain.group.domain.TargetGroup 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | 6 | interface TargetGroupRepository : JpaRepository { 7 | fun existsByProjectCodeAndGroupName(projectCode: String, groupName: String): Boolean 8 | 9 | fun findByProjectCodeAndAndGroupName(projectCode: String, groupName: String): TargetGroup? 10 | fun findByProjectCode(projectCode: String): List 11 | 12 | fun deleteByProjectCodeAndAndGroupName(projectCode: String, groupName: String) 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/push/repository/PushNotificationHistoryRepository.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.push.repository 2 | 3 | import com.dsm.clematis.domain.push.domain.PushNotificationHistory 4 | import org.springframework.data.domain.Page 5 | import org.springframework.data.domain.Pageable 6 | import org.springframework.data.jpa.repository.JpaRepository 7 | import java.time.LocalDateTime 8 | 9 | interface PushNotificationHistoryRepository : JpaRepository { 10 | fun findByCompletedAtIsNullAndReservedAtBefore(date: LocalDateTime): List 11 | fun findByProjectCode(projectCode: String, pageable: Pageable): Page 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/configuration/CrossOriginResourceSharingConfiguration.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.configuration 2 | 3 | import org.springframework.context.annotation.Configuration 4 | import org.springframework.web.servlet.config.annotation.CorsRegistry 5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer 6 | 7 | @Configuration 8 | class CrossOriginResourceSharingConfiguration : WebMvcConfigurer { 9 | 10 | override fun addCorsMappings(registry: CorsRegistry) { 11 | registry.addMapping("/**") 12 | .allowedOrigins("*") 13 | .allowedMethods("*") 14 | .allowCredentials(false) 15 | .maxAge(3000) 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/global/converter/PushStatusConverter.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.global.converter 2 | 3 | import com.dsm.clematis.global.attribute.PushStatus 4 | import com.dsm.clematis.global.exception.NonExistPushStatusException 5 | import javax.persistence.AttributeConverter 6 | import javax.persistence.Converter 7 | 8 | @Converter 9 | class PushStatusConverter : AttributeConverter { 10 | 11 | override fun convertToDatabaseColumn(status: PushStatus) = 12 | status.status 13 | 14 | override fun convertToEntityAttribute(status: String) = 15 | PushStatus.values().singleOrNull { it.status == status } 16 | ?: throw NonExistPushStatusException(status) 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/account/controller/request/AccountPasswordModificationRequest.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.account.controller.request 2 | 3 | import javax.validation.constraints.NotBlank 4 | import javax.validation.constraints.Pattern 5 | 6 | data class AccountPasswordModificationRequest( 7 | 8 | @get:NotBlank(message = " ") 9 | @get:Pattern(regexp = "^[a-zA-Z0-9!@#$%^&*]{8,20}$", message = "정규표현식 = ^[a-zA-Z0-9!@#$%^&*]{8,20}$") 10 | val newPassword: String, 11 | 12 | @get:NotBlank(message = " ") 13 | @get:Pattern(regexp = "^[a-zA-Z0-9!@#$%^&*]{8,20}$", message = "정규표현식 = ^[a-zA-Z0-9!@#$%^&*]{8,20}$") 14 | val confirmNewPassword: String, 15 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/dsm/clematis/domain/template/repository/TemplateRepository.kt: -------------------------------------------------------------------------------- 1 | package com.dsm.clematis.domain.template.repository 2 | 3 | import com.dsm.clematis.domain.template.domain.Template 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | 6 | interface TemplateRepository : JpaRepository { 7 | fun findByProjectCode(projectCode: String): List