├── .github └── workflows │ ├── build.yml │ ├── deploy-docker.yml │ └── deploy-mono.yml ├── .gitignore ├── README-ENG.md ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── infra ├── README.md ├── infra │ ├── .env │ ├── docker-compose.yml │ ├── mysql │ │ └── conf │ │ │ └── docker-mysql.cnf │ └── nginx │ │ └── sites-available │ │ └── default └── script │ ├── deploy.sh │ ├── shutdown.sh │ └── startup.sh ├── settings.gradle.kts └── src ├── course ├── rest │ ├── Meeting.http │ ├── asset │ │ ├── large-size.jpg │ │ └── test.jpg │ ├── club │ │ ├── Club.http │ │ ├── ClubInfo.http │ │ ├── album │ │ │ ├── ClubAlbum.http │ │ │ ├── ClubAlbumComment.http │ │ │ └── ClubAlbumLike.http │ │ ├── board │ │ │ ├── ClubBoard.http │ │ │ ├── ClubBoardComment.http │ │ │ └── ClubBoardLike.http │ │ └── role │ │ │ └── Role.http │ ├── common │ │ └── temp-upload.http │ ├── http-client.env.json │ ├── region │ │ └── region.http │ └── user │ │ └── user.http └── sql │ └── ddl.sql ├── docs └── asciidoc │ ├── club │ ├── addClub.adoc │ ├── addClubUser.adoc │ ├── album │ │ ├── club-album-comment-edit.adoc │ │ ├── club-album-comment-register.adoc │ │ ├── club-album-comment-remove.adoc │ │ ├── club-album-comment-select-sub.adoc │ │ ├── club-album-comment-select.adoc │ │ ├── club-album-edit.adoc │ │ ├── club-album-like-register.adoc │ │ ├── club-album-like-remove.adoc │ │ ├── club-album-register.adoc │ │ ├── club-album-remove.adoc │ │ ├── club-album-select-single.adoc │ │ └── club-album-select.adoc │ ├── board │ │ ├── club-board-comment-edit.adoc │ │ ├── club-board-comment-register.adoc │ │ ├── club-board-comment-remove.adoc │ │ ├── club-board-comment-select-sub.adoc │ │ ├── club-board-comment-select.adoc │ │ ├── club-board-delete.adoc │ │ ├── club-board-edit.adoc │ │ ├── club-board-like-register.adoc │ │ ├── club-board-like-remove.adoc │ │ ├── club-board-register.adoc │ │ ├── club-board-select-list.adoc │ │ └── club-board-select.adoc │ ├── changeClubInterests.adoc │ ├── changeClubRegions.adoc │ ├── changeClubUserRole.adoc │ ├── delete.adoc │ ├── getMyClubUserInfo.adoc │ ├── kick.adoc │ ├── meeting │ │ ├── create-meeting.adoc │ │ ├── delete-meeting.adoc │ │ ├── get-meeting-application-status.adoc │ │ ├── get-meeting-application.adoc │ │ ├── meeting-all.adoc │ │ ├── meeting-application-cancel.adoc │ │ ├── meeting-application.adoc │ │ ├── meeting-one.adoc │ │ └── modify-meeting.adoc │ ├── modify.adoc │ ├── myClubList.adoc │ ├── searchClub.adoc │ ├── selectClubInfoDetails.adoc │ └── withdraw.adoc │ ├── common │ ├── error.adoc │ ├── temp-file-upload.adoc │ └── temp-image-upload.adoc │ ├── docinfo-footer.html │ ├── docinfo.html │ ├── index.adoc │ ├── interest │ ├── changeUserInterest.adoc │ ├── interest-group-all.adoc │ └── userInterest.adoc │ ├── region │ ├── region-all.adoc │ └── userRegions.adoc │ └── user │ ├── changeUserRegions.adoc │ ├── kakaoUserProfileInfo.adoc │ ├── saveKakaoToken.adoc │ ├── user-change.adoc │ ├── user-check-register.adoc │ ├── userInfo.adoc │ ├── userRegist.adoc │ └── userWithdraw.adoc ├── main ├── kotlin │ └── com │ │ └── taskforce │ │ └── superinvention │ │ ├── SuperinventionApplication.kt │ │ ├── app │ │ ├── domain │ │ │ ├── BaseEntity.kt │ │ │ ├── club │ │ │ │ ├── Club.kt │ │ │ │ ├── ClubRepository.kt │ │ │ │ ├── ClubService.kt │ │ │ │ ├── album │ │ │ │ │ ├── ClubAlbum.kt │ │ │ │ │ ├── ClubAlbumRepository.kt │ │ │ │ │ ├── ClubAlbumService.kt │ │ │ │ │ ├── comment │ │ │ │ │ │ ├── ClubAlbumComment.kt │ │ │ │ │ │ ├── ClubAlbumCommentCTE.kt │ │ │ │ │ │ ├── ClubAlbumCommentRepository.kt │ │ │ │ │ │ └── ClubAlbumCommentService.kt │ │ │ │ │ ├── image │ │ │ │ │ │ └── ClubAlbumImageService.kt │ │ │ │ │ └── like │ │ │ │ │ │ ├── ClubAlbumLike.kt │ │ │ │ │ │ ├── ClubAlbumLikeRepository.kt │ │ │ │ │ │ └── ClubAlbumLikeService.kt │ │ │ │ ├── board │ │ │ │ │ ├── ClubBoard.kt │ │ │ │ │ ├── ClubBoardRepository.kt │ │ │ │ │ ├── ClubBoardService.kt │ │ │ │ │ ├── comment │ │ │ │ │ │ ├── ClubBoardComment.kt │ │ │ │ │ │ ├── ClubBoardCommentCTE.kt │ │ │ │ │ │ ├── ClubBoardCommentRepository.kt │ │ │ │ │ │ └── ClubBoardCommentService.kt │ │ │ │ │ ├── img │ │ │ │ │ │ ├── ClubBoardImg.kt │ │ │ │ │ │ ├── ClubBoardImgRepository.kt │ │ │ │ │ │ └── ClubBoardImgService.kt │ │ │ │ │ └── like │ │ │ │ │ │ ├── ClubBoardLike.kt │ │ │ │ │ │ ├── ClubBoardLikeRepository.kt │ │ │ │ │ │ └── ClubBoardLikeService.kt │ │ │ │ └── user │ │ │ │ │ ├── ClubUser.kt │ │ │ │ │ ├── ClubUserRepository.kt │ │ │ │ │ └── ClubUserService.kt │ │ │ ├── common │ │ │ │ ├── FileService.kt │ │ │ │ └── image │ │ │ │ │ ├── ImageFormat.kt │ │ │ │ │ ├── ImageService.kt │ │ │ │ │ ├── resize │ │ │ │ │ ├── ImageResizeService.kt │ │ │ │ │ └── strategy │ │ │ │ │ │ ├── GifResizeStrategy.kt │ │ │ │ │ │ ├── ImageResizeStrategy.kt │ │ │ │ │ │ ├── ImageResizeStrategyLocator.kt │ │ │ │ │ │ ├── JpgResizeStrategy.kt │ │ │ │ │ │ ├── PngResizeStrategy.kt │ │ │ │ │ │ └── WebpResizeStrategy.kt │ │ │ │ │ └── webp │ │ │ │ │ └── convert │ │ │ │ │ ├── WebpCompressionParam.kt │ │ │ │ │ ├── WebpConvertService.kt │ │ │ │ │ ├── handler │ │ │ │ │ ├── Gif2WebpHandler.kt │ │ │ │ │ ├── WebpAnimatedWriter.kt │ │ │ │ │ └── WebpHandler.kt │ │ │ │ │ └── strategy │ │ │ │ │ ├── Gif2WebpStrategy.kt │ │ │ │ │ ├── Jpg2WebpStrategy.kt │ │ │ │ │ ├── Png2WebpStrategy.kt │ │ │ │ │ ├── WebpConvertStrategy.kt │ │ │ │ │ └── WebpConvertStrategyLocator.kt │ │ │ ├── interest │ │ │ │ ├── ClubInterest.kt │ │ │ │ ├── ClubInterestRepository.kt │ │ │ │ ├── interest │ │ │ │ │ ├── Interest.kt │ │ │ │ │ ├── InterestDto.kt │ │ │ │ │ ├── InterestRepository.kt │ │ │ │ │ ├── InterestRepositoryImpl.kt │ │ │ │ │ └── InterestService.kt │ │ │ │ └── interestGroup │ │ │ │ │ ├── InterestGroup.kt │ │ │ │ │ ├── InterestGroupDto.kt │ │ │ │ │ ├── InterestGroupRepository.kt │ │ │ │ │ ├── InterestGroupRepositoryImpl.kt │ │ │ │ │ └── InterestGroupService.kt │ │ │ ├── meeting │ │ │ │ ├── Meeting.kt │ │ │ │ ├── MeetingApplication.kt │ │ │ │ ├── MeetingApplicationRepository.kt │ │ │ │ ├── MeetingRepository.kt │ │ │ │ └── MeetingService.kt │ │ │ ├── region │ │ │ │ ├── ClubRegion.kt │ │ │ │ ├── ClubRegionRepository.kt │ │ │ │ ├── Region.kt │ │ │ │ ├── RegionRepository.kt │ │ │ │ └── RegionService.kt │ │ │ ├── role │ │ │ │ ├── ClubUserRole.kt │ │ │ │ ├── ClubUserRoleRepository.kt │ │ │ │ ├── Role.kt │ │ │ │ ├── RoleGroup.kt │ │ │ │ ├── RoleGroupRepository.kt │ │ │ │ ├── RoleGroupRepositorySupport.kt │ │ │ │ ├── RoleRepository.kt │ │ │ │ ├── RoleRepositorySupport.kt │ │ │ │ └── RoleService.kt │ │ │ └── user │ │ │ │ ├── User.kt │ │ │ │ ├── UserDetailsProvider.kt │ │ │ │ ├── UserInfoService.kt │ │ │ │ ├── UserRepository.kt │ │ │ │ ├── UserService.kt │ │ │ │ ├── UserType.kt │ │ │ │ ├── userInterest │ │ │ │ ├── UserInterest.kt │ │ │ │ ├── UserInterestRepository.kt │ │ │ │ └── UserInterestService.kt │ │ │ │ ├── userRegion │ │ │ │ ├── UserRegion.kt │ │ │ │ ├── UserRegionRepository.kt │ │ │ │ └── UserRegionService.kt │ │ │ │ └── userRole │ │ │ │ ├── UserRole.kt │ │ │ │ ├── UserRoleRepository.kt │ │ │ │ └── UserRoleService.kt │ │ └── web │ │ │ ├── common │ │ │ └── response │ │ │ │ ├── ErrorResponseDto.kt │ │ │ │ └── ResponseDto.kt │ │ │ ├── controller │ │ │ ├── CommonController.kt │ │ │ ├── InterestGroupController.kt │ │ │ ├── club │ │ │ │ ├── ClubController.kt │ │ │ │ ├── album │ │ │ │ │ ├── ClubAlbumCommentController.kt │ │ │ │ │ ├── ClubAlbumController.kt │ │ │ │ │ └── ClubAlbumLikeController.kt │ │ │ │ └── board │ │ │ │ │ ├── ClubBoardCommentController.kt │ │ │ │ │ ├── ClubBoardController.kt │ │ │ │ │ └── ClubBoardLikeController.kt │ │ │ ├── meeting │ │ │ │ ├── MeetingApplicationController.kt │ │ │ │ └── MeetingController.kt │ │ │ ├── region │ │ │ │ └── RegionController.kt │ │ │ └── user │ │ │ │ ├── UserController.kt │ │ │ │ ├── UserInterestController.kt │ │ │ │ └── UserRegionController.kt │ │ │ └── dto │ │ │ ├── club │ │ │ ├── ClubAddRequestDto.kt │ │ │ ├── ClubDto.kt │ │ │ ├── ClubSearchRequestDto.kt │ │ │ ├── ClubUsersDto.kt │ │ │ ├── album │ │ │ │ ├── ClubAlbumDto.kt │ │ │ │ ├── comment │ │ │ │ │ └── ClubAlbumCommentDto.kt │ │ │ │ └── like │ │ │ │ │ └── ClubAlbumLikeDto.kt │ │ │ └── board │ │ │ │ ├── ClubBoardDto.kt │ │ │ │ ├── comment │ │ │ │ └── ClubBoardCommentListDto.kt │ │ │ │ ├── img │ │ │ │ └── ClubBoardImgDto.kt │ │ │ │ └── like │ │ │ │ └── ClubBoardLikeDto.kt │ │ │ ├── common │ │ │ ├── PageDto.kt │ │ │ └── image │ │ │ │ └── ResizeDto.kt │ │ │ ├── interest │ │ │ ├── InterestRequestDto.kt │ │ │ ├── InterestWithPriorityDto.kt │ │ │ └── UserInterestDto.kt │ │ │ ├── kakao │ │ │ └── kakaoDto.kt │ │ │ ├── meeting │ │ │ ├── MeetingApplicationDto.kt │ │ │ └── MeetingDto.kt │ │ │ ├── region │ │ │ ├── RegionDto.kt │ │ │ ├── RegionRequestDto.kt │ │ │ ├── RegionWithPriorityDto.kt │ │ │ └── SimpleRegionDto.kt │ │ │ ├── role │ │ │ └── RoleDto.kt │ │ │ └── user │ │ │ ├── UserDto.kt │ │ │ ├── UserProfileUpdateDto.kt │ │ │ ├── UserRegionDto.kt │ │ │ └── info │ │ │ ├── UserInfoDto.kt │ │ │ ├── UserInfoInterestDto.kt │ │ │ └── UserInfoRegionDto.kt │ │ └── common │ │ ├── advice │ │ ├── AdviceDto.kt │ │ ├── GlobalAdviceController.kt │ │ └── GlobalSecurityExceptionHandler.kt │ │ ├── config │ │ ├── WebMvcConfig.kt │ │ ├── argument │ │ │ ├── converter │ │ │ │ └── ClubBoardCategoryConverter.kt │ │ │ └── resolver │ │ │ │ └── auth │ │ │ │ └── AuthorizeArgumentResolver.kt │ │ ├── async │ │ │ └── AsyncConfig.kt │ │ ├── jpa │ │ │ ├── CriteriaConfig.kt │ │ │ ├── JpaConfig.kt │ │ │ ├── QueryDslConfig.kt │ │ │ └── dialect │ │ │ │ └── CustomMysqlDialect.kt │ │ ├── security │ │ │ ├── AppToken.kt │ │ │ ├── FilterChainExceptionHandler.kt │ │ │ ├── JwtTokenFilter.kt │ │ │ ├── JwtTokenFilterConfigurer.kt │ │ │ ├── JwtTokenProvider.kt │ │ │ └── WebSecurityConfig.kt │ │ └── web │ │ │ └── resttemplate │ │ │ ├── RestTemplateConfig.kt │ │ │ └── kakao │ │ │ ├── KakaoApiResponseErrorHandler.kt │ │ │ ├── KakaoAuthResponseErrorHandler.kt │ │ │ └── KakaoRestTemplateConfig.kt │ │ ├── exception │ │ ├── BizException.kt │ │ ├── InvalidInputException.kt │ │ ├── ResourceNotFoundException.kt │ │ ├── auth │ │ │ ├── AccessTokenExpiredException.kt │ │ │ ├── InsufficientAuthException.kt │ │ │ ├── OnlyWriterCanAccessException.kt │ │ │ ├── UserNotFoundException.kt │ │ │ └── WithdrawClubUserNotAllowedException.kt │ │ ├── club │ │ │ ├── CannotJoinClubException.kt │ │ │ ├── ClubNotFoundException.kt │ │ │ ├── UserIsNotClubMemberException.kt │ │ │ ├── album │ │ │ │ ├── ClubAlbumNotFoundException.kt │ │ │ │ └── NoAuthForClubAlbumException.kt │ │ │ ├── board │ │ │ │ └── ClubBoardNotFoundException.kt │ │ │ └── meeting │ │ │ │ ├── MeetingAlreadyApplicationException.kt │ │ │ │ ├── MeetingIsClosedException.kt │ │ │ │ └── MeetingMemberOverflowException.kt │ │ └── common │ │ │ ├── ImplementationIsNotSupported.kt │ │ │ └── IsAlreadyDeletedException.kt │ │ └── util │ │ ├── aws │ │ └── s3 │ │ │ ├── AwsS3Mo.kt │ │ │ └── S3Path.kt │ │ ├── extendFun │ │ ├── LocalDateExtension.kt │ │ └── StringExtension.kt │ │ ├── file │ │ ├── FileMo.kt │ │ └── image │ │ │ └── gif │ │ │ └── GifMo.kt │ │ └── kakao │ │ └── KakaoOAuth.kt └── resources │ ├── application-dev.properties │ ├── application-prod.properties │ ├── application.properties │ ├── banner.txt │ ├── db │ ├── data-interest-group.sql │ ├── data-interest.sql │ └── data-state.sql │ ├── dist_webp_binaries │ ├── cwebp │ ├── dwebp │ └── gif2webp │ ├── logback-spring.xml │ └── webp │ ├── linux │ ├── cwebp │ ├── dwebp │ └── gif2webp │ ├── mac │ ├── cwebp │ ├── dwebp │ └── gif2webp │ └── window │ ├── cwebp │ ├── dwebp │ └── gif2webp └── test ├── kotlin └── com │ └── taskforce │ └── superinvention │ ├── app │ └── domain │ │ ├── club │ │ ├── ClubServiceTest.kt │ │ ├── album │ │ │ ├── ClubAlbumServiceTest.kt │ │ │ └── comment │ │ │ │ └── ClubAlbumCommentServiceTest.kt │ │ ├── board │ │ │ ├── ClubBoardServiceTest.kt │ │ │ ├── comment │ │ │ │ └── ClubBoardCommentServiceTest.kt │ │ │ └── like │ │ │ │ └── ClubBoardLikeServiceTest.kt │ │ └── user │ │ │ └── ClubUserServiceTest.kt │ │ ├── common │ │ └── image │ │ │ └── resize │ │ │ └── ImageResizeServiceTest.kt │ │ ├── interest │ │ ├── interest │ │ │ └── InterestRepoTest.kt │ │ └── interestGroup │ │ │ └── InterestGroupRepoTestData.kt │ │ ├── meeting │ │ └── MeetingServiceTest.kt │ │ └── user │ │ ├── UserServiceTest.kt │ │ └── userRole │ │ └── UserRoleDataTest.kt │ ├── common │ └── extendFun │ │ └── StringExtensionTest.kt │ ├── config │ ├── MokitoHelper.kt │ ├── documentation │ │ └── ApiDocumentUtil.kt │ ├── jpa │ │ ├── CriteriaConfig.kt │ │ └── JpaTestConfig.kt │ └── test │ │ ├── ApiDocumentationTest.kt │ │ ├── ApiDocumentationTestV2.kt │ │ ├── BaseTest.kt │ │ ├── DataJpaRepoTest.kt │ │ ├── IntegrationTest.kt │ │ ├── MockTest.kt │ │ ├── MockkTest.kt │ │ └── TestEnv.kt │ └── document │ ├── club │ ├── ClubDocumentation.kt │ ├── ClubInfoDocumentation.kt │ ├── album │ │ ├── ClubAlbumCommentDocumentation.kt │ │ ├── ClubAlbumDocumentation.kt │ │ └── ClubAlbumLikeDocument.kt │ └── board │ │ ├── ClubBoardCommentDocumentation.kt │ │ ├── ClubBoardDocumentation.kt │ │ └── ClubBoardLikeDocument.kt │ ├── common │ └── CommonDocumentation.kt │ ├── interest │ └── InterestGroupDocumentation.kt │ ├── meeting │ ├── MeetingApplicationDocumentation.kt │ └── MeetingDocumentation.kt │ ├── region │ └── RegionDocumentation.kt │ └── user │ └── UserDocumentation.kt └── resources └── img ├── animated.gif ├── animated.webp ├── big-animated.gif ├── large-size.jpg ├── large-size.png ├── not-animated.gif ├── not-animated.webp ├── test-large.jpg └── test.jpg /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: '[Build] Super-Invention Server' 2 | 3 | on: 4 | pull_request: 5 | branches: [ develop ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - name: Set up JDK 11 14 | uses: actions/setup-java@v1 15 | with: 16 | java-version: 11 17 | 18 | - name: Grant execute permission for gradlew 19 | run: chmod +x gradlew 20 | 21 | - name: Build with Gradle 22 | run: ./gradlew build -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | 17 | ### IntelliJ IDEA ### 18 | .idea 19 | *.iws 20 | *.iml 21 | *.ipr 22 | out/ 23 | !**/src/main/**/out/ 24 | !**/src/test/**/out/ 25 | 26 | ### NetBeans ### 27 | /nbproject/private/ 28 | /nbbuild/ 29 | /dist/ 30 | /nbdist/ 31 | /.nb-gradle/ 32 | 33 | ### VS Code ### 34 | .vscode/ 35 | 36 | ### Spring RestDocs 파일 제외 - 각자 gradle task에서 빌드해서 쓰세요## 37 | /src/main/resources/static/docs/ 38 | 39 | ### Secret .properties 파일 제외 - 프로퍼티 파일은 따로 공유! 40 | /src/main/resources/*-secret.properties -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kapt.incremental.apt=true 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /infra/README.md: -------------------------------------------------------------------------------- 1 | ### [임시 인프라 파일] 2 | 3 | 현재 임시로 EC2 인스턴스에 도커 이미지로 모든 인프라가 올라가있습니다. 4 | 인프라에 문제가 생길 경우 이곳 환경을 참고하면됩니다. 5 | 6 | - t2.micro 7 | - mysql : DB 8 | - nginx : 리버스 프록시용 ( /api - > 서버로 ) 9 | 10 | 11 | - script 12 | ~/app/scripts 폴더 내에 위치해있으며, 서버 가동, 정지 등의 스크립트를 담고 있습니다. -------------------------------------------------------------------------------- /infra/infra/.env: -------------------------------------------------------------------------------- 1 | PINPOINT_VERSION=2.2.1 2 | AGENT_ID=super-invention-server 3 | APP_NAME=super-invention-server -------------------------------------------------------------------------------- /infra/infra/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | super-invention-server: 4 | image: sightstudio/superinvention 5 | ports: 6 | - '8080:8080' 7 | environment: 8 | spring_datasource_url: $spring_datasource_url 9 | spring_datasource_username: $spring_datasource_username 10 | spring_datasource_password: $spring_datasource_password 11 | oauth_kakao_client_id: $oauth_kakao_client_id 12 | aws_s3_accessKey: $aws_s3_accessKey 13 | aws_s3_secretAccessKey: $aws_s3_secretAccessKey 14 | host_static_path: $host_static_path 15 | jwt_token_secret_key: $jwt_token_secret_key 16 | aws_s3_endpointUrl: $aws_s3_endpointUrl 17 | JAVA_OPTS: "-javaagent:/pinpoint-agent/pinpoint-bootstrap-${PINPOINT_VERSION}.jar -Dpinpoint.agentId=${AGENT_ID} -Dpinpoint.applicationName=${APP_NAME}" 18 | volumes: 19 | - data-volume:/pinpoint-agent 20 | networks: 21 | - super-invention 22 | 23 | volumes: 24 | data-volume: 25 | external: true 26 | 27 | networks: 28 | super-invention: 29 | driver: bridge 30 | external: true 31 | -------------------------------------------------------------------------------- /infra/infra/mysql/conf/docker-mysql.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | default-time-zone='+9:00' 3 | max_allowed_packet=500M 4 | -------------------------------------------------------------------------------- /infra/script/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sh ./shutdown.sh 3 | 4 | rm -f ./app.jar 5 | 6 | mv ./temp/app.jar ./app.jar 7 | 8 | sh ./startup.sh 9 | 10 | rm -f ./temp/app.jar -------------------------------------------------------------------------------- /infra/script/shutdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | port=8080 3 | while getopts p:f:j:n opt 4 | do 5 | case $opt in 6 | p) 7 | port=$OPTARG 8 | ;; 9 | *) 10 | help 11 | exit 0 12 | ;; 13 | esac 14 | done 15 | 16 | SERVER_PID=$(lsof -i TCP:"$port" | awk 'NR == 2 {print $2}'); 17 | 18 | if [ -z "$SERVER_PID" ]; then 19 | echo "[info] No running PID detected" 20 | else 21 | echo "kill -15 $CURRENT_PID" 22 | kill -15 "$SERVER_PID" 23 | echo "[info] Spring Boot Project Shutdown Success" 24 | fi -------------------------------------------------------------------------------- /infra/script/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | help() { 3 | echo " 4 | [help] CLI 파라미터 5 | -p <포트번호> 6 | -f <스프링 프로파일> 7 | -j <실행할 jar 파일> 8 | -n <앱 이름> 9 | " 10 | } 11 | 12 | profile="dev" # Spring Profile 디폴트 13 | port=8080 # Spring 기본 포트 14 | runnableJarName="app.jar" # 실행할 jar 파일 15 | appName="Super Invertion Server" 16 | 17 | while getopts p:f:j:n opt 18 | do 19 | case $opt in 20 | n) 21 | appName=$OPTARG 22 | ;; 23 | p) 24 | port=$OPTARG 25 | ;; 26 | f) 27 | profile=$OPTARG 28 | ;; 29 | j) 30 | runnableJarName=$OPTARG 31 | ;; 32 | *) 33 | help 34 | exit 0 35 | ;; 36 | esac 37 | done 38 | 39 | nohup java -jar "$runnableJarName" \ 40 | -Dserver.port="$port" \ 41 | -Dspring.profiles.active="$profile" & 42 | 43 | if [ "$?" = "0" ]; then 44 | echo "($appName) Run Successfully" 45 | else 46 | echo "($appName) Run Fail" 47 | fi; 48 | 49 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "superinvention" 2 | -------------------------------------------------------------------------------- /src/course/rest/asset/large-size.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/course/rest/asset/large-size.jpg -------------------------------------------------------------------------------- /src/course/rest/asset/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/course/rest/asset/test.jpg -------------------------------------------------------------------------------- /src/course/rest/club/Club.http: -------------------------------------------------------------------------------- 1 | ### [로컬] 내 클럽 조회 2 | GET http://localhost:8080/clubs/search 3 | Content-Type: application/json;charset=UTF-8 4 | Accept: application/json 5 | Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIxNDUxMDAxNjQ5Iiwic3ViIjoiMTQ1MTAwMTY0OSIsImlhdCI6MTYxODc0MzEzOSwiZXhwIjoxNjE5MzQ3OTM5fQ.9i64zN1FJIGB8NF-goqeDBtvSGDoKF566eB_w3O6xAw 6 | 7 | ### [개발] 내 클럽 조회 8 | GET {{host}}/clubs/my 9 | Content-Type: application/json;charset=UTF-8 10 | Accept: application/json 11 | Authorization: Bearer {{token-dong}} 12 | 13 | 14 | ### [개발] 클럽 가입 15 | POST {{host}} /clubs/6212/users 16 | Accept: application/json 17 | Authorization: Bearer {{token-dong}} 18 | 19 | 20 | ### 모임 삭제 21 | DELETE {{host}}/clubs/6386 22 | Content-Type: application/json;charset=UTF-8 23 | Accept: application/json 24 | Authorization: Bearer {{token-jun}} 25 | 26 | ### 모임 수정 27 | PUT {{host}}/clubs/6164 28 | Content-Type: application/json;charset=UTF-8 29 | Accept: application/json 30 | Authorization: Bearer {{token-jun}} 31 | 32 | { 33 | "name": "제목을 이렇게 바꿔보자", 34 | "description": "설명을 이렇게 바꿔보자", 35 | "maximumNumber": 55, 36 | "mainImageUrl": null, 37 | "interestList": 38 | [ 39 | { 40 | "seq": 10, 41 | "priority": 1 42 | } 43 | ], 44 | "regionList": 45 | [ 46 | { 47 | "seq": 120, 48 | "priority": 1 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /src/course/rest/club/ClubInfo.http: -------------------------------------------------------------------------------- 1 | ### [로컬] 모임 상세 조회 - 클럽 미가입 && 로그인 상태 2 | GET {{host}}/clubs/6164 3 | Content-Type: application/json;charset=UTF-8 4 | Accept: application/json 5 | Authorization: Bearer {{token-sdm}} 6 | 7 | ### [로컬] 모임 상세 조회 - 클럽 가입 && 로그인 상태 8 | GET {{host}}/clubs/8936 9 | Content-Type: application/json;charset=UTF-8 10 | Accept: application/json 11 | Authorization: Bearer {{token-sdm}} 12 | 13 | ### [로컬] 클럽 상세 정보 조회 - 비로그인 상태 14 | GET {{host}}/clubs/6174 15 | Content-Type: application/json;charset=UTF-8 16 | Accept: application/json 17 | 18 | ### 모임 관심사 그룹으로 검색 19 | GET {{host}}/clubs/search?regionSeq=501 20 | Content-Type: application/json;charset=UTF-8 21 | Accept: application/json 22 | Authorization: Bearer {{token-jun}} 23 | 24 | ### 모임 그룹으로 검색 25 | GET {{host}}/clubs/search?size=20&page=0 26 | Content-Type: application/json;charset=UTF-8 27 | Accept: application/json 28 | Authorization: Bearer {{token-sdm}} -------------------------------------------------------------------------------- /src/course/rest/club/album/ClubAlbum.http: -------------------------------------------------------------------------------- 1 | ### 모임 사진첩 등록 2 | POST {{host}}/club/6327/album 3 | Content-Type: application/json;charset=UTF-8 4 | Accept: application/json 5 | Authorization: Bearer {{token-sdm}} 6 | 7 | { 8 | "title": "1234", 9 | "image": { 10 | "absolutePath": "https://super-invention-static.s3.ap-northeast-2.amazonaws.com/temp/img/20210413125934-3b9266dc-b87b-46ed-9244-84ec9eb87508-test-img.jpg", 11 | "filePath": "temp/img/20210413125934-3b9266dc-b87b-46ed-9244-84ec9eb87508-test-img.jpg", 12 | "fileName": "20210413125934-3b9266dc-b87b-46ed-9244-84ec9eb87508-test-img.jpg" 13 | } 14 | } 15 | 16 | ### 모임 사진첩 수정 17 | PUT {{host}}/club/6327/album/9078 18 | Content-Type: application/json;charset=UTF-8 19 | Accept: application/json 20 | Authorization: Bearer {{token-sdm}} 21 | 22 | { 23 | "title": "12342222", 24 | "image": { 25 | "absolutePath": "https://super-invention-static.s3.ap-northeast-2.amazonaws.com/temp/img/20210413011914-11e7686f-3e7f-4107-b0c5-960a5e1600dc-large-sizessssss.jpg", 26 | "filePath": "temp/img/20210413011914-11e7686f-3e7f-4107-b0c5-960a5e1600dc-large-sizessssss.jpg", 27 | "fileName": "20210413011914-11e7686f-3e7f-4107-b0c5-960a5e1600dc-large-sizessssss.jpg" 28 | } 29 | } 30 | 31 | ### 모임 사진첩 사진첩 조회 32 | GET {{host}}/club/6327/album?title=2 33 | Content-Type: application/json;charset=UTF-8 34 | Accept: application/json 35 | Authorization: Bearer {{token-sdm}} 36 | 37 | ### 모임 사진첩 단일 조회 38 | GET {{host}}/club/6327/album/9068 39 | Content-Type: application/json;charset=UTF-8 40 | Accept: application/json 41 | Authorization: Bearer {{token-sdm}} 42 | -------------------------------------------------------------------------------- /src/course/rest/club/album/ClubAlbumComment.http: -------------------------------------------------------------------------------- 1 | ### 내 클럽 사진첩 댓글 조회 2 | GET {{host}}/club/6174/album/9108/comment 3 | Content-Type: application/json;charset=UTF-8 4 | Accept: application/json 5 | Authorization: Bearer {{token-sdm}} 6 | 7 | ### 내 모임 사진첩 댓글 등록 - 루트 8 | POST {{host}}/club/9000/album/9120/comment 9 | Content-Type: application/json;charset=UTF-8 10 | Accept: application/json 11 | Authorization: Bearer {{token-sdm}} 12 | 13 | { 14 | "content" : "테스트 댓글" 15 | } 16 | 17 | ### 내 모임 사진첩 대댓글 조회 18 | GET {{host}}/club/9000/album/9120/comment/12083?depthLimit=2 19 | Content-Type: application/json;charset=UTF-8 20 | Accept: application/json 21 | Authorization: Bearer {{token-sdm}} 22 | 23 | ### 내 모임 사진첩 대댓글 등록 24 | POST {{host}}/club/6174/album/6943/comment?parentCommentSeq=6887 25 | Content-Type: application/json;charset=UTF-8 26 | Accept: application/json 27 | Authorization: Bearer {{token-sdm}} 28 | 29 | { 30 | "content" : "테스트 대댓글" 31 | } 32 | 33 | ### 댓글 삭제 34 | DELETE {{host}}/club/9000/album/9120/comment/12083 35 | Content-Type: application/json;charset=UTF-8 36 | Authorization: Bearer {{token-sdm}} 37 | -------------------------------------------------------------------------------- /src/course/rest/club/album/ClubAlbumLike.http: -------------------------------------------------------------------------------- 1 | ### 내 클럽 사진첩 좋아요 등록 2 | POST {{host}}/club/6327/album/6652/like 3 | Content-Type: application/json;charset=UTF-8 4 | Accept: application/json 5 | Authorization: Bearer {{token-sdm}} 6 | 7 | ### 내 클럽 사진첩 좋아요 등록 8 | POST {{host}}/club/6327/album/6652/like 9 | Content-Type: application/json;charset=UTF-8 10 | Accept: application/json 11 | Authorization: Bearer {{token-dong}} 12 | 13 | 14 | ### 내 클럽 사진첩 좋아요 취소 15 | DELETE {{host}}/club/6327/album/6652/like 16 | Content-Type: application/json;charset=UTF-8 17 | Accept: application/json 18 | Authorization: Bearer {{token-sdm}} 19 | 20 | ### 내 클럽 사진첩 좋아요 등록 21 | DELETE {{host}}/club/6174/album/6451/like 22 | Content-Type: application/json;charset=UTF-8 23 | Accept: application/json 24 | Authorization: Bearer {{token-sdm}} -------------------------------------------------------------------------------- /src/course/rest/club/board/ClubBoardComment.http: -------------------------------------------------------------------------------- 1 | ### 내 모임 게시글 댓글 조회 2 | GET {{host}}/club/6174/board/7/comment 3 | Content-Type: application/json;charset=UTF-8 4 | Accept: application/json 5 | Authorization: Bearer {{token-dong}} 6 | 7 | ### 내 모임 게시글 댓글 등록 8 | POST {{host}}/club/6327/board/7/comment 9 | Content-Type: application/json;charset=UTF-8 10 | Accept: application/json 11 | Authorization: Bearer {{token-sdm}} 12 | 13 | { 14 | "content" : "테스트 댓글" 15 | } 16 | 17 | ### 내 모임 게시글 대댓글 등록 18 | POST {{host}}/club/6327/board/7/comment?parentCommentSeq=36 19 | Content-Type: application/json;charset=UTF-8 20 | Accept: application/json 21 | Authorization: Bearer {{token-sdm}} 22 | 23 | { 24 | "content" : "테스트 댓글" 25 | } 26 | 27 | ### 내 모임 게시글 댓글 조회 28 | GET {{host}}/club/6174/board/7/comment?page=0&size=20 29 | Content-Type: application/json;charset=UTF-8 30 | Accept: application/json 31 | Authorization: Bearer {{token-sdm}} 32 | 33 | ### 내 모임 게시글 대댓글 조회 34 | GET {{host}}/club/6174/board/7/comment/36 35 | Content-Type: application/json;charset=UTF-8 36 | Accept: application/json 37 | Authorization: Bearer {{token-sdm}} 38 | 39 | ### 내 모임 게시글 댓글 삭제 40 | DELETE {{host}}/club/6212/board/60/comment/107 41 | Content-Type: application/json;charset=UTF-8 42 | Accept: application/json 43 | Authorization: Bearer {{token-sdm}} 44 | -------------------------------------------------------------------------------- /src/course/rest/club/board/ClubBoardLike.http: -------------------------------------------------------------------------------- 1 | ### 내 모임 게시글 좋아요 등록 2 | POST {{host}}/club/6174/board/2/like 3 | Content-Type: application/json;charset=UTF-8 4 | Accept: application/json 5 | Authorization: Bearer {{token-sdm}} 6 | 7 | ### 내 모임 게시글 좋아요 취소 8 | DELETE {{host}}/club/6174/board/2/like 9 | Content-Type: application/json;charset=UTF-8 10 | Accept: application/json 11 | Authorization: Bearer {{token-sdm}} -------------------------------------------------------------------------------- /src/course/rest/club/role/Role.http: -------------------------------------------------------------------------------- 1 | ### 내 클럽 조회 2 | GET {{host}}/clubs/my 3 | Content-Type: application/json;charset=UTF-8 4 | Accept: application/json 5 | Authorization: Bearer {{token-sdm}} 6 | 7 | ### 모임 매니저 조회 8 | GET {{host}}/clubs/6164/roles/managers 9 | Content-Type: application/json;charset=UTF-8 10 | Accept: application/json 11 | Authorization: Bearer {{token-sdm}} 12 | -------------------------------------------------------------------------------- /src/course/rest/common/temp-upload.http: -------------------------------------------------------------------------------- 1 | ### 파일 임시저장 2 | POST {{host}}/common/temp/file 3 | Content-Type: multipart/form-data; boundary=boundary 4 | Authorization: Bearer {{token-sdm}} 5 | 6 | --boundary 7 | Content-Disposition: form-data; name="file"; filename="large-sizessssss.jpg" 8 | 9 | < ../asset/large-size.jpg 10 | 11 | ### 이미지 임시저장 12 | POST {{host}}/common/temp/image?width=200&height=100 13 | Content-Type: multipart/form-data; boundary=boundary 14 | Authorization: Bearer {{token-sdm}} 15 | 16 | --boundary 17 | Content-Disposition: form-data; name="file"; filename="test-img.jpg" 18 | 19 | < ../asset/test.jpg 20 | -------------------------------------------------------------------------------- /src/course/rest/http-client.env.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": { 3 | "host": "mannal.ga/api", 4 | "token-sdm" : "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIxNDM5NTI4NTk3Iiwic3ViIjoiMTQzOTUyODU5NyIsImlhdCI6MTYxNzI1MjE5MSwiZXhwIjoxNjQ4Nzg4MTkxfQ.mCDTjD_3dQqTyaM3OggRHGD7eY3Vv6Ud6JpfD7qlf2E", 5 | "token-jun" : "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIxNDUxMDAxNjQ5Iiwic3ViIjoiMTQ1MTAwMTY0OSIsImlhdCI6MTU5OTI4MzIxOCwiZXhwIjoxNjMwODE5MjE4fQ.v-sfReNKli476qoHc1F2yoak-n4bh_D2Db5rczwS3Bs", 6 | "token-dong": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIxNDEyMzc1MzA5Iiwic3ViIjoiMTQxMjM3NTMwOSIsImlhdCI6MTYwMDQ0MDc4OSwiZXhwIjoxNjMxOTc2Nzg5fQ.csOA38Zh0dL1OtG0AKqRudY4E8FQMg3gVC80h7XuPsY", 7 | "token-tester": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiI2MTIiLCJzdWIiOiI2MTIiLCJpYXQiOjE2MTY1MDU1OTksImV4cCI6MTY0ODA0MTU5OX0.GIABJSsYJDZq54GO-zX681DnmYrX54q-2brt_5C9yvY" 8 | }, 9 | 10 | "local": { 11 | "host": "http://localhost:8080", 12 | "token-sdm" : "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIxNDM5NTI4NTk3Iiwic3ViIjoiMTQzOTUyODU5NyIsImlhdCI6MTYxNzI1MjE5MSwiZXhwIjoxNjQ4Nzg4MTkxfQ.mCDTjD_3dQqTyaM3OggRHGD7eY3Vv6Ud6JpfD7qlf2E", 13 | "token-jun" : "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIxNDUxMDAxNjQ5Iiwic3ViIjoiMTQ1MTAwMTY0OSIsImlhdCI6MTYxNzgwNzg1NiwiZXhwIjoxNjE3ODA4NzU2fQ.4QgMeul4HmsfXpq3I3B2lDZXGNLgT62ubVSw6Zkg2iA", 14 | "token-dong": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIxNDEyMzc1MzA5Iiwic3ViIjoiMTQxMjM3NTMwOSIsImlhdCI6MTYwMDQ0MDc4OSwiZXhwIjoxNjMxOTc2Nzg5fQ.csOA38Zh0dL1OtG0AKqRudY4E8FQMg3gVC80h7XuPsY", 15 | "token-tester": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiI2MTIiLCJzdWIiOiI2MTIiLCJpYXQiOjE2MTY1MDU1OTksImV4cCI6MTY0ODA0MTU5OX0.GIABJSsYJDZq54GO-zX681DnmYrX54q-2brt_5C9yvY" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/course/rest/region/region.http: -------------------------------------------------------------------------------- 1 | ### [로컬] 2 | GET {{host}} /regions 3 | Content-Type: application/json;charset=UTF-8 4 | Accept: application/json 5 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/addClub.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/addClub/http-request.adoc[] 14 | 15 | include::{sub-snippet}/addClub/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/addClub/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/addClub/http-response.adoc[] 21 | 22 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/addClubUser.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/addClubUser/http-request.adoc[] 14 | 15 | include::{sub-snippet}/addClubUser/path-parameters.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/addClubUser/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/addClubUser/http-response.adoc[] 21 | 22 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-comment-edit.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-comment-edit/http-request.adoc[] 14 | include::{sub-snippet}/club-album-comment-edit/path-parameters.adoc[] 15 | include::{sub-snippet}/club-album-comment-edit/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/club-album-comment-edit/response-fields.adoc[] 19 | include::{sub-snippet}/club-album-comment-edit/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-comment-register.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-comment-register/http-request.adoc[] 14 | include::{sub-snippet}/club-album-comment-register/request-parameters.adoc[] 15 | include::{sub-snippet}/club-album-comment-register/path-parameters.adoc[] 16 | include::{sub-snippet}/club-album-comment-register/request-fields.adoc[] 17 | 18 | Response 19 | include::{sub-snippet}/club-album-comment-register/response-fields.adoc[] 20 | include::{sub-snippet}/club-album-comment-register/http-response.adoc[] 21 | 22 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-comment-remove.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-comment-remove/http-request.adoc[] 14 | include::{sub-snippet}/club-album-comment-remove/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-album-comment-remove/response-fields.adoc[] 18 | 19 | include::{sub-snippet}/club-album-comment-remove/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-comment-select-sub.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-comment-select-sub/http-request.adoc[] 14 | include::{sub-snippet}/club-album-comment-select-sub/path-parameters.adoc[] 15 | include::{sub-snippet}/club-album-comment-select-sub/request-parameters.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/club-album-comment-select-sub/response-fields.adoc[] 19 | include::{sub-snippet}/club-album-comment-select-sub/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-comment-select.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-comment-select/http-request.adoc[] 14 | include::{sub-snippet}/club-album-comment-select/path-parameters.adoc[] 15 | include::{sub-snippet}/club-album-comment-select/request-parameters.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/club-album-comment-select/response-fields.adoc[] 19 | include::{sub-snippet}/club-album-comment-select/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-edit.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-edit/http-request.adoc[] 14 | 15 | include::{sub-snippet}/club-album-edit/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/club-album-edit/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/club-album-edit/http-response.adoc[] 21 | 22 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-like-register.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-like-register/http-request.adoc[] 14 | include::{sub-snippet}/club-album-like-register/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-album-like-register/response-fields.adoc[] 18 | include::{sub-snippet}/club-album-like-register/http-response.adoc[] 19 | 20 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-like-remove.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-like-remove/http-request.adoc[] 14 | include::{sub-snippet}/club-album-like-remove/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-album-like-remove/response-fields.adoc[] 18 | include::{sub-snippet}/club-album-like-remove/http-response.adoc[] 19 | 20 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-register.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-register/http-request.adoc[] 14 | 15 | include::{sub-snippet}/club-album-register/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/club-album-register/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/club-album-register/http-response.adoc[] 21 | 22 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-remove.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-remove/http-request.adoc[] 14 | include::{sub-snippet}/club-album-remove/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-album-remove/response-fields.adoc[] 18 | 19 | include::{sub-snippet}/club-album-remove/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-select-single.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-select-single/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/club-album-select-single/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/club-album-select-single/http-response.adoc[] 19 | 20 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/album/club-album-select.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-select/http-request.adoc[] 14 | include::{sub-snippet}/club-album-select/request-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-album-select/response-fields.adoc[] 18 | 19 | include::{sub-snippet}/club-album-select/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-comment-edit.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-board-comment-edit/http-request.adoc[] 14 | include::{sub-snippet}/club-board-comment-edit/path-parameters.adoc[] 15 | include::{sub-snippet}/club-board-comment-edit/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/club-board-comment-edit/response-fields.adoc[] 19 | include::{sub-snippet}/club-board-comment-edit/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-comment-register.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-board-comment-register/http-request.adoc[] 14 | include::{sub-snippet}/club-board-comment-register/request-parameters.adoc[] 15 | include::{sub-snippet}/club-board-comment-register/path-parameters.adoc[] 16 | include::{sub-snippet}/club-board-comment-register/request-fields.adoc[] 17 | 18 | Response 19 | include::{sub-snippet}/club-board-comment-register/response-fields.adoc[] 20 | include::{sub-snippet}/club-board-comment-register/http-response.adoc[] 21 | 22 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-comment-remove.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-board-comment-remove/http-request.adoc[] 14 | include::{sub-snippet}/club-board-comment-remove/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-board-comment-remove/response-fields.adoc[] 18 | 19 | include::{sub-snippet}/club-board-comment-remove/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-comment-select-sub.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-board-comment-select-sub/http-request.adoc[] 14 | include::{sub-snippet}/club-board-comment-select-sub/path-parameters.adoc[] 15 | include::{sub-snippet}/club-board-comment-select-sub/request-parameters.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/club-board-comment-select-sub/response-fields.adoc[] 19 | include::{sub-snippet}/club-board-comment-select-sub/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-comment-select.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-board-comment-select/http-request.adoc[] 14 | include::{sub-snippet}/club-board-comment-select/path-parameters.adoc[] 15 | include::{sub-snippet}/club-board-comment-select/request-parameters.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/club-board-comment-select/response-fields.adoc[] 19 | include::{sub-snippet}/club-board-comment-select/http-response.adoc[] 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-delete.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/delete-club-board/http-request.adoc[] 14 | include::{sub-snippet}/delete-club-board/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/delete-club-board/response-fields.adoc[] 18 | include::{sub-snippet}/delete-club-board/response-body.adoc[] 19 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-edit.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/edit-club-board/http-request.adoc[] 14 | include::{sub-snippet}/edit-club-board/path-parameters.adoc[] 15 | include::{sub-snippet}/edit-club-board/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/edit-club-board/response-fields.adoc[] 19 | include::{sub-snippet}/edit-club-board/response-body.adoc[] 20 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-like-register.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-like-register/http-request.adoc[] 14 | include::{sub-snippet}/club-album-like-register/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-album-like-register/response-fields.adoc[] 18 | include::{sub-snippet}/club-album-like-register/http-response.adoc[] 19 | 20 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-like-remove.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-album-like-remove/http-request.adoc[] 14 | include::{sub-snippet}/club-album-like-remove/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-album-like-remove/response-fields.adoc[] 18 | include::{sub-snippet}/club-album-like-remove/http-response.adoc[] 19 | 20 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-register.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/register-club-board/http-request.adoc[] 14 | include::{sub-snippet}/register-club-board/request-fields.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/register-club-board/response-fields.adoc[] 18 | include::{sub-snippet}/register-club-board/response-body.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-select-list.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/select-club-board-list/http-request.adoc[] 14 | include::{sub-snippet}/select-club-board-list/request-parameters.adoc[] 15 | 16 | 17 | Response 18 | include::{sub-snippet}/select-club-board-list/response-fields.adoc[] 19 | include::{sub-snippet}/select-club-board-list/response-body.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/board/club-board-select.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/select-club-board/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/select-club-board/response-fields.adoc[] 17 | include::{sub-snippet}/select-club-board/response-body.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/changeClubInterests.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/changeClubInterests/http-request.adoc[] 14 | 15 | include::{sub-snippet}/changeClubInterests/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/changeClubInterests/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/changeClubInterests/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/changeClubRegions.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/changeClubRegions/http-request.adoc[] 14 | 15 | include::{sub-snippet}/changeClubRegions/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/changeClubRegions/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/changeClubRegions/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/changeClubUserRole.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | 13 | 14 | Request 15 | include::{sub-snippet}/changeClubUserRole/http-request.adoc[] 16 | |=== 17 | | 권한번호 | 권한코드 | 권한명 18 | 19 | | 1 20 | | NONE 21 | | 없음 (미사용) 22 | 23 | | 2 24 | | MEMBER 25 | | 회원 (모임 미가입) 26 | 27 | | 3 28 | | CLUB_MEMBER 29 | | 모임원 30 | 31 | | 4 32 | | MANAGER 33 | | 매니저 34 | 35 | | 5 36 | | MASTER 37 | | 모임장 38 | |=== 39 | 40 | Response 41 | include::{sub-snippet}/changeClubUserRole/response-fields.adoc[] 42 | 43 | include::{sub-snippet}/changeClubUserRole/http-response.adoc[] 44 | 45 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/delete.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-delete/http-request.adoc[] 14 | include::{sub-snippet}/club-delete/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-delete/http-response.adoc[] 18 | include::{sub-snippet}/club-delete/response-fields.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/getMyClubUserInfo.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/getMyClubUserInfo/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/getMyClubUserInfo/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/getMyClubUserInfo/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/kick.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-kick/http-request.adoc[] 14 | include::{sub-snippet}/club-kick/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-kick/http-response.adoc[] 18 | include::{sub-snippet}/club-kick/response-fields.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/meeting/create-meeting.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/create-meeting/http-request.adoc[] 14 | 15 | include::{sub-snippet}/create-meeting/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/create-meeting/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/create-meeting/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/meeting/delete-meeting.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/delete-meeting/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/delete-meeting/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/delete-meeting/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/meeting/get-meeting-application-status.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/get-meeting-application-status/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/get-meeting-application-status/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/get-meeting-application-status/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/meeting/get-meeting-application.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/get-meeting-application/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/get-meeting-application/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/get-meeting-application/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/meeting/meeting-all.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | ifndef::snippets[] 5 | :sub-snippet: ../../../../../build/generated-snippets 6 | endif::[] 7 | :doctype: book 8 | :icons: font 9 | :source-highlighter: highlightjs 10 | :toc: left 11 | :toclevels: 4 12 | :sectlinks: 13 | :site-url: /build/asciidoc/html5/state 14 | 15 | Request 16 | include::{sub-snippet}/meeting-all/http-request.adoc[] 17 | 18 | Response 19 | include::{sub-snippet}/meeting-all/response-fields.adoc[] 20 | 21 | include::{sub-snippet}/meeting-all/http-response.adoc[] 22 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/meeting/meeting-application-cancel.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/meeting-application-cancel/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/meeting-application-cancel/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/meeting-application-cancel/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/meeting/meeting-application.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/meeting-application/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/meeting-application/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/meeting-application/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/meeting/meeting-one.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | ifndef::snippets[] 5 | :sub-snippet: ../../../../../build/generated-snippets 6 | endif::[] 7 | :doctype: book 8 | :icons: font 9 | :source-highlighter: highlightjs 10 | :toc: left 11 | :toclevels: 4 12 | :sectlinks: 13 | :site-url: /build/asciidoc/html5/state 14 | 15 | Request 16 | include::{sub-snippet}/meeting-one/http-request.adoc[] 17 | 18 | Response 19 | include::{sub-snippet}/meeting-one/response-fields.adoc[] 20 | 21 | include::{sub-snippet}/meeting-one/http-response.adoc[] 22 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/meeting/modify-meeting.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/modify-meeting/http-request.adoc[] 14 | 15 | include::{sub-snippet}/modify-meeting/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/modify-meeting/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/modify-meeting/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/modify.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-modify/http-request.adoc[] 14 | include::{sub-snippet}/club-modify/path-parameters.adoc[] 15 | include::{sub-snippet}/club-modify/request-body.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/club-modify/http-response.adoc[] 19 | include::{sub-snippet}/club-modify/response-fields.adoc[] 20 | -------------------------------------------------------------------------------- /src/docs/asciidoc/club/myClubList.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/myClubList/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/myClubList/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/myClubList/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/searchClub.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/searchClub/http-request.adoc[] 14 | 15 | include::{sub-snippet}/searchClub/request-parameters.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/searchClub/http-response.adoc[] 19 | 20 | include::{sub-snippet}/searchClub/response-fields.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/selectClubInfoDetails.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/select-club-info-detail/http-request.adoc[] 14 | include::{sub-snippet}/select-club-info-detail/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/select-club-info-detail/http-response.adoc[] 18 | include::{sub-snippet}/select-club-info-detail/response-fields.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/club/withdraw.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/club-withdraw/http-request.adoc[] 14 | include::{sub-snippet}/club-withdraw/path-parameters.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/club-withdraw/http-response.adoc[] 18 | include::{sub-snippet}/club-withdraw/response-fields.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/common/error.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/common 11 | 12 | Response 13 | include::{sub-snippet}/error/response-fields.adoc[] 14 | include::{sub-snippet}/error/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/common/temp-file-upload.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/common 11 | 12 | Request 13 | include::{sub-snippet}/temp-file-upload/http-request.adoc[] 14 | include::{sub-snippet}/temp-file-upload/request-parts.adoc[] 15 | 16 | Response 17 | include::{sub-snippet}/temp-file-upload/response-fields.adoc[] 18 | include::{sub-snippet}/temp-file-upload/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/common/temp-image-upload.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/common 11 | 12 | Request 13 | include::{sub-snippet}/temp-image-upload/http-request.adoc[] 14 | include::{sub-snippet}/temp-image-upload/request-parts.adoc[] 15 | include::{sub-snippet}/temp-image-upload/request-parameters.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/temp-image-upload/response-fields.adoc[] 19 | include::{sub-snippet}/temp-image-upload/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/docinfo-footer.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/docs/asciidoc/docinfo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/docs/asciidoc/interest/changeUserInterest.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/changeUserInterest/http-request.adoc[] 14 | 15 | include::{sub-snippet}/changeUserInterest/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/changeUserInterest/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/changeUserInterest/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/interest/interest-group-all.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/interest-group-all/http-request.adoc[] 14 | 15 | .... 16 | 요구 Request Header 없음 17 | .... 18 | 19 | .... 20 | 요구 Request Body 없음 21 | .... 22 | 23 | Response 24 | include::{sub-snippet}/interest-group-all/response-fields.adoc[] 25 | 26 | include::{sub-snippet}/interest-group-all/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/interest/userInterest.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/userInterest/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/userInterest/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/userInterest/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/region/region-all.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/region-all/http-request.adoc[] 14 | 15 | .... 16 | 요구 Request Header 없음 17 | .... 18 | 19 | .... 20 | 요구 Request Body 없음 21 | .... 22 | 23 | Response 24 | include::{sub-snippet}/region-all/response-fields.adoc[] 25 | 26 | include::{sub-snippet}/region-all/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/region/userRegions.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/user-states 11 | 12 | Request 13 | include::{sub-snippet}/userRegions/http-request.adoc[] 14 | 15 | .... 16 | 요구 Request Fields 없음 17 | .... 18 | 19 | Response 20 | include::{sub-snippet}/userRegions/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/user/changeUserRegions.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/changeUserRegions/http-request.adoc[] 14 | 15 | include::{sub-snippet}/changeUserRegions/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/changeUserRegions/response-fields.adoc[] 19 | 20 | include::{sub-snippet}/changeUserRegions/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/user/kakaoUserProfileInfo.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/kakaoUserProfileInfo/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/kakaoUserProfileInfo/response-fields.adoc[] 17 | 18 | include::{sub-snippet}/kakaoUserProfileInfo/http-response.adoc[] 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/docs/asciidoc/user/saveKakaoToken.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | .... 14 | 요구 Request Header 없음 15 | .... 16 | 17 | include::{sub-snippet}/saveKakaoToken/http-request.adoc[] 18 | include::{sub-snippet}/saveKakaoToken/request-fields.adoc[] 19 | 20 | Response 21 | include::{sub-snippet}/saveKakaoToken/response-fields.adoc[] 22 | include::{sub-snippet}/saveKakaoToken/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/user/user-change.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/user-change/http-request.adoc[] 14 | 15 | include::{sub-snippet}/user-change/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/user-change/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/user/user-check-register.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/user-check-register/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/user-check-register/http-response.adoc[] 17 | include::{sub-snippet}/user-check-register/response-fields.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/user/userInfo.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/user-info/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/user-info/http-response.adoc[] 17 | include::{sub-snippet}/user-info/response-fields.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/user/userRegist.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/userRegist/http-request.adoc[] 14 | 15 | include::{sub-snippet}/userRegist/request-fields.adoc[] 16 | 17 | Response 18 | include::{sub-snippet}/userRegist/http-response.adoc[] -------------------------------------------------------------------------------- /src/docs/asciidoc/user/userWithdraw.adoc: -------------------------------------------------------------------------------- 1 | ifndef::snippets[] 2 | :sub-snippet: ../../../../build/generated-snippets 3 | endif::[] 4 | :doctype: book 5 | :icons: font 6 | :source-highlighter: highlightjs 7 | :toc: left 8 | :toclevels: 4 9 | :sectlinks: 10 | :site-url: /build/asciidoc/html5/state 11 | 12 | Request 13 | include::{sub-snippet}/userWithdraw/http-request.adoc[] 14 | 15 | Response 16 | include::{sub-snippet}/userWithdraw/http-response.adoc[] -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/SuperinventionApplication.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | import org.springframework.web.servlet.config.annotation.EnableWebMvc 6 | 7 | @SpringBootApplication 8 | class SuperinventionApplication 9 | 10 | fun main(args: Array) { 11 | runApplication(*args) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/BaseEntity.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain 2 | import org.springframework.data.annotation.CreatedDate 3 | import org.springframework.data.annotation.LastModifiedDate 4 | import org.springframework.data.jpa.domain.support.AuditingEntityListener 5 | import java.time.LocalDateTime 6 | import javax.persistence.* 7 | 8 | @EntityListeners(AuditingEntityListener::class) 9 | @MappedSuperclass 10 | open class BaseEntity { 11 | 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | var seq: Long? = null 15 | 16 | @CreatedDate 17 | var createdAt: LocalDateTime? = LocalDateTime.now() 18 | 19 | @LastModifiedDate 20 | var updatedAt: LocalDateTime? = null 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/album/comment/ClubAlbumComment.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.album.comment 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.album.ClubAlbum 5 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 6 | import org.hibernate.annotations.Formula 7 | import javax.persistence.Entity 8 | import javax.persistence.FetchType 9 | import javax.persistence.JoinColumn 10 | import javax.persistence.ManyToOne 11 | 12 | @Entity 13 | class ClubAlbumComment( 14 | var content: String, 15 | 16 | @ManyToOne(fetch = FetchType.LAZY) 17 | @JoinColumn(name="club_user_seq") 18 | var clubUser: ClubUser, 19 | 20 | @ManyToOne(fetch = FetchType.LAZY) 21 | @JoinColumn(name="club_album_seq") 22 | var clubAlbum: ClubAlbum, 23 | 24 | @ManyToOne(fetch = FetchType.LAZY) 25 | @JoinColumn(name="parent_comment_seq") 26 | var parent: ClubAlbumComment?, 27 | 28 | var depth: Long, 29 | 30 | var deleteFlag: Boolean ?= false 31 | ): BaseEntity() { 32 | 33 | // 직전 하위 뎁스의 댓글 개수만 보여줌 34 | @Formula("(select count(*) from club_album_comment cac where cac.parent_comment_seq = seq and cac.depth = depth+1)") 35 | var subCommentCnt: Long ?= null 36 | 37 | // 모든 하위 뎁스의 댓글 개수만 보여줌 38 | @Formula("(select count(*) from club_album_comment cac where cac.parent_comment_seq = seq and cac.depth > depth)") 39 | var totalSubCommentCnt: Long ?= null 40 | 41 | constructor(content: String, clubUser: ClubUser, clubAlbum: ClubAlbum) :this( 42 | content = content, 43 | clubUser = clubUser, 44 | clubAlbum = clubAlbum, 45 | parent = null, 46 | depth = 1 47 | ) 48 | } 49 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/album/comment/ClubAlbumCommentCTE.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.album.comment 2 | 3 | import com.blazebit.persistence.CTE 4 | import com.taskforce.superinvention.app.domain.BaseEntity 5 | import com.taskforce.superinvention.app.domain.club.album.ClubAlbum 6 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 7 | import javax.persistence.Entity 8 | import javax.persistence.FetchType 9 | import javax.persistence.JoinColumn 10 | import javax.persistence.ManyToOne 11 | 12 | @CTE 13 | @Entity 14 | class ClubAlbumCommentCTE( 15 | var content: String, 16 | 17 | @ManyToOne(fetch = FetchType.LAZY) 18 | @JoinColumn(name="parent_comment_seq") 19 | var parent: ClubAlbumComment?, 20 | 21 | @ManyToOne(fetch = FetchType.LAZY) 22 | @JoinColumn(name="club_user_seq") 23 | var clubUser: ClubUser, 24 | 25 | @ManyToOne(fetch = FetchType.LAZY) 26 | @JoinColumn(name="club_album_seq") 27 | var clubAlbum: ClubAlbum, 28 | 29 | var depth: Long, 30 | 31 | var subCommentCnt: Long?, 32 | 33 | var deleteFlag: Boolean ?= false 34 | 35 | ): BaseEntity() 36 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/album/like/ClubAlbumLike.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.album.like 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.album.ClubAlbum 5 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 6 | import javax.persistence.* 7 | 8 | @Entity 9 | class ClubAlbumLike( 10 | 11 | @ManyToOne(fetch = FetchType.LAZY) 12 | @JoinColumn(name = "club_album_seq") 13 | val clubAlbum: ClubAlbum, 14 | 15 | @ManyToOne(fetch = FetchType.LAZY) 16 | @JoinColumn(name= "club_user_seq") 17 | val clubUser: ClubUser 18 | ): BaseEntity() -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/album/like/ClubAlbumLikeRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.album.like 2 | 3 | import com.querydsl.core.types.Predicate 4 | import com.taskforce.superinvention.app.domain.club.album.ClubAlbum 5 | import com.taskforce.superinvention.app.domain.club.album.QClubAlbum 6 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 7 | import org.springframework.data.jpa.repository.JpaRepository 8 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 9 | import org.springframework.stereotype.Repository 10 | 11 | interface ClubAlbumLikeRepository: JpaRepository, ClubAlbumLikeCustom { 12 | 13 | fun findByClubAlbumAndClubUser(clubAlbum: ClubAlbum, clubUser: ClubUser): ClubAlbumLike? 14 | fun findByClubAlbumSeqAndClubUser(clubAlbumSeq: Long, clubUser: ClubUser): ClubAlbumLike? 15 | fun findByClubAlbumIn(clubAlbumList: List): List 16 | } 17 | 18 | interface ClubAlbumLikeCustom { 19 | fun getClubAlbumLikeCnt(clubAlbum: ClubAlbum): Long 20 | } 21 | 22 | @Repository 23 | class ClubAlbumLikeRepositoryImpl: ClubAlbumLikeCustom, 24 | QuerydslRepositorySupport(ClubAlbumLike::class.java) { 25 | 26 | override fun getClubAlbumLikeCnt(clubAlbum: ClubAlbum): Long { 27 | val clubAlbumLike = QClubAlbumLike.clubAlbumLike 28 | 29 | val query = from(clubAlbumLike) 30 | .where(eqSeq(clubAlbumLike.clubAlbum, clubAlbum)) 31 | 32 | return query.fetchCount() 33 | } 34 | 35 | 36 | private fun eqSeq(clubAlbum: QClubAlbum, targetClubAlbum: ClubAlbum): Predicate { 37 | return clubAlbum.seq.eq(targetClubAlbum.seq) 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/board/comment/ClubBoardComment.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.board.comment 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 5 | import com.taskforce.superinvention.app.domain.club.board.ClubBoard 6 | import org.hibernate.annotations.Formula 7 | import javax.persistence.Entity 8 | import javax.persistence.FetchType 9 | import javax.persistence.JoinColumn 10 | import javax.persistence.ManyToOne 11 | 12 | @Entity 13 | class ClubBoardComment( 14 | var content: String, 15 | 16 | @ManyToOne( fetch = FetchType.LAZY) 17 | @JoinColumn(name = "club_user_seq") 18 | var clubUser: ClubUser, 19 | 20 | @ManyToOne( fetch = FetchType.LAZY) 21 | @JoinColumn(name = "club_board_seq") 22 | var clubBoard: ClubBoard, 23 | 24 | @ManyToOne( fetch = FetchType.LAZY) 25 | @JoinColumn(name = "parent_comment_seq") 26 | var parent: ClubBoardComment ?= null, 27 | 28 | var depth: Long, 29 | 30 | var deleteFlag: Boolean ?= false, 31 | 32 | ) : BaseEntity() { 33 | 34 | // 직전 하위 뎁스의 댓글 개수만 보여줌 35 | @Formula("(select count(*) from club_board_comment cac where cac.parent_comment_seq = seq and cac.depth = depth+1)") 36 | var subCommentCnt: Long ?= null 37 | 38 | // 모든 하위 뎁스의 댓글 개수만 보여줌 39 | @Formula("(select count(*) from club_board_comment cac where cac.parent_comment_seq = seq and cac.depth > depth)") 40 | var totalSubCommentCnt: Long ?= null 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/board/comment/ClubBoardCommentCTE.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.board.comment 2 | 3 | import com.blazebit.persistence.CTE 4 | import com.taskforce.superinvention.app.domain.BaseEntity 5 | import com.taskforce.superinvention.app.domain.club.album.ClubAlbum 6 | import com.taskforce.superinvention.app.domain.club.board.ClubBoard 7 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 8 | import javax.persistence.Entity 9 | import javax.persistence.FetchType 10 | import javax.persistence.JoinColumn 11 | import javax.persistence.ManyToOne 12 | 13 | @CTE 14 | @Entity 15 | class ClubBoardCommentCTE( 16 | 17 | var content: String, 18 | 19 | @ManyToOne(fetch = FetchType.LAZY) 20 | @JoinColumn(name="parent_comment_seq") 21 | var parent: ClubBoardComment?, 22 | 23 | @ManyToOne(fetch = FetchType.LAZY) 24 | @JoinColumn(name="club_user_seq") 25 | var clubUser: ClubUser, 26 | 27 | @ManyToOne(fetch = FetchType.LAZY) 28 | @JoinColumn(name="club_board_seq") 29 | var clubBoard: ClubBoard, 30 | 31 | var depth: Long, 32 | 33 | var subCommentCnt: Long?, 34 | 35 | var deleteFlag: Boolean ?= false, 36 | 37 | ): BaseEntity() 38 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/board/img/ClubBoardImg.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.board.img 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.board.ClubBoard 5 | import javax.persistence.Entity 6 | import javax.persistence.FetchType 7 | import javax.persistence.JoinColumn 8 | import javax.persistence.ManyToOne 9 | 10 | @Entity 11 | class ClubBoardImg( 12 | 13 | @ManyToOne( fetch = FetchType.LAZY) 14 | @JoinColumn(name = "club_board_seq") 15 | var clubBoard: ClubBoard, 16 | 17 | var imgUrl : String, 18 | 19 | var imgName: String, 20 | 21 | var displayOrder: Long?, 22 | 23 | var deleteFlag: Boolean 24 | ): BaseEntity() 25 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/board/img/ClubBoardImgRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.board.img 2 | 3 | import com.taskforce.superinvention.app.domain.club.board.ClubBoard 4 | import com.taskforce.superinvention.app.domain.club.board.comment.ClubBoardComment 5 | import com.taskforce.superinvention.app.domain.club.board.comment.ClubBoardCommentRepositoryCustom 6 | import org.springframework.data.jpa.repository.JpaRepository 7 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 8 | import org.springframework.stereotype.Repository 9 | 10 | interface ClubBoardImgRepository : JpaRepository, ClubBoardImgRepositoryCustom { 11 | fun findByClubBoard(clubBoard: ClubBoard): List 12 | fun findBySeqIn(clubBoardSeqList: List): List 13 | } 14 | 15 | interface ClubBoardImgRepositoryCustom { 16 | fun findByClubBoardOrderByOrderAsc(clubBoard: ClubBoard): List 17 | } 18 | 19 | @Repository 20 | class ClubBoardImgRepositoryImpl: ClubBoardImgRepositoryCustom, 21 | QuerydslRepositorySupport(ClubBoardImg::class.java) { 22 | 23 | override fun findByClubBoardOrderByOrderAsc(clubBoard: ClubBoard): List { 24 | val clubBoardImg = QClubBoardImg.clubBoardImg 25 | 26 | return from(clubBoardImg) 27 | .where( 28 | clubBoardImg.clubBoard.eq(clubBoard), 29 | clubBoardImg.deleteFlag.isFalse, 30 | ) 31 | .orderBy(clubBoardImg.displayOrder.asc()) 32 | .fetch() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/board/like/ClubBoardLike.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.board.like 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.board.ClubBoard 5 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 6 | import javax.persistence.* 7 | 8 | @Entity 9 | class ClubBoardLike( 10 | 11 | @ManyToOne(fetch = FetchType.LAZY) 12 | @JoinColumn(name = "club_board_seq") 13 | val clubBoard: ClubBoard, 14 | 15 | @ManyToOne(fetch = FetchType.LAZY) 16 | @JoinColumn(name= "club_user_seq") 17 | val clubUser: ClubUser 18 | 19 | ): BaseEntity() -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/board/like/ClubBoardLikeRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.board.like 2 | 3 | import com.querydsl.core.types.dsl.BooleanExpression 4 | import com.taskforce.superinvention.app.domain.club.board.ClubBoard 5 | import com.taskforce.superinvention.app.domain.club.board.QClubBoard 6 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 7 | import org.springframework.data.jpa.repository.JpaRepository 8 | import org.springframework.data.jpa.repository.Query 9 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 10 | import org.springframework.stereotype.Repository 11 | 12 | interface ClubBoardLikeRepository: JpaRepository, ClubBoardLikeRepositoryCustom { 13 | fun findByClubBoardAndClubUser(board: ClubBoard, clubUser: ClubUser): ClubBoardLike? 14 | fun findByClubBoardIn(clubBoardList: List): List 15 | } 16 | 17 | interface ClubBoardLikeRepositoryCustom { 18 | fun getClubBoardLikeCnt(clubBoard: ClubBoard): Long 19 | } 20 | 21 | @Repository 22 | class ClubBoardLikeRepositoryImpl: ClubBoardLikeRepositoryCustom, 23 | QuerydslRepositorySupport(ClubBoard::class.java){ 24 | 25 | override fun getClubBoardLikeCnt(clubBoard: ClubBoard): Long { 26 | val clubBoardLike = QClubBoardLike.clubBoardLike 27 | 28 | val query = from(clubBoardLike) 29 | .where(eqSeq(clubBoardLike.clubBoard, clubBoard)) 30 | 31 | return query.fetchCount() 32 | } 33 | 34 | private fun eqSeq(clubBoard1: QClubBoard, clubBoard2: ClubBoard): BooleanExpression 35 | = clubBoard1.seq.eq(clubBoard2.seq) 36 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/user/ClubUser.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.user 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.Club 5 | import com.taskforce.superinvention.app.domain.role.ClubUserRole 6 | import com.taskforce.superinvention.app.domain.user.User 7 | import javax.persistence.* 8 | 9 | @Entity 10 | class ClubUser( 11 | @ManyToOne(fetch = FetchType.LAZY) 12 | @JoinColumn(name = "club_seq") 13 | var club: Club, 14 | 15 | @ManyToOne(fetch = FetchType.LAZY) 16 | @JoinColumn(name = "user_seq") 17 | var user: User, 18 | 19 | var isLiked: Boolean? 20 | ) : BaseEntity() { 21 | 22 | constructor(club: Club, user: User) 23 | : this(club, user, false) 24 | 25 | @OneToMany 26 | @JoinColumn(name = "club_user_seq") 27 | lateinit var clubUserRoles: MutableSet 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/club/user/ClubUserService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.club.user 2 | 3 | import com.taskforce.superinvention.app.domain.role.Role 4 | import com.taskforce.superinvention.app.domain.user.User 5 | import com.taskforce.superinvention.app.web.dto.club.ClubUserStatusDto 6 | import com.taskforce.superinvention.common.exception.InvalidInputException 7 | import com.taskforce.superinvention.common.exception.club.UserIsNotClubMemberException 8 | import org.springframework.stereotype.Service 9 | import org.springframework.transaction.annotation.Transactional 10 | 11 | @Service 12 | class ClubUserService( 13 | private val clubUserRepository: ClubUserRepository 14 | ) { 15 | 16 | // 클럽에서의 유저 상태 표시 17 | @Transactional 18 | fun getClubUserDetails(user: User?, clubSeq: Long): ClubUserStatusDto? { 19 | if(user == null) { 20 | return null 21 | } 22 | 23 | val clubUser = clubUserRepository.findClubUserWithRole(clubSeq, user) 24 | 25 | return clubUser?.let ( ::ClubUserStatusDto ) 26 | } 27 | 28 | fun getValidClubUser(clubSeq: Long, user: User): ClubUser { 29 | return clubUserRepository.findByClubSeqAndUser(clubSeq, user) 30 | ?: throw UserIsNotClubMemberException() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/FileService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common 2 | 3 | import com.taskforce.superinvention.common.util.aws.s3.AwsS3Mo 4 | import com.taskforce.superinvention.common.util.aws.s3.S3Path 5 | import org.springframework.stereotype.Service 6 | import org.springframework.web.multipart.MultipartFile 7 | 8 | @Service 9 | class FileService ( 10 | private val awsS3Mo: AwsS3Mo, 11 | ){ 12 | companion object { 13 | const val TEMP_IMG_DIR_PATH = "temp/img" 14 | } 15 | 16 | fun fileTempSave(multipartFile: MultipartFile): S3Path { 17 | return awsS3Mo.uploadFileWithUUID(multipartFile, TEMP_IMG_DIR_PATH) 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/ImageFormat.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image 2 | 3 | enum class ImageFormat { 4 | JPEG, JPG, PNG, GIF, WEBP; 5 | 6 | companion object { 7 | private val map = values() 8 | fun extensionOf(value: String): ImageFormat? = values().find { it.name == value.toUpperCase() } 9 | } 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/ImageService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image 2 | 3 | import com.taskforce.superinvention.app.domain.common.image.resize.strategy.ImageResizeStrategyLocator 4 | import com.taskforce.superinvention.app.web.dto.common.image.ResizeDto 5 | import com.taskforce.superinvention.common.exception.InvalidInputException 6 | import com.taskforce.superinvention.common.util.aws.s3.AwsS3Mo 7 | import com.taskforce.superinvention.common.util.aws.s3.S3Path 8 | import com.taskforce.superinvention.common.util.file.FileMo 9 | import org.apache.commons.io.FilenameUtils 10 | import org.springframework.stereotype.Service 11 | import org.springframework.web.multipart.MultipartFile 12 | import java.io.File 13 | 14 | @Service 15 | class ImageService( 16 | private val awsS3Mo: AwsS3Mo, 17 | private val imageResizeStrategyLocator: ImageResizeStrategyLocator 18 | ) { 19 | companion object { 20 | const val TEMP_IMG_DIR_PATH = "temp/img" 21 | val invalidInputException = InvalidInputException() 22 | } 23 | 24 | fun fileImageSave(multipartFile: MultipartFile, resize: ResizeDto = ResizeDto()): S3Path { 25 | val file = FileMo.convertMultiPartToFile(multipartFile) 26 | 27 | if(resize.width != null && resize.height != null) { 28 | return awsS3Mo.uploadFileWithUUID(resizeImage(file, resize), TEMP_IMG_DIR_PATH) 29 | } 30 | 31 | return awsS3Mo.uploadFileWithUUID(file, TEMP_IMG_DIR_PATH) 32 | } 33 | 34 | fun resizeImage(file: File, resize: ResizeDto): File { 35 | val extension = FilenameUtils.getExtension(file.name) 36 | 37 | val format: ImageFormat = ImageFormat.extensionOf(extension) 38 | ?: throw invalidInputException 39 | 40 | return imageResizeStrategyLocator.getStrategy(format) 41 | .resize(file, resize) 42 | .absoluteFile 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/resize/ImageResizeService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.resize 2 | 3 | import com.taskforce.superinvention.app.domain.common.image.webp.convert.WebpConvertService 4 | import com.taskforce.superinvention.common.exception.InvalidInputException 5 | import org.springframework.stereotype.Service 6 | 7 | @Service 8 | class ImageResizeService( 9 | private val webpConversionService: WebpConvertService, 10 | ) { 11 | 12 | companion object { 13 | val invalidInputException = InvalidInputException() 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/resize/strategy/GifResizeStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.resize.strategy 2 | 3 | import com.drew.imaging.ImageMetadataReader 4 | import com.sksamuel.scrimage.ImmutableImage 5 | import com.sksamuel.scrimage.nio.GifWriter 6 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 7 | import com.taskforce.superinvention.app.web.dto.common.image.ResizeDto 8 | import com.taskforce.superinvention.common.util.file.image.gif.GifMo 9 | import org.springframework.stereotype.Service 10 | import java.io.File 11 | 12 | @Service 13 | class GifResizeStrategy: ImageResizeStrategy { 14 | 15 | override fun identify(imageFormat: ImageFormat): Boolean { 16 | return imageFormat == ImageFormat.GIF 17 | } 18 | 19 | override fun resize(file: File, resize: ResizeDto): File { 20 | val metadata = ImageMetadataReader.readMetadata(file) 21 | return if(GifMo.isAnimated(metadata)) { 22 | file 23 | } else { 24 | ImmutableImage 25 | .loader() 26 | .fromFile(file) 27 | .scaleTo(resize.width!!.toInt(), resize.height!!.toInt()) 28 | .output(GifWriter.Default, File.createTempFile("s3-img", file.name)) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/resize/strategy/ImageResizeStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.resize.strategy 2 | 3 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 4 | import com.taskforce.superinvention.app.web.dto.common.image.ResizeDto 5 | import java.io.File 6 | 7 | interface ImageResizeStrategy { 8 | fun identify(imageFormat: ImageFormat): Boolean 9 | fun resize(file: File, resize: ResizeDto): File 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/resize/strategy/ImageResizeStrategyLocator.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.resize.strategy 2 | 3 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 4 | import com.taskforce.superinvention.common.exception.common.ImplementationIsNotSupported 5 | import org.springframework.stereotype.Service 6 | 7 | @Service 8 | class ImageResizeStrategyLocator( 9 | private val imageResizeStrategy: List 10 | ) { 11 | 12 | fun getStrategy(imageFormat: ImageFormat): ImageResizeStrategy { 13 | return imageResizeStrategy.find { service -> service.identify(imageFormat) } 14 | ?: throw ImplementationIsNotSupported() 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/resize/strategy/JpgResizeStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.resize.strategy 2 | 3 | import com.sksamuel.scrimage.ImmutableImage 4 | import com.sksamuel.scrimage.nio.JpegWriter 5 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 6 | import com.taskforce.superinvention.app.web.dto.common.image.ResizeDto 7 | import org.springframework.stereotype.Service 8 | import java.io.File 9 | 10 | @Service 11 | class JpgResizeStrategy: ImageResizeStrategy { 12 | 13 | override fun identify(imageFormat: ImageFormat): Boolean { 14 | return imageFormat == ImageFormat.JPEG || 15 | imageFormat == ImageFormat.JPG 16 | } 17 | 18 | override fun resize(file: File, resize: ResizeDto): File { 19 | return ImmutableImage 20 | .loader() 21 | .fromFile(file) 22 | .scaleTo(resize.width!!.toInt(), resize.height!!.toInt()) 23 | .output(JpegWriter.Default, File.createTempFile("s3-img", file.name)) 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/resize/strategy/PngResizeStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.resize.strategy 2 | 3 | import com.sksamuel.scrimage.ImmutableImage 4 | import com.sksamuel.scrimage.nio.GifWriter 5 | import com.sksamuel.scrimage.nio.PngWriter 6 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 7 | import com.taskforce.superinvention.app.web.dto.common.image.ResizeDto 8 | import org.springframework.stereotype.Service 9 | import java.io.File 10 | 11 | @Service 12 | class PngResizeStrategy: ImageResizeStrategy { 13 | 14 | override fun identify(imageFormat: ImageFormat): Boolean { 15 | return imageFormat == ImageFormat.PNG 16 | } 17 | 18 | override fun resize(file: File, resize: ResizeDto): File { 19 | return ImmutableImage 20 | .loader() 21 | .fromFile(file) 22 | .scaleTo(resize.width!!.toInt(), resize.height!!.toInt()) 23 | .output(PngWriter.NoCompression, File.createTempFile("s3-img", file.name)) 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/resize/strategy/WebpResizeStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.resize.strategy 2 | 3 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 4 | import com.taskforce.superinvention.app.web.dto.common.image.ResizeDto 5 | import org.springframework.stereotype.Service 6 | import java.io.File 7 | 8 | @Service 9 | class WebpResizeStrategy: ImageResizeStrategy { 10 | 11 | override fun identify(imageFormat: ImageFormat): Boolean { 12 | return imageFormat == ImageFormat.WEBP 13 | } 14 | 15 | override fun resize(file: File, resize: ResizeDto): File { 16 | // @Todo webp는 resizing 하지 않음 17 | return file 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/webp/convert/WebpCompressionParam.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.webp.convert 2 | 3 | data class WebpCompressionParam( 4 | val q: Int = -1 , // RGB 채널 압축 여부 ( 0 ~ 6 ) 5 | val m: Int = -1, // 압축 방식 지정 ( 0 ~ 6 ) - 높을 수록 고효율 압축, 시간 증가 6 | val lossless: Boolean = false, // 손실 압축 여부 7 | ) 8 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/webp/convert/WebpConvertService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.webp.convert 2 | 3 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 4 | import com.taskforce.superinvention.app.domain.common.image.webp.convert.strategy.WebpConvertStrategyLocator 5 | import com.taskforce.superinvention.common.config.async.AsyncConfig 6 | import com.taskforce.superinvention.common.exception.InvalidInputException 7 | import com.taskforce.superinvention.common.util.aws.s3.AwsS3Mo 8 | import com.taskforce.superinvention.common.util.aws.s3.S3Path 9 | import org.apache.commons.io.FilenameUtils 10 | import org.springframework.scheduling.annotation.Async 11 | import org.springframework.stereotype.Service 12 | import java.io.File 13 | 14 | @Service 15 | class WebpConvertService( 16 | private val strategyLocator: WebpConvertStrategyLocator, 17 | private val awsS3Mo: AwsS3Mo 18 | ) { 19 | 20 | companion object { 21 | val invalidInputException = InvalidInputException() 22 | } 23 | 24 | // s3 상의 이미지 경로에 /이미지.webp 형태의 압축본 생성 25 | @Async(AsyncConfig.WEBP_CONVERSION) 26 | fun convertToWebP(s3Path: S3Path) { 27 | val folderPath = s3Path.folderPath() 28 | 29 | val fileName = FilenameUtils.removeExtension(s3Path.fileName) 30 | val extension = FilenameUtils.getExtension(s3Path.fileName) 31 | val s3File = awsS3Mo.getObjectAsFile(s3Path) 32 | 33 | val format: ImageFormat = ImageFormat.extensionOf(extension) 34 | ?: throw invalidInputException 35 | 36 | val convertStrategy = strategyLocator.getStrategy(format) 37 | val convertedFile: File = convertStrategy.convert(fileName, s3File, WebpCompressionParam()) 38 | 39 | awsS3Mo.uploadFile(convertedFile, folderPath) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/webp/convert/handler/WebpAnimatedWriter.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.webp.convert.handler 2 | 3 | import java.io.File 4 | 5 | class WebpAnimatedWriter( 6 | private var q: Int = -1, 7 | private var m: Int = -1, 8 | private var mixed: Boolean = true, 9 | private var lossy: Boolean = true, 10 | private var multiThread: Boolean = true, 11 | ) { 12 | 13 | companion object { 14 | val DEFAULT: WebpAnimatedWriter = WebpAnimatedWriter() 15 | val LOSSLESS_COMPRESSION: WebpAnimatedWriter = DEFAULT.withLossless() 16 | } 17 | 18 | private val handler = Gif2WebpHandler() 19 | 20 | fun withQ(q: Int): WebpAnimatedWriter { 21 | require(q >= 0) { "q must be between 0 and 100" } 22 | require(q <= 100) { "q must be between 0 and 100" } 23 | return WebpAnimatedWriter(q, m, lossy) 24 | } 25 | 26 | fun withM(m: Int): WebpAnimatedWriter { 27 | require(m >= 0) { "m must be between 0 and 6" } 28 | require(m <= 6) { "m must be between 0 and 6" } 29 | return WebpAnimatedWriter(q, m, lossy) 30 | } 31 | 32 | fun withLossless(): WebpAnimatedWriter { 33 | return WebpAnimatedWriter(q, m, false) 34 | } 35 | 36 | fun writeAsByteArray(gifImage: File): ByteArray { 37 | return handler.convert(gifImage, q, m, lossy, mixed, multiThread) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/webp/convert/handler/WebpHandler.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.webp.convert.handler 2 | 3 | import org.apache.commons.lang3.SystemUtils 4 | import java.io.IOException 5 | import java.nio.file.Files 6 | import java.nio.file.Path 7 | import java.nio.file.StandardCopyOption 8 | import java.util.* 9 | import java.util.concurrent.TimeUnit 10 | 11 | abstract class WebpHandler { 12 | 13 | companion object { 14 | fun createPlaceholder(name: String): Path { 15 | return Files.createTempFile(name, "binary") 16 | } 17 | 18 | fun installBinary(output: Path, vararg sources: String) { 19 | for (source in sources) { 20 | val inputStream = WebpHandler::class.java.getResourceAsStream(source) 21 | if (inputStream != null) { 22 | Files.copy(inputStream, output, StandardCopyOption.REPLACE_EXISTING) 23 | inputStream.close() 24 | if (!SystemUtils.IS_OS_WINDOWS) { 25 | setExecutable(output) 26 | } 27 | return 28 | } 29 | } 30 | throw IOException("Could not locate webp binary at " + sources.contentToString()) 31 | } 32 | 33 | private fun setExecutable(output: Path): Boolean { 34 | return try { 35 | ProcessBuilder("chmod", "+x", output.toAbsolutePath().toString()) 36 | .start() 37 | .waitFor(30, TimeUnit.SECONDS) 38 | } catch (e: InterruptedException) { 39 | throw IOException(e) 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/webp/convert/strategy/Jpg2WebpStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.webp.convert.strategy 2 | 3 | import com.sksamuel.scrimage.ImmutableImage 4 | import com.sksamuel.scrimage.webp.WebpWriter 5 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 6 | import com.taskforce.superinvention.app.domain.common.image.webp.convert.WebpCompressionParam 7 | import com.taskforce.superinvention.common.util.kakao.KakaoOAuth 8 | import org.apache.commons.io.FileUtils 9 | import org.slf4j.Logger 10 | import org.slf4j.LoggerFactory 11 | import org.springframework.stereotype.Service 12 | import java.io.File 13 | import java.io.FileOutputStream 14 | import java.io.IOException 15 | 16 | @Service 17 | class Jpg2WebpStrategy: WebpConvertStrategy { 18 | 19 | companion object { 20 | val LOG: Logger = LoggerFactory.getLogger(Jpg2WebpStrategy::class.java) 21 | } 22 | 23 | override fun identify(imageFormat: ImageFormat): Boolean { 24 | return imageFormat == ImageFormat.JPG || 25 | imageFormat == ImageFormat.JPEG 26 | } 27 | 28 | override fun convert(fileName: String, file: File, param: WebpCompressionParam): File { 29 | 30 | return try { 31 | ImmutableImage.loader() 32 | .fromFile(file) 33 | .output(WebpWriter.DEFAULT, File("${fileName}.webp")) 34 | } catch (e: IOException) { 35 | LOG.error("JPG -> WebP간 변환 실패, 컨버팅을 취소합니다. {}", e) 36 | file 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/webp/convert/strategy/Png2WebpStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.webp.convert.strategy 2 | 3 | import com.sksamuel.scrimage.ImmutableImage 4 | import com.sksamuel.scrimage.webp.WebpWriter 5 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 6 | import com.taskforce.superinvention.app.domain.common.image.webp.convert.WebpCompressionParam 7 | import org.apache.commons.io.FileUtils 8 | import org.slf4j.Logger 9 | import org.slf4j.LoggerFactory 10 | import org.springframework.stereotype.Service 11 | import java.io.File 12 | import java.io.FileOutputStream 13 | import java.io.IOException 14 | 15 | @Service 16 | class Png2WebpStrategy: WebpConvertStrategy { 17 | 18 | companion object { 19 | val LOG: Logger = LoggerFactory.getLogger(Png2WebpStrategy::class.java) 20 | } 21 | 22 | override fun identify(imageFormat: ImageFormat): Boolean { 23 | return imageFormat == ImageFormat.PNG 24 | } 25 | 26 | override fun convert(fileName: String, file: File, param: WebpCompressionParam): File { 27 | 28 | return try { 29 | ImmutableImage.loader() 30 | .fromFile(file) 31 | .output(WebpWriter.DEFAULT, File("${fileName}.webp")) 32 | } catch (e: IOException) { 33 | LOG.error("PNG -> WebP간 변환 실패, 컨버팅을 취소합니다. {}", e) 34 | file 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/webp/convert/strategy/WebpConvertStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.webp.convert.strategy 2 | 3 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 4 | import com.taskforce.superinvention.app.domain.common.image.webp.convert.WebpCompressionParam 5 | import java.io.File 6 | 7 | interface WebpConvertStrategy { 8 | fun identify(imageFormat: ImageFormat): Boolean 9 | fun convert(fileName: String, file: File, param: WebpCompressionParam): File 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/common/image/webp/convert/strategy/WebpConvertStrategyLocator.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.common.image.webp.convert.strategy 2 | 3 | import com.taskforce.superinvention.app.domain.common.image.ImageFormat 4 | import com.taskforce.superinvention.common.exception.common.ImplementationIsNotSupported 5 | import org.springframework.stereotype.Service 6 | 7 | @Service 8 | class WebpConvertStrategyLocator( 9 | private val webpConvertStrategy: List 10 | ) { 11 | 12 | fun getStrategy(imageFormat: ImageFormat): WebpConvertStrategy { 13 | return webpConvertStrategy.find { service -> service.identify(imageFormat) } 14 | ?: throw ImplementationIsNotSupported() 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/ClubInterest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.Club 5 | import com.taskforce.superinvention.app.domain.interest.interest.Interest 6 | import com.taskforce.superinvention.app.domain.interest.interestGroup.InterestGroup 7 | import javax.persistence.Entity 8 | import javax.persistence.FetchType 9 | import javax.persistence.JoinColumn 10 | import javax.persistence.ManyToOne 11 | 12 | @Entity 13 | class ClubInterest( 14 | @ManyToOne(fetch = FetchType.LAZY) 15 | @JoinColumn(name = "club_seq") 16 | var club: Club, 17 | @ManyToOne(fetch = FetchType.LAZY) 18 | @JoinColumn(name = "interest_seq") 19 | var interest: Interest, 20 | var priority: Long 21 | ) : BaseEntity() { 22 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interest/Interest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interest 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.interest.interestGroup.InterestGroup 5 | import javax.persistence.Entity 6 | import javax.persistence.FetchType 7 | import javax.persistence.JoinColumn 8 | import javax.persistence.ManyToOne 9 | 10 | @Entity 11 | class Interest( 12 | var name: String, 13 | 14 | @ManyToOne(fetch = FetchType.LAZY) 15 | @JoinColumn(name = "interest_group_seq") 16 | var interestGroup: InterestGroup 17 | ) : BaseEntity() -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interest/InterestDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interest 2 | 3 | import com.taskforce.superinvention.app.domain.interest.interestGroup.SimpleInterestGroupDto 4 | 5 | class InterestDto { 6 | var seq: Long? 7 | var name: String 8 | var interestGroup: SimpleInterestGroupDto 9 | 10 | constructor(seq: Long?, name: String, interestGroup: SimpleInterestGroupDto) { 11 | this.seq = seq 12 | this.name = name 13 | this.interestGroup = interestGroup 14 | } 15 | 16 | constructor(interest: Interest) { 17 | this.seq = interest.seq 18 | this.name = interest.name 19 | this.interestGroup = SimpleInterestGroupDto(interest.interestGroup) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interest/InterestRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interest 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository 4 | import org.springframework.stereotype.Repository 5 | 6 | @Repository 7 | interface InterestRepository : JpaRepository, 8 | InterestRepositoryCustom { 9 | } 10 | 11 | interface InterestRepositoryCustom { 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interest/InterestRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interest 2 | 3 | import com.querydsl.core.types.Projections 4 | import com.querydsl.jpa.impl.JPAQueryFactory 5 | import com.taskforce.superinvention.app.domain.interest.interest.QInterest.interest 6 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 7 | import org.springframework.stereotype.Repository 8 | 9 | @Repository 10 | class InterestRepositoryImpl( 11 | private val query: JPAQueryFactory 12 | ) : QuerydslRepositorySupport(Interest::class.java), 13 | InterestRepositoryCustom 14 | { 15 | fun findBySeq(seq: Long): Interest { 16 | return from(interest) 17 | .where(interest.seq.eq(seq)) 18 | .fetchOne() 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interest/InterestService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interest 2 | 3 | import com.taskforce.superinvention.app.domain.user.userInterest.UserInterestRepository 4 | import com.taskforce.superinvention.common.exception.BizException 5 | import org.springframework.http.HttpStatus 6 | import org.springframework.stereotype.Service 7 | import org.springframework.transaction.annotation.Transactional 8 | import java.lang.IllegalArgumentException 9 | 10 | @Service 11 | class InterestService( 12 | private val interestRepository: InterestRepository, 13 | private val userInterestRepository: UserInterestRepository 14 | ) { 15 | fun findBySeq(seq: Long):Interest = interestRepository.findById(seq).orElseThrow{IllegalArgumentException()} 16 | 17 | @Transactional 18 | fun checkBeforeConvertClubInterest(interestList: Iterable): Iterable { 19 | if (!isInEqualsInterestGroup(interestList)) throw BizException("하나의 관심사 그룹에 속하는 관심사들만 등록할 수 있습니다", HttpStatus.BAD_REQUEST) 20 | return interestList 21 | } 22 | 23 | @Transactional 24 | fun isInEqualsInterestGroup(interests: Iterable): Boolean { 25 | return interests.map { it.interestGroup }.distinctBy { it.seq }.size == 1 26 | } 27 | 28 | @Transactional 29 | fun findBySeqList(seqList: Iterable): List = interestRepository.findAllById(seqList) 30 | 31 | 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interestGroup/InterestGroup.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interestGroup 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.interest.interest.Interest 5 | import javax.persistence.Entity 6 | import javax.persistence.OneToMany 7 | 8 | @Entity 9 | class InterestGroup ( 10 | var name: String 11 | ) : BaseEntity() { 12 | @OneToMany(mappedBy = "interestGroup") 13 | lateinit var interestList: List 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interestGroup/InterestGroupDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interestGroup 2 | 3 | import com.taskforce.superinvention.app.domain.interest.interest.Interest 4 | import com.taskforce.superinvention.app.domain.interest.interest.InterestDto 5 | 6 | class InterestGroupDto { 7 | var name: String 8 | var groupSeq: Long? 9 | var interestList: List 10 | 11 | constructor(group: InterestGroup, interestList: List ) { 12 | this.name = group.name 13 | this.groupSeq = group.seq 14 | this.interestList = interestList.map { interest -> InterestDto(interest.seq, interest.name, SimpleInterestGroupDto(interest.interestGroup))}.toMutableList() 15 | } 16 | 17 | constructor(groupSeq: Long, name: String, interestList: List ) { 18 | this.name = name 19 | this.groupSeq = groupSeq 20 | this.interestList = interestList 21 | } 22 | } 23 | 24 | data class SimpleInterestGroupDto( 25 | val seq: Long, 26 | val name: String 27 | ) { 28 | constructor(interestGroup:InterestGroup): this(interestGroup.seq!!, interestGroup.name) 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interestGroup/InterestGroupRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interestGroup 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository 4 | import org.springframework.stereotype.Repository 5 | 6 | @Repository 7 | interface InterestGroupRepository : JpaRepository, 8 | InterestGroupRepositoryCustom 9 | 10 | interface InterestGroupRepositoryCustom { 11 | fun findAllInterestGroupList(): List 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interestGroup/InterestGroupRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interestGroup 2 | 3 | import com.querydsl.core.group.GroupBy.groupBy 4 | import com.querydsl.core.group.GroupBy.list 5 | import com.querydsl.jpa.impl.JPAQueryFactory 6 | import com.taskforce.superinvention.app.domain.interest.interest.Interest 7 | import com.taskforce.superinvention.app.domain.interest.interest.QInterest.interest 8 | import com.taskforce.superinvention.app.domain.interest.interestGroup.QInterestGroup.interestGroup 9 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 10 | import org.springframework.stereotype.Repository 11 | 12 | @Repository 13 | class InterestGroupRepositoryImpl( 14 | private val query: JPAQueryFactory 15 | ): InterestGroupRepositoryCustom, 16 | QuerydslRepositorySupport(InterestGroup::class.java) { 17 | 18 | override fun findAllInterestGroupList(): MutableList { 19 | 20 | val groups: MutableMap> = query. 21 | select(interestGroup.seq, interestGroup.name, interest.seq, interest.name). 22 | from(interestGroup). 23 | innerJoin(interestGroup.interestList, interest). 24 | transform(groupBy(interestGroup).`as`(list(interest))) 25 | 26 | return groups.map { interestGroup -> 27 | InterestGroupDto(interestGroup.key, interestGroup.value) 28 | }.toMutableList() 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/interest/interestGroup/InterestGroupService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interestGroup 2 | 3 | import org.springframework.stereotype.Service 4 | 5 | @Service 6 | class InterestGroupService( 7 | private val interestGroupRepo: InterestGroupRepository 8 | ) { 9 | 10 | fun getInterestList(): List { 11 | val result = interestGroupRepo.findAllInterestGroupList() 12 | return result 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/meeting/Meeting.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.meeting 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.Club 5 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 6 | import java.time.LocalDateTime 7 | import javax.persistence.* 8 | 9 | @Entity 10 | class Meeting( 11 | var title: String, 12 | var content: String, 13 | var startTimestamp: LocalDateTime, 14 | var endTimestamp: LocalDateTime, 15 | @ManyToOne 16 | var club: Club, 17 | var deleteFlag: Boolean, 18 | var maximumNumber: Int?, 19 | @ManyToOne 20 | var regClubUser: ClubUser, 21 | var region: String?, 22 | var regionURL: String?, 23 | var cost: Int? 24 | ) : BaseEntity() { 25 | @OneToMany(mappedBy = "meeting", fetch = FetchType.EAGER) 26 | @OrderBy("deleteFlag desc") 27 | var meetingApplications: List = listOf() 28 | 29 | fun isOpen(): Boolean = endTimestamp.isAfter(LocalDateTime.now()) 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/meeting/MeetingApplication.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.meeting 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 5 | import javax.persistence.* 6 | 7 | @Entity 8 | class MeetingApplication( 9 | @ManyToOne 10 | @JoinColumn(name = "club_user_seq") 11 | var clubUser: ClubUser, 12 | 13 | @ManyToOne 14 | @JoinColumn(name = "meeting_seq") 15 | var meeting: Meeting, 16 | var deleteFlag: Boolean 17 | ) : BaseEntity(){ 18 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/region/ClubRegion.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.region 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.Club 5 | import com.taskforce.superinvention.app.domain.region.Region 6 | import javax.persistence.Entity 7 | import javax.persistence.FetchType 8 | import javax.persistence.ManyToOne 9 | 10 | @Entity 11 | class ClubRegion( 12 | @ManyToOne(fetch = FetchType.LAZY) 13 | var club:Club, 14 | 15 | @ManyToOne(fetch = FetchType.LAZY) 16 | var region: Region, 17 | var priority: Long 18 | ) : BaseEntity() -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/region/ClubRegionRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.region 2 | 3 | import com.taskforce.superinvention.app.domain.club.Club 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface ClubRegionRepository : JpaRepository { 9 | fun findByClub(club: Club): List 10 | fun findByClubSeq(clubSeq: Long): List? 11 | fun findByClubSeqIn(clubSeq: List): List 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/region/Region.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.region 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore 4 | import com.taskforce.superinvention.app.domain.BaseEntity 5 | import javax.persistence.* 6 | 7 | @Entity 8 | class Region( 9 | 10 | @ManyToOne(fetch = FetchType.LAZY) 11 | @JoinColumn(name="super_region_seq", foreignKey = ForeignKey(ConstraintMode.NO_CONSTRAINT)) 12 | @JsonIgnore 13 | var superRegion: Region?, 14 | var name: String, 15 | var superRegionRoot: String, 16 | var level: Long 17 | 18 | ): BaseEntity() { 19 | 20 | @OneToMany 21 | @JoinColumn(name="super_region_seq", foreignKey = ForeignKey(ConstraintMode.NO_CONSTRAINT)) 22 | var subRegions: List = listOf() 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/region/RegionRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.region 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository 4 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface RegionRepository : JpaRepository, RegionRepositoryCustom { 9 | 10 | } 11 | 12 | interface RegionRepositoryCustom { 13 | fun findByLevelWithSubRegions(): List 14 | } 15 | 16 | @Repository 17 | class RegionRepositoryImpl: RegionRepositoryCustom, 18 | QuerydslRepositorySupport(Region::class.java) { 19 | 20 | override fun findByLevelWithSubRegions(): List { 21 | val superRegion = QRegion.region 22 | val subRegion = QRegion("r2") 23 | 24 | val result = from(superRegion) 25 | .join(superRegion.subRegions, subRegion).fetchJoin() 26 | .where(superRegion.superRegion.isNull) 27 | 28 | val fetch = result.fetch().distinct() 29 | return fetch 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/region/RegionService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.region 2 | 3 | import com.taskforce.superinvention.app.web.dto.region.* 4 | import com.taskforce.superinvention.common.exception.BizException 5 | import org.springframework.http.HttpStatus 6 | import org.springframework.stereotype.Service 7 | import org.springframework.transaction.annotation.Transactional 8 | import java.lang.IllegalArgumentException 9 | 10 | @Service 11 | class RegionService( 12 | val regionRepository: RegionRepository 13 | ) { 14 | @Transactional 15 | fun findAllRegionDtoList(): List { 16 | val regions = regionRepository.findByLevelWithSubRegions().map { of(it, it.subRegions) } 17 | return regions 18 | } 19 | 20 | fun findBySeq(seq: Long): Region = regionRepository.findById(seq).orElseThrow{IllegalArgumentException()} 21 | 22 | @Transactional 23 | fun checkBeforeConvertClubRegion(regions: Iterable): Iterable { 24 | if (!isInEqualsSuperRegion(regions)) throw BizException("하나의 도/(특별)시 에 속하는 지역 끼리만 등록할 수 있습니다", HttpStatus.BAD_REQUEST) 25 | return regions 26 | } 27 | 28 | @Transactional 29 | fun isInEqualsSuperRegion(regions: Iterable): Boolean { 30 | return regions.map { it.superRegion?: it }.distinctBy { it.seq }.size == 1 31 | } 32 | 33 | @Transactional 34 | fun findBySeqList(seqList: Iterable) = regionRepository.findAllById(seqList) 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/role/ClubUserRole.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.role 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 5 | import javax.persistence.* 6 | 7 | @Entity 8 | class ClubUserRole( 9 | @ManyToOne(fetch = FetchType.LAZY) 10 | @JoinColumn(name = "club_user_seq") 11 | var clubUser: ClubUser, 12 | 13 | @ManyToOne(fetch = FetchType.LAZY) 14 | @JoinColumn(name = "role_seq") 15 | var role: Role 16 | ): BaseEntity() -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/role/ClubUserRoleRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.role 2 | 3 | import com.taskforce.superinvention.app.domain.club.user.ClubUser 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface ClubUserRoleRepository : JpaRepository { 9 | fun findByClubUser(clubUser: ClubUser): Set 10 | fun findByClubUserIn(clubUsers: Iterable): List 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/role/Role.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.role 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import javax.persistence.* 5 | 6 | @Entity 7 | class Role ( 8 | @Enumerated(EnumType.STRING) 9 | var name: RoleName, 10 | 11 | @ManyToOne(fetch = FetchType.LAZY) 12 | @JoinColumn(name = "role_group_seq") 13 | var roleGroup: RoleGroup, 14 | 15 | var level: Int 16 | ): BaseEntity() { 17 | 18 | companion object { 19 | const val NONE = "ROLE_NONE" 20 | const val MEMBER = "ROLE_MEMBER" 21 | const val CLUB_MEMBER = "ROLE_CLUB_MEMBER" 22 | const val MANAGER = "ROLE_MANAGER" 23 | const val MASTER = "ROLE_MASTER" 24 | 25 | private val lookup = RoleName.values().associateBy(RoleName::role) 26 | fun fromRoleName(role: String): RoleName = requireNotNull(lookup[role]) 27 | } 28 | 29 | enum class RoleName( 30 | val label: String, 31 | val role : String 32 | ) { 33 | NONE("비회원", Role.NONE), 34 | MEMBER("회원", Role.MEMBER), 35 | CLUB_MEMBER("모임원", Role.CLUB_MEMBER), 36 | MANAGER("매니저", Role.MANAGER), 37 | MASTER("모임장",Role.MASTER) 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/role/RoleGroup.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.role 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import javax.persistence.Entity 5 | 6 | @Entity 7 | class RoleGroup( 8 | var name: String, 9 | var role_type: String 10 | ) : BaseEntity() -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/role/RoleGroupRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.role 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository 4 | import org.springframework.stereotype.Repository 5 | 6 | @Repository 7 | interface RoleGroupRepository : JpaRepository { 8 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/role/RoleGroupRepositorySupport.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.role 2 | 3 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 4 | import org.springframework.stereotype.Repository 5 | 6 | @Repository 7 | class RoleGroupRepositorySupport : QuerydslRepositorySupport(RoleGroup::class.java){ 8 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/role/RoleRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.role 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository 4 | import org.springframework.stereotype.Repository 5 | 6 | @Repository 7 | interface RoleRepository : JpaRepository { 8 | fun findByName(roleName: Role.RoleName): Role 9 | fun findBySeqIn(roleSeqList: Set): Set 10 | fun findByNameIn(roleNameList: Set): Set 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/role/RoleRepositorySupport.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.role 2 | 3 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 4 | import org.springframework.stereotype.Repository 5 | 6 | @Repository 7 | class RoleRepositorySupport : QuerydslRepositorySupport(Role::class.java) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/UserDetailsProvider.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user 2 | 3 | import org.slf4j.LoggerFactory 4 | import org.springframework.security.core.userdetails.UserDetails 5 | import org.springframework.security.core.userdetails.UserDetailsService 6 | import org.springframework.stereotype.Service 7 | import org.springframework.transaction.annotation.Transactional 8 | 9 | @Service 10 | class UserDetailsProvider( 11 | private val userRepository: UserRepository 12 | ): UserDetailsService { 13 | 14 | companion object { 15 | val LOG = LoggerFactory.getLogger(UserDetailsProvider::class.java) 16 | } 17 | 18 | @Transactional 19 | override fun loadUserByUsername(userId: String): UserDetails { 20 | val user: User = userRepository.findByUserId(userId)!! 21 | 22 | return org.springframework.security.core.userdetails.User 23 | .withUsername(user.userId) 24 | .password("") 25 | .authorities(user.userRoles) 26 | .accountExpired(false) 27 | .accountLocked(false) 28 | .credentialsExpired(false) 29 | .disabled(false) 30 | .build() 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/UserInfoService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user 2 | 3 | import com.taskforce.superinvention.app.domain.user.userInterest.UserInterestService 4 | import com.taskforce.superinvention.app.domain.user.userRegion.UserRegionService 5 | import com.taskforce.superinvention.app.web.dto.user.info.UserInfoDto 6 | import com.taskforce.superinvention.app.web.dto.user.info.UserInfoInterestDto 7 | import com.taskforce.superinvention.app.web.dto.user.info.UserInfoRegionDto 8 | import org.springframework.stereotype.Service 9 | import org.springframework.transaction.annotation.Transactional 10 | 11 | @Service 12 | class UserInfoService( 13 | private val userRepository: UserRepository, 14 | private val userInterestService : UserInterestService, 15 | private val userRegionService: UserRegionService 16 | ){ 17 | @Transactional 18 | fun getUserInfo(userData: User): UserInfoDto { 19 | 20 | val user = userRepository.findByUserId(userData.userId)!! 21 | 22 | // [1] 유저 관심사 조회 23 | val userInfoInterests: List = userInterestService.findUserInterests(user) 24 | 25 | // [2] 유저 관심 지역 조회 26 | val userRegions: List = userRegionService.findUserRegionList(user).userRegions 27 | .map { userRegions -> UserInfoRegionDto(userRegions.priority, userRegions.region) } 28 | 29 | return UserInfoDto(user, userRegions, userInfoInterests) 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/UserRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository 4 | import org.springframework.stereotype.Repository 5 | 6 | @Repository 7 | interface UserRepository : JpaRepository { 8 | fun findByUserId(userId: String?): User? 9 | fun findByUserName(username: String): User? 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/UserType.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user 2 | 3 | enum class UserType { 4 | KAKAO 5 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/userInterest/UserInterest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user.userInterest 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.interest.interest.Interest 5 | import com.taskforce.superinvention.app.domain.user.User 6 | import javax.persistence.Entity 7 | import javax.persistence.FetchType 8 | import javax.persistence.JoinColumn 9 | import javax.persistence.ManyToOne 10 | 11 | @Entity 12 | class UserInterest( 13 | @ManyToOne(fetch = FetchType.LAZY) 14 | @JoinColumn(name = "user_seq") 15 | var user: User, 16 | @ManyToOne(fetch = FetchType.LAZY) 17 | @JoinColumn(name = "interest_seq") 18 | var interest: Interest, 19 | var priority: Long 20 | ) : BaseEntity() -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/userInterest/UserInterestRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user.userInterest 2 | 3 | import com.taskforce.superinvention.app.domain.interest.interest.QInterest 4 | import com.taskforce.superinvention.app.domain.interest.interestGroup.QInterestGroup 5 | import com.taskforce.superinvention.app.domain.user.User 6 | import org.springframework.data.jpa.repository.JpaRepository 7 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 8 | import org.springframework.stereotype.Repository 9 | 10 | @Repository 11 | interface UserInterestRepository : JpaRepository, UserInterestRepositoryCustom{ 12 | fun findByUserOrderByPriority(user: User): List 13 | } 14 | 15 | interface UserInterestRepositoryCustom { 16 | fun findUserInterests(user: User): List 17 | } 18 | 19 | @Repository 20 | class UserInterestRepositoryImpl: UserInterestRepositoryCustom, 21 | QuerydslRepositorySupport(UserInterest::class.java) { 22 | 23 | override fun findUserInterests(user: User): List { 24 | val userInterest = QUserInterest.userInterest 25 | val interest = QInterest.interest 26 | val interestGroup = QInterestGroup.interestGroup 27 | 28 | val query = from(userInterest) 29 | .join(userInterest.interest, interest).fetchJoin() 30 | .join(interest.interestGroup, interestGroup).fetchJoin() 31 | .where(userInterest.user.seq.eq(user.seq)) 32 | 33 | return query.fetch() 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/userRegion/UserRegion.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user.userRegion 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.region.Region 5 | import com.taskforce.superinvention.app.domain.user.User 6 | import javax.persistence.Entity 7 | import javax.persistence.FetchType 8 | import javax.persistence.JoinColumn 9 | import javax.persistence.ManyToOne 10 | 11 | @Entity 12 | class UserRegion( 13 | @ManyToOne(fetch = FetchType.LAZY) 14 | @JoinColumn(name="user_seq") 15 | var user: User, 16 | @ManyToOne(fetch = FetchType.LAZY) 17 | @JoinColumn(name="region_seq") 18 | var region: Region, 19 | var priority: Long 20 | ) : BaseEntity() -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/userRegion/UserRegionRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user.userRegion 2 | 3 | import com.taskforce.superinvention.app.domain.region.QRegion 4 | import com.taskforce.superinvention.app.domain.user.QUser 5 | import org.springframework.data.jpa.repository.JpaRepository 6 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport 7 | import org.springframework.stereotype.Repository 8 | 9 | @Repository 10 | interface UserRegionRepository : JpaRepository, UserRegionRepositoryCustom { 11 | fun findByUserSeq(userSeq: Long): List 12 | } 13 | 14 | interface UserRegionRepositoryCustom { 15 | fun findByUserWithRegion(userSeq: Long): List 16 | } 17 | 18 | @Repository 19 | class UserRegionRepositoryImpl: UserRegionRepositoryCustom, 20 | QuerydslRepositorySupport(UserRegion::class.java){ 21 | 22 | override fun findByUserWithRegion(userSeq: Long): List { 23 | 24 | val user = QUser.user 25 | val userRegion = QUserRegion.userRegion 26 | val region = QRegion.region 27 | 28 | val query = from(userRegion) 29 | .join(userRegion.user, user).fetchJoin() 30 | .join(userRegion.region, region).fetchJoin() 31 | .where(userRegion.user.seq.eq(userSeq)) 32 | return query.fetch() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/userRole/UserRole.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user.userRole 2 | 3 | import com.taskforce.superinvention.app.domain.BaseEntity 4 | import com.taskforce.superinvention.app.domain.user.User 5 | import org.springframework.security.core.GrantedAuthority 6 | import javax.persistence.Entity 7 | import javax.persistence.FetchType 8 | import javax.persistence.JoinColumn 9 | import javax.persistence.ManyToOne 10 | 11 | @Entity 12 | class UserRole( 13 | @ManyToOne(fetch = FetchType.LAZY) 14 | @JoinColumn(name = "user_seq") 15 | var user: User, 16 | var roleName: String 17 | ) : BaseEntity(), GrantedAuthority { 18 | 19 | override fun getAuthority(): String { 20 | return roleName 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/userRole/UserRoleRepository.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user.userRole 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository 4 | import org.springframework.stereotype.Repository 5 | 6 | @Repository 7 | interface UserRoleRepository : JpaRepository { 8 | fun findByUserSeqAndRoleName(userSeq: Long, roleName: String): UserRole? 9 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/domain/user/userRole/UserRoleService.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user.userRole 2 | 3 | import com.taskforce.superinvention.app.domain.role.Role 4 | import com.taskforce.superinvention.app.domain.user.User 5 | import org.springframework.stereotype.Service 6 | 7 | @Service 8 | class UserRoleService( 9 | val userRoleRepository: UserRoleRepository 10 | ) { 11 | 12 | fun addRole(user: User, roleName: Role.RoleName) { 13 | userRoleRepository.save(UserRole(user, roleName.role)) 14 | } 15 | 16 | fun removeRoleIfExist(user: User, roleName: Role.RoleName) { 17 | val userRole = userRoleRepository.findByUserSeqAndRoleName(user.seq!!, roleName.role) 18 | 19 | if(userRole != null) { 20 | userRoleRepository.delete(userRole) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/common/response/ErrorResponseDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.common.response 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | import java.lang.RuntimeException 6 | 7 | class ErrorResponseDto( 8 | val httpStatus: HttpStatus, 9 | override val message: String 10 | ) : RuntimeException() -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/common/response/ResponseDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.common.response 2 | 3 | 4 | class ResponseDto ( 5 | val data: T, 6 | val message: String = "success" 7 | ) { 8 | companion object { 9 | const val EMPTY = "" 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/controller/CommonController.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.controller 2 | 3 | import com.taskforce.superinvention.app.domain.common.FileService 4 | import com.taskforce.superinvention.app.domain.common.image.ImageService 5 | import com.taskforce.superinvention.app.web.common.response.ResponseDto 6 | import com.taskforce.superinvention.app.web.dto.common.image.ResizeDto 7 | import com.taskforce.superinvention.common.util.aws.s3.S3Path 8 | import org.springframework.web.bind.annotation.PostMapping 9 | import org.springframework.web.bind.annotation.RequestMapping 10 | import org.springframework.web.bind.annotation.RestController 11 | import org.springframework.web.multipart.MultipartFile 12 | 13 | @RequestMapping("/common") 14 | @RestController 15 | class CommonController( 16 | private val fileService : FileService, 17 | private val imageService: ImageService 18 | ) { 19 | @PostMapping("/temp/image") 20 | fun imageTempSave(file: MultipartFile, resize: ResizeDto): ResponseDto { 21 | return ResponseDto(data = imageService.fileImageSave(file, resize)) 22 | } 23 | 24 | @PostMapping("/temp/file") 25 | fun fileTempSave(file: MultipartFile): ResponseDto { 26 | return ResponseDto(data = fileService.fileTempSave(file)) 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/controller/InterestGroupController.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.controller 2 | 3 | import com.taskforce.superinvention.app.domain.interest.interestGroup.InterestGroupDto 4 | import com.taskforce.superinvention.app.domain.interest.interestGroup.InterestGroupService 5 | import com.taskforce.superinvention.app.web.common.response.ResponseDto 6 | import org.springframework.web.bind.annotation.GetMapping 7 | import org.springframework.web.bind.annotation.RestController 8 | 9 | @RestController 10 | class InterestGroupController( 11 | private val interestGroupService: InterestGroupService 12 | ) { 13 | 14 | @GetMapping("/interestGroup/all") 15 | fun getInterestList(): ResponseDto> { 16 | val result = interestGroupService.getInterestList() 17 | return ResponseDto(data = result) 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/controller/club/album/ClubAlbumLikeController.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.controller.club.album 2 | 3 | import com.taskforce.superinvention.app.domain.club.album.like.ClubAlbumLikeService 4 | import com.taskforce.superinvention.app.domain.user.User 5 | import com.taskforce.superinvention.app.web.common.response.ResponseDto 6 | import com.taskforce.superinvention.app.web.dto.club.album.like.ClubAlbumLikeDto 7 | import com.taskforce.superinvention.common.config.argument.resolver.auth.AuthUser 8 | import org.springframework.http.HttpStatus 9 | import org.springframework.web.bind.annotation.* 10 | 11 | @RestController 12 | @RequestMapping("/club/{clubSeq}/album/{clubAlbumSeq}/like") 13 | class ClubAlbumLikeController( 14 | private val clubAlbumLikeService: ClubAlbumLikeService 15 | ) { 16 | @PostMapping 17 | @ResponseStatus(HttpStatus.CREATED) 18 | fun registerClubAlbumLike(@AuthUser user: User, 19 | @PathVariable clubSeq: Long, 20 | @PathVariable clubAlbumSeq: Long): ResponseDto { 21 | 22 | return ResponseDto(data = clubAlbumLikeService.registerClubAlbumLike(user, clubSeq, clubAlbumSeq)) 23 | } 24 | 25 | @DeleteMapping 26 | fun deleteClubAlbumLike(@AuthUser user: User, 27 | @PathVariable clubSeq: Long, 28 | @PathVariable clubAlbumSeq: Long): ResponseDto { 29 | 30 | return ResponseDto(data = clubAlbumLikeService.removeClubAlbumLike(user, clubSeq, clubAlbumSeq)) 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/controller/club/board/ClubBoardLikeController.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.controller.club.board 2 | 3 | import com.taskforce.superinvention.app.domain.club.board.like.ClubBoardLikeService 4 | import com.taskforce.superinvention.app.domain.user.User 5 | import com.taskforce.superinvention.app.web.common.response.ResponseDto 6 | import com.taskforce.superinvention.app.web.dto.club.board.like.ClubBoardLikeDto 7 | import com.taskforce.superinvention.common.config.argument.resolver.auth.AuthUser 8 | import org.springframework.http.HttpStatus 9 | import org.springframework.web.bind.annotation.* 10 | 11 | @RestController 12 | @RequestMapping("/club/{clubSeq}/board/{clubBoardSeq}/like") 13 | class ClubBoardLikeController( 14 | private val clubBoardLikeService: ClubBoardLikeService 15 | ) { 16 | @PostMapping 17 | @ResponseStatus(HttpStatus.CREATED) 18 | fun registerClubBoardLike(@AuthUser user: User, 19 | @PathVariable clubSeq: Long, 20 | @PathVariable clubBoardSeq: Long): ResponseDto { 21 | 22 | return ResponseDto(data = clubBoardLikeService.registerClubBoardLike(user, clubSeq, clubBoardSeq)) 23 | } 24 | 25 | @DeleteMapping 26 | fun deleteClubBoardLike(@AuthUser user: User, 27 | @PathVariable clubSeq: Long, 28 | @PathVariable clubBoardSeq: Long): ResponseDto { 29 | 30 | return ResponseDto(data = clubBoardLikeService.removeClubBoardLike(user, clubSeq, clubBoardSeq)) 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/controller/region/RegionController.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.controller.region 2 | 3 | import com.taskforce.superinvention.app.domain.region.RegionService 4 | import com.taskforce.superinvention.app.web.common.response.ResponseDto 5 | import com.taskforce.superinvention.app.web.dto.region.RegionDto 6 | import org.springframework.web.bind.annotation.GetMapping 7 | import org.springframework.web.bind.annotation.RestController 8 | 9 | @RestController 10 | class RegionController( 11 | val regionService: RegionService 12 | ) { 13 | 14 | @GetMapping("/regions") 15 | fun getAllRegionList(): ResponseDto> { 16 | val findByLevel = regionService.findAllRegionDtoList() 17 | return ResponseDto(data = findByLevel) 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/controller/user/UserInterestController.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.controller.user 2 | 3 | import com.taskforce.superinvention.app.domain.role.Role 4 | import com.taskforce.superinvention.app.domain.user.User 5 | import com.taskforce.superinvention.app.domain.user.userInterest.UserInterestService 6 | import com.taskforce.superinvention.app.web.common.response.ResponseDto 7 | import com.taskforce.superinvention.app.web.dto.interest.InterestRequestDto 8 | import com.taskforce.superinvention.app.web.dto.interest.UserInterestDto 9 | import com.taskforce.superinvention.common.config.argument.resolver.auth.AuthUser 10 | import org.springframework.security.access.annotation.Secured 11 | import org.springframework.web.bind.annotation.* 12 | 13 | @RestController 14 | @RequestMapping("/users/interests") 15 | class UserInterestController( 16 | private val userInterestService: UserInterestService 17 | ) { 18 | @Secured(Role.MEMBER) 19 | @GetMapping 20 | fun getUserInterestList(@AuthUser user: User): ResponseDto { 21 | val findUserInterest: UserInterestDto = userInterestService.findUserInterest(user) 22 | return ResponseDto(data = findUserInterest) 23 | } 24 | 25 | @Secured(Role.MEMBER) 26 | @PutMapping 27 | fun changeUserInterest(@AuthUser user: User, 28 | @RequestBody interestRequestDto: List): ResponseDto { 29 | return ResponseDto(data = userInterestService.changeUserInterest(user, interestRequestDto)) 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/controller/user/UserRegionController.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.controller.user 2 | 3 | import com.taskforce.superinvention.app.domain.role.Role 4 | import com.taskforce.superinvention.app.domain.user.User 5 | import com.taskforce.superinvention.app.domain.user.userRegion.UserRegionService 6 | import com.taskforce.superinvention.app.web.common.response.ResponseDto 7 | import com.taskforce.superinvention.app.web.dto.region.RegionRequestDto 8 | import com.taskforce.superinvention.app.web.dto.user.UserRegionDto 9 | import com.taskforce.superinvention.common.config.argument.resolver.auth.AuthUser 10 | import org.springframework.security.access.annotation.Secured 11 | import org.springframework.web.bind.annotation.* 12 | 13 | @RestController 14 | @RequestMapping("/users/regions") 15 | class UserRegionController( 16 | private val userRegionService: UserRegionService 17 | ) { 18 | 19 | @Secured(Role.NONE, Role.MEMBER) 20 | @GetMapping 21 | fun getUserRegionList(@AuthUser user: User): ResponseDto { 22 | val findUserRegionList = userRegionService.findUserRegionList(user) 23 | return ResponseDto(data = findUserRegionList) 24 | } 25 | 26 | @Secured(Role.NONE, Role.MEMBER) 27 | @PutMapping 28 | fun changeUserRegion(@AuthUser user: User, 29 | @RequestBody regionRequestDto: List): ResponseDto { 30 | 31 | return ResponseDto(data = userRegionService.changeUserRegion(user, regionRequestDto)) 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/club/ClubAddRequestDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.club 2 | 3 | import com.taskforce.superinvention.app.web.dto.interest.InterestRequestDto 4 | import com.taskforce.superinvention.app.web.dto.region.RegionRequestDto 5 | import com.taskforce.superinvention.common.util.aws.s3.S3Path 6 | import javax.validation.constraints.Min 7 | import javax.validation.constraints.NotBlank 8 | import javax.validation.constraints.NotEmpty 9 | 10 | class ClubAddRequestDto( 11 | @get:NotBlank(message = "모임 명을 입력해주세요") 12 | var name: String, 13 | @get:NotBlank(message = "모임 설명을 작성해주세요") 14 | var description: String, 15 | 16 | @get:Min(value = 2, message = "최소 인원은 2명 이상이어야 합니다") 17 | var maximumNumber: Long, 18 | 19 | var img: S3Path?, 20 | 21 | @get:NotEmpty(message = "모임 관심사를 하나 이상 선택해주세요") 22 | var interestList: List, 23 | 24 | @get:NotEmpty(message = "모임 지역을 하나 이상 선택해주세요") 25 | var regionList: List 26 | ) 27 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/club/ClubSearchRequestDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.club 2 | 3 | class ClubSearchRequestDto { 4 | var regionSeq: Long? = null 5 | var interestSeq: Long? = null 6 | var interestGroupSeq: Long? = null 7 | var text: String? = null 8 | 9 | constructor(regionSeq: Long?, interestSeq: Long?, interestGroupSeq: Long?, query: String?) { 10 | this.regionSeq = regionSeq 11 | this.interestSeq = interestSeq 12 | this.interestGroupSeq = interestGroupSeq 13 | this.text = query 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/club/album/like/ClubAlbumLikeDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.club.album.like 2 | 3 | data class ClubAlbumLikeDto( 4 | val clubSeq: Long, 5 | val clubAlbumSeq: Long, 6 | val likeCnt: Long 7 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/club/board/img/ClubBoardImgDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.club.board.img 2 | 3 | import com.taskforce.superinvention.common.util.aws.s3.S3Path 4 | 5 | data class ClubBoardImgEditS3Path ( 6 | val imgSeq: Long?, 7 | val img: S3Path 8 | ) 9 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/club/board/like/ClubBoardLikeDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.club.board.like 2 | 3 | data class ClubBoardLikeDto( 4 | val clubSeq: Long, 5 | val clubBoardSeq: Long, 6 | val likeCnt: Long 7 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/common/PageDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.common 2 | 3 | import org.springframework.data.domain.Page 4 | 5 | data class PageDto( 6 | val pageable : PageableDto, 7 | val content : List, 8 | val last : Boolean, 9 | val size : Int, 10 | val totalPages: Int 11 | ) { 12 | constructor(page : Page) : this( 13 | content = page.content, 14 | pageable = PageableDto(page), 15 | last = page.isLast, 16 | size = page.size, 17 | totalPages = page.totalPages 18 | ) 19 | } 20 | 21 | data class PageableDto ( 22 | val pageNumber : Int 23 | ) { 24 | constructor(page: Page): this ( 25 | pageNumber = page.pageable.pageNumber 26 | ) 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/common/image/ResizeDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.common.image 2 | 3 | data class ResizeDto( 4 | val width : Long ? = null, 5 | val height: Long ? = null 6 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/interest/InterestRequestDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.interest 2 | 3 | class InterestRequestDto( 4 | val seq: Long, 5 | val priority: Long 6 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/interest/InterestWithPriorityDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.interest 2 | 3 | import com.taskforce.superinvention.app.domain.interest.ClubInterest 4 | import com.taskforce.superinvention.app.domain.interest.interest.InterestDto 5 | import com.taskforce.superinvention.app.domain.user.userInterest.UserInterest 6 | 7 | data class InterestWithPriorityDto( 8 | val interest: InterestDto, 9 | val priority: Long 10 | ) { 11 | constructor(clubInterest: ClubInterest): this(InterestDto(clubInterest.interest), clubInterest.priority) 12 | constructor(userInterest: UserInterest): this(InterestDto(userInterest.interest), userInterest.priority) 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/interest/UserInterestDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.interest 2 | 3 | class UserInterestDto( 4 | val userSeq: Long, 5 | val userId: String?, 6 | val interestList: List 7 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/kakao/kakaoDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.kakao 2 | 3 | import com.taskforce.superinvention.app.web.dto.interest.InterestRequestDto 4 | import com.taskforce.superinvention.app.web.dto.region.RegionRequestDto 5 | import java.time.LocalDate 6 | 7 | data class KakaoToken ( 8 | val token_type : String? = "", 9 | val access_token : String? = "", 10 | val expires_in : Int? = 0, 11 | val refresh_token: String? = "", 12 | val refresh_token_expires_in: Int? = 0 13 | ) 14 | 15 | data class KakaoOAuthResponse ( 16 | val msg: String, 17 | val code: Int 18 | ) 19 | 20 | data class KakaoUserInfo ( 21 | val id: String, 22 | val properties: KakaoUserProperties, 23 | val kakao_account: KakaoUserAccount 24 | ) 25 | 26 | data class KakaoUserRegistRequest ( 27 | val userName: String?, 28 | val birthday: LocalDate?, 29 | val profileImageLink: String?, 30 | val userRegions: List, 31 | val userInterests: List 32 | ) 33 | 34 | data class KakaoUserProperties ( 35 | val nickname: String, 36 | val profile_image: String = "", 37 | val thumbnail_image: String = "" 38 | ) 39 | 40 | data class KakaoUserAccount ( 41 | val profile_needs_agreement: Boolean, 42 | val profile: KakaoUserProfile, 43 | val hasGender: Boolean, 44 | val gender_needs_agreement: Boolean 45 | ) 46 | 47 | data class KakaoUserProfile( 48 | val nickname: String, 49 | val profile_image_url: String = "", 50 | val thumbnail_image_url: String = "" 51 | ) 52 | 53 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/region/RegionDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.region 2 | 3 | import com.taskforce.superinvention.app.domain.region.Region 4 | import kotlin.streams.toList 5 | 6 | 7 | class RegionDto { 8 | var seq: Long? 9 | var name: String 10 | var superRegionRoot: String 11 | var level: Long 12 | var subRegions: List 13 | 14 | constructor( 15 | seq: Long?, 16 | name: String, 17 | superRegionRoot: String, 18 | level: Long, 19 | subRegions: List 20 | ) { 21 | this.seq = seq 22 | this.name = name 23 | this.superRegionRoot = superRegionRoot 24 | this.level = level 25 | this.subRegions = subRegions 26 | } 27 | } 28 | 29 | 30 | fun of(region: Region, findDepth: Long): RegionDto 31 | { 32 | return RegionDto( 33 | seq = region.seq, 34 | name = region.name, 35 | superRegionRoot = region.superRegionRoot, 36 | level = region.level, 37 | subRegions = if (findDepth > 0) region.subRegions.map { e -> of(e, findDepth - 1) }.toList() else emptyList() 38 | ) 39 | } 40 | 41 | 42 | fun of(region: Region, subRegions: List): RegionDto 43 | { 44 | return RegionDto( 45 | seq = region.seq, 46 | name = region.name, 47 | superRegionRoot = region.superRegionRoot, 48 | level = region.level, 49 | subRegions = subRegions.map { 50 | RegionDto( 51 | seq = it.seq, 52 | name = it.name, 53 | superRegionRoot = it.superRegionRoot, 54 | level = it.level, 55 | subRegions = emptyList() 56 | ) } 57 | ) 58 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/region/RegionRequestDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.region 2 | 3 | class RegionRequestDto( 4 | var seq: Long, 5 | var priority: Long 6 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/region/RegionWithPriorityDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.region 2 | 3 | import com.taskforce.superinvention.app.domain.region.ClubRegion 4 | 5 | class RegionWithPriorityDto( 6 | val region: SimpleRegionDto, 7 | val priority: Long 8 | ) { 9 | constructor(clubRegion: ClubRegion): this(SimpleRegionDto(clubRegion.region), clubRegion.priority) 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/region/SimpleRegionDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.region 2 | 3 | import com.taskforce.superinvention.app.domain.region.ClubRegion 4 | import com.taskforce.superinvention.app.domain.region.Region 5 | 6 | class SimpleRegionDto( 7 | val seq: Long, 8 | val name: String, 9 | val superRegionRoot: String, 10 | val level: Long 11 | ) { 12 | 13 | 14 | constructor(region: Region): this(region.seq!!, region.name, region.superRegionRoot, region.level) 15 | 16 | constructor(clubRegion: ClubRegion): 17 | this( 18 | clubRegion.region.seq!!, 19 | clubRegion.region.name, 20 | clubRegion.region.superRegionRoot, 21 | clubRegion.region.level 22 | ) 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/role/RoleDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.role 2 | 3 | import com.taskforce.superinvention.app.domain.role.Role 4 | 5 | data class RoleDto ( 6 | var name: Role.RoleName, 7 | var roleGroupName: String 8 | ) { 9 | constructor(role: Role) : 10 | this( 11 | name = role.name, 12 | roleGroupName = role.roleGroup.name 13 | ) 14 | 15 | constructor(nameStr: String, roleGroupName: String) : 16 | this( 17 | name = Role.fromRoleName(nameStr), 18 | roleGroupName = roleGroupName 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/user/UserDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.user 2 | 3 | import com.taskforce.superinvention.app.domain.user.User 4 | import com.taskforce.superinvention.app.domain.user.UserType 5 | import com.taskforce.superinvention.app.domain.user.userRole.UserRole 6 | import com.taskforce.superinvention.app.web.dto.role.RoleDto 7 | import com.taskforce.superinvention.common.util.extendFun.toBaseDate 8 | import java.time.LocalDate 9 | import javax.persistence.OneToMany 10 | 11 | data class UserMemberCheckDto( 12 | val isMember: Boolean 13 | ) 14 | 15 | data class UserDto( 16 | var seq: Long, 17 | var userRoles: Set, 18 | var userName: String?, 19 | var birthday: String?, 20 | var profileImageLink: String? 21 | ) { 22 | constructor(user: User): this( 23 | seq = user.seq!!, 24 | userRoles = user.userRoles.map { it.roleName }.toSet(), 25 | userName = user.userName, 26 | birthday = user.birthday?.toBaseDate(), 27 | profileImageLink = user.profileImageLink 28 | ) 29 | } 30 | 31 | data class UserIdAndNameDto( 32 | var seq: Long, 33 | var userName: String 34 | ) { 35 | constructor(user: User): this(user.seq!!, user.userName!!) 36 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/user/UserProfileUpdateDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.user 2 | 3 | import com.taskforce.superinvention.common.util.aws.s3.S3Path 4 | 5 | data class UserProfileUpdateDto ( 6 | val profileImage: S3Path 7 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/user/UserRegionDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.user 2 | 3 | import com.taskforce.superinvention.app.domain.user.User 4 | import com.taskforce.superinvention.app.web.dto.region.RegionWithPriorityDto 5 | 6 | class UserRegionDto(user: User, regions: List) { 7 | val userSeq: Long? 8 | val userId: String? 9 | val userRegions: List 10 | 11 | init { 12 | this.userSeq = user.seq 13 | this.userId = user.userId 14 | this.userRegions = regions 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/user/info/UserInfoDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.user.info 2 | 3 | import com.taskforce.superinvention.app.domain.user.User 4 | import com.taskforce.superinvention.common.util.extendFun.toBaseDate 5 | 6 | data class UserInfoDto( 7 | val seq: Long, 8 | val userName: String = "", 9 | val birthday: String = "", 10 | val profileImageLink: String = "", 11 | val userRegions : List = emptyList(), 12 | val userInterests: List = emptyList() 13 | ) { 14 | constructor(user: User, userRegions: List, userInfoInterests: List): this( 15 | seq = user.seq!!, 16 | userName = user.userName ?: "", 17 | birthday = user.birthday?.toBaseDate() ?: "", 18 | profileImageLink = user.profileImageLink ?: "", 19 | userRegions = userRegions, 20 | userInterests = userInfoInterests 21 | ) 22 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/user/info/UserInfoInterestDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.user.info 2 | 3 | import com.taskforce.superinvention.app.domain.interest.interestGroup.InterestGroup 4 | import com.taskforce.superinvention.app.domain.user.userInterest.UserInterest 5 | 6 | 7 | data class UserInfoInterestDto ( 8 | val interest: UserInfoInterestItem, 9 | val priority: Long 10 | ) { 11 | constructor(userInterest: UserInterest): 12 | this( 13 | interest = UserInfoInterestItem(userInterest), 14 | priority = userInterest.priority 15 | ) 16 | } 17 | 18 | data class UserInfoInterestItem ( 19 | val seq : Long, 20 | val name: String = "", 21 | val interestGroup: UserInfoInterestGroupDto 22 | ) { 23 | constructor(userInterest: UserInterest): 24 | this( 25 | seq = userInterest.seq!!, 26 | name = userInterest.interest.name, 27 | interestGroup = UserInfoInterestGroupDto(userInterest.interest.interestGroup) 28 | ) 29 | } 30 | 31 | data class UserInfoInterestGroupDto ( 32 | val seq : Long, 33 | val name: String 34 | ) { 35 | constructor(interestGroup: InterestGroup) : 36 | this( 37 | seq = interestGroup.seq!!, 38 | name= interestGroup.name 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/app/web/dto/user/info/UserInfoRegionDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.web.dto.user.info 2 | 3 | import com.taskforce.superinvention.app.web.dto.region.SimpleRegionDto 4 | 5 | data class UserInfoRegionDto ( 6 | val region : SimpleRegionDto, 7 | val priority: Long 8 | ) { 9 | constructor(priority: Long, simpleRegionDto: SimpleRegionDto): this ( 10 | region = simpleRegionDto, 11 | priority = priority 12 | ) 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/advice/AdviceDto.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.advice 2 | 3 | 4 | data class ErrorResponse( 5 | val message: String, 6 | val stackTrace: String = "" 7 | ) { 8 | companion object { 9 | const val defaultMessage = "서버에 에러가 발생하였습니다" 10 | fun sliceArrayAndJoin(arr: Array<*>): String { 11 | return arr.sliceArray(0..20).joinToString (separator = "\n"){ it.toString() } 12 | } 13 | } 14 | 15 | constructor(message: String, stackTrace: Array) : 16 | this(message, sliceArrayAndJoin(stackTrace)) 17 | 18 | constructor(stackTrace: Array): 19 | this(defaultMessage, sliceArrayAndJoin(stackTrace)) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/advice/GlobalSecurityExceptionHandler.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.advice 2 | 3 | import com.taskforce.superinvention.common.util.kakao.KakaoOAuth 4 | import org.slf4j.Logger 5 | import org.slf4j.LoggerFactory 6 | import org.springframework.http.HttpStatus 7 | import org.springframework.http.ResponseEntity 8 | import org.springframework.security.access.AccessDeniedException 9 | import org.springframework.web.bind.annotation.ExceptionHandler 10 | import org.springframework.web.bind.annotation.RestControllerAdvice 11 | 12 | @RestControllerAdvice 13 | class GlobalControllerExceptionHandler { 14 | 15 | companion object { 16 | val LOG: Logger = LoggerFactory.getLogger(KakaoOAuth::class.java) 17 | } 18 | 19 | @ExceptionHandler(AccessDeniedException::class) 20 | fun forbiddenWithNoAuthException(e: AccessDeniedException) : ResponseEntity { 21 | LOG.error(e.message) 22 | return ResponseEntity( 23 | ErrorResponse("접근 권한이 없습니다.", e.stackTrace), 24 | HttpStatus.INTERNAL_SERVER_ERROR 25 | ) 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/WebMvcConfig.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config 2 | 3 | import com.taskforce.superinvention.common.config.argument.converter.ClubBoardCategoryConverter 4 | import com.taskforce.superinvention.common.config.argument.resolver.auth.AuthorizeArgumentResolver 5 | import org.springframework.context.annotation.Configuration 6 | import org.springframework.data.web.PageableHandlerMethodArgumentResolver 7 | import org.springframework.format.FormatterRegistry 8 | import org.springframework.web.method.support.HandlerMethodArgumentResolver 9 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry 10 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport 11 | 12 | @Configuration 13 | class WebMvcConfig( 14 | private val authorizeArgumentResolver: AuthorizeArgumentResolver 15 | ): WebMvcConfigurationSupport() { 16 | 17 | override fun addResourceHandlers(registry: ResourceHandlerRegistry) { 18 | registry.addResourceHandler("/docs/**") 19 | .addResourceLocations("classpath:/static/docs/") 20 | } 21 | 22 | override fun addArgumentResolvers(argumentResolvers: MutableList) { 23 | argumentResolvers.add(authorizeArgumentResolver) 24 | argumentResolvers.add(PageableHandlerMethodArgumentResolver()); 25 | } 26 | 27 | override fun addFormatters(registry: FormatterRegistry) { 28 | registry.addConverter(ClubBoardCategoryConverter()) 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/argument/converter/ClubBoardCategoryConverter.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.argument.converter 2 | 3 | import com.taskforce.superinvention.app.domain.club.board.ClubBoard 4 | import com.taskforce.superinvention.common.exception.InvalidInputException 5 | import org.springframework.core.convert.converter.Converter 6 | 7 | class ClubBoardCategoryConverter: Converter { 8 | 9 | override fun convert(source: String): ClubBoard.Category { 10 | return ClubBoard.Category.fromCategoryLabel(source) 11 | ?: throw InvalidInputException(message = "해당 카테고리로를 검색할 수 없습니다.") 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/argument/resolver/auth/AuthorizeArgumentResolver.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.argument.resolver.auth 2 | 3 | import com.taskforce.superinvention.app.domain.user.User 4 | import com.taskforce.superinvention.app.domain.user.UserRepository 5 | import com.taskforce.superinvention.common.exception.auth.UserNotFoundException 6 | import org.springframework.core.MethodParameter 7 | import org.springframework.security.core.Authentication 8 | import org.springframework.security.core.context.SecurityContextHolder 9 | import org.springframework.stereotype.Component 10 | import org.springframework.web.bind.support.WebDataBinderFactory 11 | import org.springframework.web.context.request.NativeWebRequest 12 | import org.springframework.web.method.support.HandlerMethodArgumentResolver 13 | import org.springframework.web.method.support.ModelAndViewContainer 14 | 15 | annotation class AuthUser( 16 | val allowAnonymous: Boolean = true 17 | ) 18 | 19 | @Component 20 | class AuthorizeArgumentResolver( 21 | val userRepository: UserRepository 22 | ): HandlerMethodArgumentResolver { 23 | 24 | override fun supportsParameter(parameter: MethodParameter): Boolean { 25 | return parameter.hasParameterAnnotation(AuthUser::class.java) 26 | } 27 | 28 | override fun resolveArgument(parameter: MethodParameter, mavContainer: ModelAndViewContainer?, webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory?): User? { 29 | val authUser = parameter.parameter.getAnnotation(AuthUser::class.java) 30 | 31 | val authentication: Authentication = SecurityContextHolder.getContext().authentication 32 | val userId = authentication.name 33 | 34 | val userEntity: User? = userRepository.findByUserId(userId) 35 | 36 | if(!authUser.allowAnonymous && userEntity == null) { 37 | throw UserNotFoundException() 38 | } 39 | 40 | return userEntity 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/async/AsyncConfig.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.async 2 | 3 | import org.springframework.context.annotation.Bean 4 | import org.springframework.context.annotation.Configuration 5 | import org.springframework.scheduling.annotation.EnableAsync 6 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor 7 | import java.util.concurrent.Executor 8 | 9 | @Configuration 10 | @EnableAsync 11 | class AsyncConfig { 12 | 13 | companion object { 14 | const val WEBP_CONVERSION = "webpConversion" 15 | } 16 | 17 | @Bean(WEBP_CONVERSION) 18 | fun webpConversionAsyncTaskExecutor(): Executor { 19 | 20 | val threadPoolTaskExecutor = ThreadPoolTaskExecutor() 21 | threadPoolTaskExecutor.corePoolSize = 10 22 | threadPoolTaskExecutor.maxPoolSize = 30 23 | threadPoolTaskExecutor.setThreadNamePrefix("super-invention-webp-conversion") 24 | 25 | return threadPoolTaskExecutor 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/jpa/CriteriaConfig.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.jpa 2 | 3 | import com.blazebit.persistence.Criteria 4 | import com.blazebit.persistence.CriteriaBuilderFactory 5 | import org.springframework.context.annotation.Bean 6 | import org.springframework.context.annotation.Configuration 7 | import javax.persistence.EntityManager 8 | 9 | @Configuration 10 | class CriteriaConfig( 11 | private val entityManager: EntityManager 12 | ) { 13 | 14 | @Bean 15 | fun createCriteriaBuilderFactory() : CriteriaBuilderFactory { 16 | val config = Criteria.getDefault() 17 | return config.createCriteriaBuilderFactory(entityManager.entityManagerFactory) 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/jpa/JpaConfig.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.jpa 2 | 3 | import org.springframework.context.annotation.Bean 4 | import org.springframework.context.annotation.Configuration 5 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing 6 | import org.springframework.orm.jpa.JpaVendorAdapter 7 | import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter 8 | import org.springframework.orm.jpa.vendor.Database 9 | import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter 10 | 11 | 12 | @Configuration 13 | @EnableJpaAuditing 14 | class JpaConfig { 15 | 16 | @Bean 17 | fun jpaVendorAdapter(): JpaVendorAdapter { 18 | val adapter: AbstractJpaVendorAdapter = HibernateJpaVendorAdapter() 19 | adapter.setShowSql(true) 20 | adapter.setDatabase(Database.MYSQL) 21 | adapter.setDatabasePlatform("com.taskforce.superinvention.common.config.jpa.dialect.CustomMysqlDialect") 22 | adapter.setGenerateDdl(false) 23 | return adapter 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/jpa/QueryDslConfig.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.jpa 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory 4 | import org.springframework.context.annotation.Bean 5 | import org.springframework.context.annotation.Configuration 6 | import javax.persistence.EntityManager 7 | 8 | @Configuration 9 | class QueryDslConfig ( 10 | private val entityManager: EntityManager 11 | ) { 12 | 13 | @Bean 14 | fun jpaQueryFactory(): JPAQueryFactory = JPAQueryFactory(entityManager) 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/jpa/dialect/CustomMysqlDialect.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.jpa.dialect 2 | 3 | import org.hibernate.dialect.MySQL8Dialect 4 | import org.hibernate.dialect.function.SQLFunctionTemplate 5 | import org.hibernate.type.StandardBasicTypes 6 | 7 | class CustomMysqlDialect() : MySQL8Dialect() { 8 | 9 | init { 10 | this.registerFunction("group_concat", SQLFunctionTemplate(StandardBasicTypes.STRING, "group_concat(?1)")) 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/security/AppToken.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.security 2 | 3 | data class AppToken( 4 | var isRegistered: Boolean?, 5 | var appToken : String? 6 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/security/FilterChainExceptionHandler.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.security 2 | 3 | import org.springframework.web.filter.OncePerRequestFilter 4 | import java.lang.Exception 5 | import javax.servlet.FilterChain 6 | import javax.servlet.http.HttpServletRequest 7 | import javax.servlet.http.HttpServletResponse 8 | import org.springframework.web.servlet.HandlerExceptionResolver 9 | 10 | import org.springframework.beans.factory.annotation.Autowired 11 | import org.springframework.beans.factory.annotation.Qualifier 12 | import org.springframework.stereotype.Component 13 | 14 | @Component 15 | class FilterChainExceptionHandler : OncePerRequestFilter() { 16 | 17 | @Autowired 18 | @Qualifier("handlerExceptionResolver") 19 | lateinit var resolver: HandlerExceptionResolver 20 | 21 | override fun doFilterInternal( 22 | request: HttpServletRequest, 23 | response: HttpServletResponse, 24 | filterChain: FilterChain 25 | ) { 26 | try { 27 | filterChain.doFilter(request, response) 28 | } catch (e: Exception) { 29 | resolver.resolveException(request, response, null, e) 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/security/JwtTokenFilter.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.security 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.security.core.Authentication 5 | import org.springframework.security.core.context.SecurityContextHolder 6 | import org.springframework.web.filter.OncePerRequestFilter 7 | import javax.servlet.FilterChain 8 | import javax.servlet.http.HttpServletRequest 9 | import javax.servlet.http.HttpServletResponse 10 | 11 | class JwtTokenFilter( 12 | private val jwtTokenProvider: JwtTokenProvider 13 | ) : OncePerRequestFilter() { 14 | 15 | override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) { 16 | val token: String = resolveToken(request) 17 | 18 | try { 19 | if (isTokenValidate(token)) { 20 | val auth: Authentication = jwtTokenProvider.getAuthentication(token) 21 | SecurityContextHolder.getContext().authentication = auth 22 | } 23 | } catch (ex: BizException) { 24 | SecurityContextHolder.clearContext() 25 | response.sendError(ex.httpStatus.value(), ex.message) 26 | return 27 | } 28 | filterChain.doFilter(request, response) 29 | } 30 | 31 | private fun resolveToken(req: HttpServletRequest): String { 32 | val bearerToken = req.getHeader(JwtTokenProvider.TOKEN_HEADER) 33 | return if (bearerToken != null && bearerToken.startsWith("Bearer ")) { 34 | bearerToken.substring(7) 35 | } else "" 36 | } 37 | 38 | private fun isTokenValidate(token: String): Boolean { 39 | if(token.isBlank()) { 40 | return false 41 | } 42 | 43 | if(jwtTokenProvider.validateToken(token)) { 44 | return true 45 | } 46 | return false 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/security/JwtTokenFilterConfigurer.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.security 2 | 3 | import org.springframework.security.config.annotation.SecurityConfigurerAdapter 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity 5 | import org.springframework.security.web.DefaultSecurityFilterChain 6 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter 7 | 8 | class JwtTokenFilterConfigurer( 9 | private val jwtTokenProvider: JwtTokenProvider 10 | ) : SecurityConfigurerAdapter() { 11 | 12 | override fun configure(http: HttpSecurity) { 13 | val customFilter = JwtTokenFilter(jwtTokenProvider) 14 | http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter::class.java) 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/web/resttemplate/RestTemplateConfig.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.web.resttemplate 2 | 3 | import org.apache.http.client.HttpClient 4 | import org.apache.http.impl.client.HttpClientBuilder 5 | import org.springframework.context.annotation.Bean 6 | import org.springframework.context.annotation.Configuration 7 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory 8 | import org.springframework.web.client.RestTemplate 9 | 10 | @Configuration 11 | class RestTemplateConfig { 12 | 13 | @Bean 14 | fun restTemplate(): RestTemplate { 15 | val factory = HttpComponentsClientHttpRequestFactory() 16 | val httpClient: HttpClient = HttpClientBuilder.create() 17 | .setMaxConnTotal(50) 18 | .setMaxConnPerRoute(30) 19 | .build() 20 | 21 | factory.httpClient = httpClient 22 | factory.setConnectTimeout(2000) 23 | factory.setReadTimeout(2000) 24 | 25 | return RestTemplate(factory) 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/config/web/resttemplate/kakao/KakaoAuthResponseErrorHandler.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.config.web.resttemplate.kakao 2 | 3 | import org.slf4j.Logger 4 | import org.slf4j.LoggerFactory 5 | import org.springframework.http.HttpStatus.Series.* 6 | import org.springframework.http.client.ClientHttpResponse 7 | import org.springframework.stereotype.Component 8 | import org.springframework.web.client.ResponseErrorHandler 9 | 10 | @Component 11 | class KakaoAuthResponseErrorHandler: ResponseErrorHandler { 12 | 13 | companion object { 14 | val LOG: Logger = LoggerFactory.getLogger(KakaoAuthResponseErrorHandler::class.java) 15 | } 16 | 17 | override fun hasError(response: ClientHttpResponse): Boolean { 18 | return ( 19 | response.statusCode.series() == CLIENT_ERROR // 400 번대 20 | || response.statusCode.series() == SERVER_ERROR // 500 번대 21 | ) 22 | } 23 | 24 | override fun handleError(response: ClientHttpResponse) { 25 | val msg = "${response.statusCode}\n${response.rawStatusCode}\n${response.statusText}" 26 | LOG.error(msg) 27 | 28 | when(response.statusCode.series()) { 29 | SERVER_ERROR -> {} 30 | CLIENT_ERROR -> {} 31 | else -> { 32 | LOG.error("알 수 없는 에러입니다.") 33 | throw Exception() 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/BizException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception 2 | 3 | import org.springframework.http.HttpStatus 4 | 5 | open class BizException( 6 | override val message: String, 7 | val httpStatus: HttpStatus 8 | ) : RuntimeException() { 9 | 10 | companion object { 11 | private const val serialVersionUID = 1L 12 | } 13 | 14 | constructor(message: String) : this(message, HttpStatus.INTERNAL_SERVER_ERROR) 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/InvalidInputException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception 2 | 3 | import org.springframework.http.HttpStatus 4 | 5 | class InvalidInputException( 6 | message: String, 7 | httpStatus: HttpStatus 8 | ) : BizException(message, httpStatus) { 9 | constructor(message: String): this(message, HttpStatus.BAD_REQUEST) 10 | constructor(): this("입력값이 올바르지않습니다.", HttpStatus.BAD_REQUEST) 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/ResourceNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class ResourceNotFoundException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | constructor(message: String): this(message, HttpStatus.NO_CONTENT) 11 | constructor(): this("해당 자원이 존재하지 않습니다.", HttpStatus.NO_CONTENT) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/auth/AccessTokenExpiredException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.auth 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class AccessTokenExpiredException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/auth/InsufficientAuthException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.auth 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | open class InsufficientAuthException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | constructor(): this( 11 | message = "권한이 충분하지 않습니다.", 12 | httpStatus = HttpStatus.FORBIDDEN 13 | ) 14 | 15 | constructor(message: String): this( 16 | message = message, 17 | httpStatus = HttpStatus.FORBIDDEN 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/auth/OnlyWriterCanAccessException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.auth 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class OnlyWriterCanAccessException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | constructor(message: String): this(message, HttpStatus.FORBIDDEN) 11 | constructor(): this("오직 해당 자원의 작성자만 자원에 접근할 수 있습니다.", HttpStatus.FORBIDDEN) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/auth/UserNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.auth 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class UserNotFoundException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | 11 | constructor(): this("해당 유저를 찾을 수 없습니다.", HttpStatus.UNAUTHORIZED) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/auth/WithdrawClubUserNotAllowedException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.auth 2 | 3 | class WithdrawClubUserNotAllowedException( 4 | message: String, 5 | ): InsufficientAuthException(message) { 6 | constructor(): this( 7 | message = "탈퇴한 모임에서는 사용할 수 없는 기능입니다.", 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/club/CannotJoinClubException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.club 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class CannotJoinClubException(message: String, 7 | httpStatus: HttpStatus 8 | ) : BizException(message, httpStatus) { 9 | 10 | constructor(): this("모임에 가입하실 수 없습니다.", HttpStatus.FORBIDDEN) 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/club/ClubNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.club 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class ClubNotFoundException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | 11 | constructor(): this("해당 모임은 존재하지 않습니다.", HttpStatus.BAD_REQUEST) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/club/UserIsNotClubMemberException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.club 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class UserIsNotClubMemberException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | constructor(): this("해당 유저는 모임원이 아닙니다.", HttpStatus.FORBIDDEN) 11 | 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/club/album/ClubAlbumNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.club.album 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class ClubAlbumNotFoundException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | 11 | constructor(): this("해당 사진은 모임 사진첩에 존재하지 않습니다..", HttpStatus.BAD_REQUEST) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/club/album/NoAuthForClubAlbumException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.club.album 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class NoAuthForClubAlbumException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | 11 | constructor(): this(""" 12 | |해당 모임 사진첩 사진에 대한 권한이 없습니다. 13 | |매니저, 마스터 그리고 사진 등록자만 요청할 수 있습니다. 14 | """.trimMargin(), HttpStatus.FORBIDDEN) 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/club/board/ClubBoardNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.club.board 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class ClubBoardNotFoundException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | 11 | constructor(): this("해당 게시글은 존재하지 않습니다..", HttpStatus.BAD_REQUEST) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/club/meeting/MeetingAlreadyApplicationException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.club.meeting 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class MeetingAlreadyApplicationException(message: String) : BizException(message, HttpStatus.CONFLICT) { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/club/meeting/MeetingIsClosedException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.club.meeting 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class MeetingIsClosedException(message: String) : BizException(message, HttpStatus.CONFLICT) { 7 | constructor(): this("이미 종료된 만남입니다") 8 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/club/meeting/MeetingMemberOverflowException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.club.meeting 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class MeetingMemberOverflowException(message: String) : BizException(message, HttpStatus.CONFLICT) { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/common/ImplementationIsNotSupported.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.common 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class ImplementationIsNotSupported( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | 11 | constructor(): this("해당 요청은 사용될 수 없습니다. (구현체 없음)", HttpStatus.BAD_REQUEST) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/exception/common/IsAlreadyDeletedException.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.exception.common 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import org.springframework.http.HttpStatus 5 | 6 | class IsAlreadyDeletedException( 7 | message: String, 8 | httpStatus: HttpStatus 9 | ) : BizException(message, httpStatus) { 10 | 11 | constructor(): this("해당 자원은 이미 삭제되었습니다.", HttpStatus.BAD_REQUEST) 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/util/aws/s3/S3Path.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.util.aws.s3 2 | 3 | data class S3Path ( 4 | var absolutePath: String = "", 5 | var filePath : String = "", 6 | var fileName : String = "" 7 | ) { 8 | fun folderPath(): String { 9 | return filePath.replace("/${fileName}", "") 10 | } 11 | } 12 | 13 | fun S3Path.isValidPath(): Boolean { 14 | return this.absolutePath.isNotBlank() && 15 | this.filePath.isNotBlank() && 16 | this.fileName.isNotBlank() 17 | } 18 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/util/extendFun/LocalDateExtension.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.util.extendFun 2 | 3 | import com.taskforce.superinvention.common.exception.BizException 4 | import java.time.DayOfWeek 5 | import java.time.LocalDate 6 | import java.time.LocalDateTime 7 | import java.time.LocalTime 8 | import java.time.format.DateTimeFormatter 9 | 10 | const val DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss" 11 | const val DATE_FORMAT = "yyyy-MM-dd" 12 | const val DATE_FORMAT_KOR = "yyyy년 MM월 dd일" 13 | const val TIME_FORMAT = "HH:mm" 14 | const val YEAR_MONTH_KOR = "yyyy년 MM월" 15 | 16 | fun LocalDate.toBaseDate(): String { 17 | 18 | return this.format(DateTimeFormatter.ofPattern(DATE_FORMAT)) 19 | } 20 | 21 | fun LocalDateTime.toBaseDateTime(): String { 22 | return this.format(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)) 23 | } 24 | 25 | fun LocalDate.toKorDate(): String { 26 | return this.format(DateTimeFormatter.ofPattern(DATE_FORMAT_KOR)) 27 | } 28 | 29 | fun LocalTime.toBaseTime(): String { 30 | return this.format(DateTimeFormatter.ofPattern(TIME_FORMAT)) 31 | } 32 | 33 | fun DayOfWeek.getKorDisplayName(): String { 34 | return when(this.value) { 35 | 1 -> "월요일" 36 | 2 -> "화요일" 37 | 3 -> "수요일" 38 | 4 -> "목요일" 39 | 5 -> "금요일" 40 | 6 -> "토요일" 41 | 7 -> "일요일" 42 | else -> throw BizException("존재하지 않는 요일데이터입니다") 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/util/extendFun/StringExtension.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.util.extendFun 2 | 3 | fun String.sliceIfExceed(range: IntRange): String { 4 | return if(this.length > range.last) { 5 | this.slice(range) 6 | } else { 7 | this 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/util/file/FileMo.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.util.file 2 | 3 | import org.apache.tomcat.util.http.fileupload.FileUtils 4 | import org.springframework.web.multipart.MultipartFile 5 | import java.io.File 6 | import java.io.FileOutputStream 7 | import java.time.LocalDateTime 8 | import java.time.format.DateTimeFormatter 9 | import java.util.* 10 | 11 | class FileMo { 12 | companion object { 13 | 14 | fun convertMultiPartToFile(file: MultipartFile): File { 15 | val convertedFile = File(file.originalFilename!!) 16 | val fos = FileOutputStream(convertedFile) 17 | fos.write(file.bytes) 18 | fos.close() 19 | return convertedFile 20 | } 21 | 22 | fun generateUUID(multiPart: MultipartFile): String { 23 | val datetimeStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddhhmmss")) 24 | 25 | val uuid = "${datetimeStr}-${UUID.randomUUID()}" 26 | val fileName = multiPart.originalFilename!!.replace(" ".toRegex(), "-") 27 | 28 | return "${uuid}-${fileName}" 29 | } 30 | 31 | fun generateUUID(file: File): String { 32 | val datetimeStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddhhmmss")) 33 | 34 | val uuid = "${datetimeStr}-${UUID.randomUUID()}" 35 | val fileName = file.name.replace(" ".toRegex(), "-") 36 | 37 | return "${uuid}-${fileName}" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/taskforce/superinvention/common/util/file/image/gif/GifMo.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.util.file.image.gif 2 | 3 | import com.drew.imaging.ImageMetadataReader 4 | import com.drew.metadata.Metadata 5 | import com.drew.metadata.gif.GifControlDirectory 6 | import java.io.ByteArrayInputStream 7 | 8 | class GifMo { 9 | companion object { 10 | fun isAnimated(metadata: Metadata): Boolean { 11 | val controlDirectories = metadata.getDirectoriesOfType(GifControlDirectory::class.java) as List<*> 12 | 13 | return controlDirectories.size > 1 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.driverClassName=org.mariadb.jdbc.Driver 3 | 4 | # JPA 5 | spring.jpa.database-platform=org.hibernate.dialect.MariaDB103Dialect 6 | spring.jpa.properties.hibernate.show_sql=true 7 | spring.jpa.hibernate.ddl-auto=none 8 | spring.jpa.properties.hibernate.jdbc.batch_size=100 9 | spring.jpa.properties.hibernate.order_inserts=true 10 | 11 | 12 | 13 | # Security 14 | security.jwt.token.expireMinuit=5 15 | 16 | logging.level.root=info 17 | 18 | # AWS 19 | aws.s3.bucketName=super-invention-static 20 | 21 | # ETC -------------------------------------------------------------------------------- /src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.driverClassName=org.mariadb.jdbc.Driver 3 | 4 | # JPA 5 | spring.jpa.database-platform=org.hibernate.dialect.MariaDB103Dialect 6 | spring.jpa.properties.hibernate.show_sql=true 7 | spring.jpa.hibernate.ddl-auto=none 8 | spring.jpa.properties.hibernate.jdbc.batch_size=100 9 | spring.jpa.properties.hibernate.order_inserts=true 10 | 11 | 12 | logging.level.root=info 13 | 14 | # AWS 15 | aws.s3.bucketName=super-invention-static 16 | 17 | # ETC -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=dev,dev-secret 2 | 3 | spring.data.redis.repositories.enabled = false 4 | spring.servlet.multipart.max-file-size=50MB 5 | spring.servlet.multipart.max-request-size=50MB -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ███████╗██╗ ██╗██████╗ ███████╗██████╗ ██╗███╗ ██╗██╗ ██╗███████╗███╗ ██╗████████╗██╗ ██████╗ ███╗ ██╗ 2 | ██╔════╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ██║████╗ ██║██║ ██║██╔════╝████╗ ██║╚══██╔══╝██║██╔═══██╗████╗ ██║ 3 | ███████╗██║ ██║██████╔╝█████╗ ██████╔╝ ██║██╔██╗ ██║██║ ██║█████╗ ██╔██╗ ██║ ██║ ██║██║ ██║██╔██╗ ██║ 4 | ╚════██║██║ ██║██╔═══╝ ██╔══╝ ██╔══██╗ ██║██║╚██╗██║╚██╗ ██╔╝██╔══╝ ██║╚██╗██║ ██║ ██║██║ ██║██║╚██╗██║ 5 | ███████║╚██████╔╝██║ ███████╗██║ ██║ ██║██║ ╚████║ ╚████╔╝ ███████╗██║ ╚████║ ██║ ██║╚██████╔╝██║ ╚████║ 6 | ╚══════╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═══╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ 7 | -------------------------------------------------------------------------------- /src/main/resources/db/data-interest-group.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO interest_group 2 | ( seq, created_at, updated_at, name) 3 | VALUES 4 | (1, now(), now(), '아웃도어/여행'), 5 | (2, now(), now(), '운동/스포츠'), 6 | (3, now(), now(), '인문학/책/글'), 7 | (4, now(), now(), '외국/언어'), 8 | (5, now(), now(), '문화/공연/축제'); 9 | -------------------------------------------------------------------------------- /src/main/resources/db/data-interest.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO interest 2 | ( seq, interest_group_seq, created_at, updated_at, name ) 3 | VALUES 4 | 5 | # 아웃도어/ 여행 6 | (1, 1, now(), now(), '해외여행'), 7 | (2, 1, now(), now(), '국내여행'), 8 | (3, 1, now(), now(), '당일치기'), 9 | 10 | # 운동/스포츠 11 | (4, 2, now(), now(), '자전거'), 12 | (5, 2, now(), now(), '볼링'), 13 | (6, 2, now(), now(), '배드민'), 14 | (7, 2, now(), now(), '헬스'), 15 | (8, 2, now(), now(), '크로스핏'), 16 | 17 | # 인문학/책/글 18 | (9, 3, now(), now(), '책읽기'), 19 | (10, 3, now(), now(), '시 감상'), 20 | 21 | # 외국/언어 22 | (11, 4, now(), now(), '영어'), 23 | (12, 4, now(), now(), '독일'), 24 | (13, 4, now(), now(), '일본거'), 25 | 26 | # 문화/공연/축제 27 | (14, 5, now(), now(), '콘서트'), 28 | (15, 5, now(), now(), '클래식'), 29 | (16, 5, now(), now(), '오페라'), 30 | (17, 5, now(), now(), '재즈'); 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/dist_webp_binaries/cwebp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/dist_webp_binaries/cwebp -------------------------------------------------------------------------------- /src/main/resources/dist_webp_binaries/dwebp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/dist_webp_binaries/dwebp -------------------------------------------------------------------------------- /src/main/resources/dist_webp_binaries/gif2webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/dist_webp_binaries/gif2webp -------------------------------------------------------------------------------- /src/main/resources/webp/linux/cwebp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/webp/linux/cwebp -------------------------------------------------------------------------------- /src/main/resources/webp/linux/dwebp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/webp/linux/dwebp -------------------------------------------------------------------------------- /src/main/resources/webp/linux/gif2webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/webp/linux/gif2webp -------------------------------------------------------------------------------- /src/main/resources/webp/mac/cwebp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/webp/mac/cwebp -------------------------------------------------------------------------------- /src/main/resources/webp/mac/dwebp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/webp/mac/dwebp -------------------------------------------------------------------------------- /src/main/resources/webp/mac/gif2webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/webp/mac/gif2webp -------------------------------------------------------------------------------- /src/main/resources/webp/window/cwebp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/webp/window/cwebp -------------------------------------------------------------------------------- /src/main/resources/webp/window/dwebp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/webp/window/dwebp -------------------------------------------------------------------------------- /src/main/resources/webp/window/gif2webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/main/resources/webp/window/gif2webp -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/app/domain/interest/interest/InterestRepoTest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interest 2 | 3 | import com.taskforce.superinvention.config.test.DataJpaRepoTest 4 | import org.springframework.beans.factory.annotation.Autowired 5 | 6 | class InterestRepoTest: DataJpaRepoTest() { 7 | 8 | @Autowired 9 | lateinit var interestRepository: InterestRepository 10 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/app/domain/interest/interestGroup/InterestGroupRepoTestData.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.interest.interestGroup 2 | 3 | import com.taskforce.superinvention.config.test.DataJpaRepoTest 4 | import org.springframework.beans.factory.annotation.Autowired 5 | 6 | class InterestGroupRepoTestData : DataJpaRepoTest() { 7 | 8 | @Autowired 9 | lateinit var interestGroupRepo: InterestGroupRepository 10 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/app/domain/user/userRole/UserRoleDataTest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.app.domain.user.userRole 2 | 3 | import com.taskforce.superinvention.config.test.DataJpaRepoTest 4 | import org.springframework.beans.factory.annotation.Autowired 5 | 6 | 7 | class UserRoleDataTest : DataJpaRepoTest() { 8 | 9 | @Autowired 10 | lateinit var userRoleRepository: UserRoleRepository 11 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/common/extendFun/StringExtensionTest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.common.extendFun 2 | 3 | import com.taskforce.superinvention.common.util.extendFun.sliceIfExceed 4 | import com.taskforce.superinvention.config.test.MockkTest 5 | import org.junit.jupiter.api.Assertions 6 | import org.junit.jupiter.api.Test 7 | 8 | class StringExtensionTest: MockkTest() { 9 | 10 | @Test 11 | fun `sliceIfExceed - 범위를 넘어섯을 때만 문자열을 자름`() { 12 | 13 | val str = "문자열-10-글자-" 14 | val str2 = "3글자" 15 | 16 | Assertions.assertEquals("문자열", str.sliceIfExceed(0 until 3)) 17 | Assertions.assertEquals("3글자" , str2.sliceIfExceed(0 until 3)) 18 | } 19 | 20 | @Test 21 | fun `sliceIfExceed - 범위 내에 있을때는 문자열을 자르지 않음`() { 22 | val str = "문자열-10-글자-" 23 | Assertions.assertEquals(str, str.sliceIfExceed(0 until 100)) 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/MokitoHelper.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config 2 | 3 | import com.taskforce.superinvention.app.domain.role.Role 4 | import com.taskforce.superinvention.app.domain.role.RoleGroup 5 | import org.mockito.Mockito 6 | 7 | object MockitoHelper { 8 | fun anyObject(): T { 9 | Mockito.any() 10 | return uninitialized() 11 | } 12 | 13 | @Suppress("UNCHECKED_CAST") 14 | fun uninitialized(): T = null as T 15 | 16 | fun getRoleByRoleName(roleName: Role.RoleName, level: Int): Role { 17 | return Role(roleName, RoleGroup("MOCK_ROLE_GROUP", "MOCK_ROLE_TYPE"), level) 18 | } 19 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/jpa/CriteriaConfig.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config.jpa 2 | 3 | import com.blazebit.persistence.Criteria 4 | import com.blazebit.persistence.CriteriaBuilderFactory 5 | import org.springframework.boot.test.context.TestConfiguration 6 | import org.springframework.context.annotation.Bean 7 | import javax.persistence.EntityManager 8 | 9 | @TestConfiguration 10 | class CriteriaConfig( 11 | private val entityManager: EntityManager 12 | ) { 13 | 14 | @Bean 15 | fun createCriteriaBuilderFactory() : CriteriaBuilderFactory { 16 | val config = Criteria.getDefault() 17 | return config.createCriteriaBuilderFactory(entityManager.entityManagerFactory) 18 | } 19 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/jpa/JpaTestConfig.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config.jpa 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory 4 | import org.springframework.boot.test.context.TestConfiguration 5 | import org.springframework.context.annotation.Bean 6 | import javax.persistence.EntityManager 7 | 8 | @TestConfiguration 9 | class JpaTestConfig( 10 | private val entityManager: EntityManager 11 | ) { 12 | 13 | @Bean 14 | fun jpaQueryFactory(): JPAQueryFactory = JPAQueryFactory(entityManager) 15 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/test/ApiDocumentationTestV2.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config.test 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper 4 | import com.ninjasquad.springmockk.MockkBean 5 | import com.taskforce.superinvention.app.domain.user.* 6 | import com.taskforce.superinvention.common.config.argument.resolver.auth.AuthorizeArgumentResolver 7 | import com.taskforce.superinvention.common.config.security.JwtTokenProvider 8 | import io.mockk.every 9 | import org.springframework.beans.factory.annotation.Autowired 10 | import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs 11 | import org.springframework.test.web.servlet.MockMvc 12 | 13 | @AutoConfigureRestDocs 14 | abstract class ApiDocumentationTestV2: BaseTest { 15 | 16 | @Autowired 17 | lateinit var mockMvc: MockMvc 18 | 19 | @Autowired 20 | lateinit var objectMapper: ObjectMapper 21 | 22 | @MockkBean 23 | lateinit var authorizeArgumentResolver: AuthorizeArgumentResolver 24 | 25 | @MockkBean 26 | lateinit var userRepository: UserRepository 27 | 28 | @MockkBean(relaxed = true) 29 | lateinit var jwtTokenProvider: JwtTokenProvider 30 | 31 | @MockkBean 32 | lateinit var userDetailsProvider: UserDetailsProvider 33 | 34 | // @AuthUser - ArgumentResolver 모킹 35 | fun initMockAuthUser(user: User) { 36 | every { authorizeArgumentResolver.resolveArgument(any(), any(), any(), any()) }.returns(user) 37 | every { authorizeArgumentResolver.supportsParameter(any())}.returns(true) 38 | } 39 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/test/BaseTest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config.test 2 | 3 | import org.apache.commons.io.IOUtils 4 | import java.io.InputStream 5 | import java.nio.file.Path 6 | import java.nio.file.Paths 7 | 8 | interface BaseTest { 9 | 10 | fun getResourcePath(): String { 11 | val resourceDirectory: Path = Paths.get("src", "test", "resources") 12 | return resourceDirectory.toFile().absolutePath 13 | } 14 | 15 | fun getResourceAsStream(path: String): InputStream { 16 | return this::class.java.getResourceAsStream(path) 17 | } 18 | 19 | fun getResourceByteArray(path: String): ByteArray { 20 | return IOUtils.toByteArray(this::class.java.getResourceAsStream(path)) 21 | } 22 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/test/DataJpaRepoTest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config.test 2 | 3 | import com.taskforce.superinvention.config.jpa.CriteriaConfig 4 | import com.taskforce.superinvention.config.jpa.JpaTestConfig 5 | import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase 6 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest 7 | import org.springframework.context.annotation.Import 8 | import org.springframework.test.context.ActiveProfiles 9 | import org.springframework.transaction.annotation.Transactional 10 | 11 | @DataJpaTest 12 | @Transactional 13 | @ActiveProfiles(TestEnv.TEST) 14 | @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 15 | @Import(value = [JpaTestConfig::class, CriteriaConfig::class]) 16 | abstract class DataJpaRepoTest: BaseTest -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/test/IntegrationTest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config.test 2 | 3 | import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase 4 | import org.springframework.boot.test.context.SpringBootTest 5 | import org.springframework.test.context.ActiveProfiles 6 | import org.springframework.transaction.annotation.Transactional 7 | 8 | @SpringBootTest 9 | @ActiveProfiles(TestEnv.TEST) 10 | @Transactional 11 | @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 12 | abstract class IntegrationTest: BaseTest -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/test/MockTest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config.test 2 | 3 | import org.junit.jupiter.api.extension.ExtendWith 4 | import org.mockito.junit.jupiter.MockitoExtension 5 | import org.springframework.test.context.ActiveProfiles 6 | 7 | @ExtendWith(MockitoExtension::class) 8 | @ActiveProfiles(TestEnv.TEST) 9 | abstract class MockTest: BaseTest 10 | -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/test/MockkTest.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config.test 2 | 3 | import io.mockk.junit5.MockKExtension 4 | import org.junit.jupiter.api.extension.ExtendWith 5 | import org.springframework.test.context.ActiveProfiles 6 | import org.springframework.test.context.junit.jupiter.SpringExtension 7 | 8 | @ExtendWith(SpringExtension::class) 9 | @ActiveProfiles(TestEnv.TEST) 10 | abstract class MockkTest: BaseTest -------------------------------------------------------------------------------- /src/test/kotlin/com/taskforce/superinvention/config/test/TestEnv.kt: -------------------------------------------------------------------------------- 1 | package com.taskforce.superinvention.config.test 2 | 3 | object TestEnv { 4 | const val TEST = "test" 5 | } -------------------------------------------------------------------------------- /src/test/resources/img/animated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/test/resources/img/animated.gif -------------------------------------------------------------------------------- /src/test/resources/img/animated.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/test/resources/img/animated.webp -------------------------------------------------------------------------------- /src/test/resources/img/big-animated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/test/resources/img/big-animated.gif -------------------------------------------------------------------------------- /src/test/resources/img/large-size.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/test/resources/img/large-size.jpg -------------------------------------------------------------------------------- /src/test/resources/img/large-size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/test/resources/img/large-size.png -------------------------------------------------------------------------------- /src/test/resources/img/not-animated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/test/resources/img/not-animated.gif -------------------------------------------------------------------------------- /src/test/resources/img/not-animated.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/test/resources/img/not-animated.webp -------------------------------------------------------------------------------- /src/test/resources/img/test-large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/test/resources/img/test-large.jpg -------------------------------------------------------------------------------- /src/test/resources/img/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TASK-FORCE/mannalga-api/c4b5566e633bca6409ab5e7be17397531a72c434/src/test/resources/img/test.jpg --------------------------------------------------------------------------------