From 12fc8fae550b1d30caaea40be125d6b942be6711 Mon Sep 17 00:00:00 2001 From: yeopyeop-82 Date: Sat, 3 Feb 2024 18:24:43 +0900 Subject: [PATCH 1/2] =?UTF-8?q?add=20:=20=EB=AC=B8=EC=9D=98=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 8196 -> 0 bytes .../meme-bug-report-template.md | 19 -- .github/ISSUE_TEMPLATE/meme-issue-template.md | 15 -- .github/workflows/docker.yml | 95 ------- .gitignore | 40 --- Dockerfile | 4 - README.md | 1 - build.gradle | 37 --- docker-compose.yaml | 18 -- gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 7 - gradlew | 249 ------------------ gradlew.bat | 92 ------- settings.gradle | 1 - src/.DS_Store | Bin 6148 -> 0 bytes src/main/.DS_Store | Bin 6148 -> 0 bytes .../java/umc/meme/shop/ShopApplication.java | 15 -- .../artist/controller/ArtistController.java | 37 --- .../artist/converter/ArtistConverter.java | 21 -- .../artist/dto/request/ArtistProfileDto.java | 29 -- .../domain/artist/dto/response/ArtistDto.java | 75 ------ .../artist/dto/response/ArtistPageDto.java | 21 -- .../shop/domain/artist/entity/Artist.java | 106 -------- .../domain/artist/entity/enums/Gender.java | 5 - .../artist/entity/enums/MakeupLocation.java | 5 - .../domain/artist/entity/enums/Region.java | 22 -- .../artist/entity/enums/WorkExperience.java | 7 - .../artist/repository/ArtistRepository.java | 7 - .../domain/artist/service/ArtistService.java | 47 ---- .../dto/request/FavoriteArtistDto.java | 12 - .../dto/request/FavoritePortfolioDto.java | 12 - .../FavoriteArtistPageResponseDto.java | 21 -- .../response/FavoriteArtistResponseDto.java | 26 -- .../FavoritePortfolioResponseDto.java | 40 --- .../FavoritePortfolioResponsePageDto.java | 20 -- .../favorite/entity/FavoriteArtist.java | 26 -- .../favorite/entity/FavoritePortfolio.java | 29 -- .../repository/FavoriteArtistRepository.java | 15 -- .../FavoritePortfolioRepository.java | 15 -- .../model/controller/ModelController.java | 119 --------- .../model/dto/request/ModelProfileDto.java | 16 -- .../meme/shop/domain/model/entity/Model.java | 86 ------ .../model/entity/enums/PersonalColor.java | 5 - .../domain/model/entity/enums/SkinType.java | 5 - .../model/repository/ModelRepository.java | 7 - .../domain/model/service/ModelService.java | 242 ----------------- .../mypage/controller/MyPageController.java | 43 --- .../mypage/dto/request/MypageInquiryDto.java | 24 -- .../mypage/dto/response/MypageDetailDto.java | 20 -- .../mypage/dto/response/MypageTosDto.java | 10 - .../shop/domain/mypage/entity/Inquiry.java | 36 --- .../mypage/repository/InquiryRepository.java | 7 - .../domain/mypage/service/MypageService.java | 69 ----- .../controller/PortfolioController.java | 46 ---- .../converter/PortfolioConverter.java | 47 ---- .../dto/request/CreatePortfolioDto.java | 29 -- .../dto/request/UpdatePortfolioDto.java | 25 -- .../portfolio/dto/response/PortfolioDto.java | 89 ------- .../dto/response/PortfolioImgDto.java | 21 -- .../dto/response/PortfolioPageDto.java | 20 -- .../domain/portfolio/entity/Portfolio.java | 96 ------- .../domain/portfolio/entity/PortfolioImg.java | 24 -- .../portfolio/entity/enums/Category.java | 16 -- .../repository/PortfolioImgRepository.java | 7 - .../repository/PortfolioRepository.java | 35 --- .../portfolio/service/PortfolioService.java | 149 ----------- .../controller/ReservationController.java | 63 ----- .../dto/request/AlterReservationDto.java | 13 - .../dto/request/ReservationRequestDto.java | 24 -- .../dto/response/ArtistLocationDto.java | 20 -- .../dto/response/ArtistTimeDto.java | 17 -- .../dto/response/ReservationCompleteDto.java | 25 -- .../dto/response/ReservationResponseDto.java | 57 ---- .../reservation/entity/Reservation.java | 64 ----- .../reservation/entity/enums/Status.java | 5 - .../repository/ReservationRepository.java | 26 -- .../service/ReservationService.java | 152 ----------- .../review/controller/ReviewController.java | 46 ---- .../review/converter/ReviewConverter.java | 27 -- .../review/dto/request/DeleteReviewDto.java | 16 -- .../domain/review/dto/request/ReviewDto.java | 21 -- .../review/dto/response/ReviewImgDto.java | 14 - .../dto/response/ReviewListPageDto.java | 22 -- .../dto/response/ReviewListResponseDto.java | 27 -- .../dto/response/ReviewResponseDto.java | 34 --- .../shop/domain/review/entity/Review.java | 39 --- .../shop/domain/review/entity/ReviewImg.java | 24 -- .../repository/ReviewImgRepository.java | 7 - .../review/repository/ReviewRepository.java | 11 - .../domain/review/service/ReviewService.java | 146 ---------- .../java/umc/meme/shop/domain/user/User.java | 38 --- .../meme/shop/domain/user/UserRepository.java | 7 - .../umc/meme/shop/global/ErrorStatus.java | 77 ------ .../umc/meme/shop/global/SuccessStatus.java | 55 ---- .../shop/global/config/SwaggerConfig.java | 40 --- .../umc/meme/shop/global/enums/DayOfWeek.java | 6 - .../umc/meme/shop/global/enums/Times.java | 28 -- .../global/exception/GlobalException.java | 11 - .../exception/GlobalExceptionAdvice.java | 18 -- .../exception/GlobalExceptionHandler.java | 9 - .../shop/global/response/ApiResponse.java | 35 --- src/test/java/umc/meme/shop/ArtistTest.java | 74 ------ .../umc/meme/shop/ShopApplicationTests.java | 13 - 103 files changed, 3795 deletions(-) delete mode 100644 .DS_Store delete mode 100644 .github/ISSUE_TEMPLATE/meme-bug-report-template.md delete mode 100644 .github/ISSUE_TEMPLATE/meme-issue-template.md delete mode 100644 .github/workflows/docker.yml delete mode 100644 .gitignore delete mode 100644 Dockerfile delete mode 100644 README.md delete mode 100644 build.gradle delete mode 100644 docker-compose.yaml delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat delete mode 100644 settings.gradle delete mode 100644 src/.DS_Store delete mode 100644 src/main/.DS_Store delete mode 100644 src/main/java/umc/meme/shop/ShopApplication.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/controller/ArtistController.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/converter/ArtistConverter.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/dto/request/ArtistProfileDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistPageDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/Artist.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/enums/Gender.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/enums/MakeupLocation.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/enums/Region.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/enums/WorkExperience.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/repository/ArtistRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/artist/service/ArtistService.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoriteArtistDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoritePortfolioDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistPageResponseDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistResponseDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponseDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponsePageDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/entity/FavoriteArtist.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/entity/FavoritePortfolio.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/repository/FavoriteArtistRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/favorite/repository/FavoritePortfolioRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/model/controller/ModelController.java delete mode 100644 src/main/java/umc/meme/shop/domain/model/dto/request/ModelProfileDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/model/entity/Model.java delete mode 100644 src/main/java/umc/meme/shop/domain/model/entity/enums/PersonalColor.java delete mode 100644 src/main/java/umc/meme/shop/domain/model/entity/enums/SkinType.java delete mode 100644 src/main/java/umc/meme/shop/domain/model/repository/ModelRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/model/service/ModelService.java delete mode 100644 src/main/java/umc/meme/shop/domain/mypage/controller/MyPageController.java delete mode 100644 src/main/java/umc/meme/shop/domain/mypage/dto/request/MypageInquiryDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageDetailDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageTosDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/mypage/entity/Inquiry.java delete mode 100644 src/main/java/umc/meme/shop/domain/mypage/repository/InquiryRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/mypage/service/MypageService.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/controller/PortfolioController.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/converter/PortfolioConverter.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/request/CreatePortfolioDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/request/UpdatePortfolioDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioImgDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioPageDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/entity/Portfolio.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/entity/PortfolioImg.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/entity/enums/Category.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioImgRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/portfolio/service/PortfolioService.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/controller/ReservationController.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/request/AlterReservationDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/request/ReservationRequestDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistLocationDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistTimeDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationCompleteDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationResponseDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/entity/Reservation.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/entity/enums/Status.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/repository/ReservationRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/reservation/service/ReservationService.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/controller/ReviewController.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/converter/ReviewConverter.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/dto/request/DeleteReviewDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/dto/request/ReviewDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/dto/response/ReviewImgDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListPageDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListResponseDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/dto/response/ReviewResponseDto.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/entity/Review.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/entity/ReviewImg.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/repository/ReviewImgRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/repository/ReviewRepository.java delete mode 100644 src/main/java/umc/meme/shop/domain/review/service/ReviewService.java delete mode 100644 src/main/java/umc/meme/shop/domain/user/User.java delete mode 100644 src/main/java/umc/meme/shop/domain/user/UserRepository.java delete mode 100644 src/main/java/umc/meme/shop/global/ErrorStatus.java delete mode 100644 src/main/java/umc/meme/shop/global/SuccessStatus.java delete mode 100644 src/main/java/umc/meme/shop/global/config/SwaggerConfig.java delete mode 100644 src/main/java/umc/meme/shop/global/enums/DayOfWeek.java delete mode 100644 src/main/java/umc/meme/shop/global/enums/Times.java delete mode 100644 src/main/java/umc/meme/shop/global/exception/GlobalException.java delete mode 100644 src/main/java/umc/meme/shop/global/exception/GlobalExceptionAdvice.java delete mode 100644 src/main/java/umc/meme/shop/global/exception/GlobalExceptionHandler.java delete mode 100644 src/main/java/umc/meme/shop/global/response/ApiResponse.java delete mode 100644 src/test/java/umc/meme/shop/ArtistTest.java delete mode 100644 src/test/java/umc/meme/shop/ShopApplicationTests.java diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 52b68ac73a2790bd5ed2253a0632977fbbca5ad8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM%}*0S6o13#RzQ}IBJm^H*oz4S5yg*qaH$YOjDfTSA%JzaJJb!!PTk#7k&yJP ze}I30R})VrUOjp9=+%S&fEN#*@XbdBTJWZrIFHQyrZexiZ{Ba)oxTD9BwO*W01N|w zfsLcth20Ux*LiEQ7B$0p1o;5oY`}_cz}zNZJ)srQ3TOqi0$KsBz`vmYp4r@tW6piK zs(Y<~R^Y!>fIlBBY#eQcHHqTUft@G;5ZiEC7>=gCaOXqB0BOc;SR)>sC%t|R-jn{e)hM63l;DoI8?v$57HF2 zu{~je+P&`yV^D$!9Pp4w57hmf_qKu8al9|N(BRv7&=;zQuS{Mxcy}H4#$CC%r=)@P zqk)xz9L!*L)9?Us3^p4xZz(k}dLaf13I6#IV$Arr`E%Xg9MG*5{UazI-jz`42rsu9 zm(_15@7;3X$I1BkXVTKz*51)+bQ)d8TK);E<`XBW#91d=;jb1L3*7qHaTk4BEtrFM zS(rF}NFzb;J&G=?5B<<%)hw%oUM#qIxnQJ>RKXnH*_j+4AGNOCoY)<;c5Y4Z@zv|Q zyD1}`xqLfU*a$X5_5$-mBkExcJ@WOhp5G;vvtQg&*^rO*Y`&OgJ)hL6uI`@Gy=Gtk zK;K|rI-MRmlOFCrd#+#(xK44S6!CrDWdVz_L4_8~-Wao;EwXSvqFb2dQbM04dH*>s z^*0c5)O)l)wXj`ApTYeJanXAbrQu2`^1ZqB^_V70JVG&IK`_r^Kk-?(d|-8XRYXtd z=4`mmFe2Z`DnT$p7^!Zw$D%!2P+1jv`2q92wr zcfLsxQyKe`9GQ@*>uL^Qeb}oSeE&?p8hu0~YcRi}FSg zCorPL35d4BnnavI)91gCL3dh#6H}m7Mjqzh0cMW>{r|-FrvqyRv;u!#0n#>|pUz?& zc{Dc% DUQ09U diff --git a/.github/ISSUE_TEMPLATE/meme-bug-report-template.md b/.github/ISSUE_TEMPLATE/meme-bug-report-template.md deleted file mode 100644 index 1ad06b8..0000000 --- a/.github/ISSUE_TEMPLATE/meme-bug-report-template.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: MEME BUG REPORT TEMPLATE -about: 메메 버그 이슈 템플릿 -title: '' -labels: '' -assignees: '' - ---- - -## 🐞 버그 설명 -| 문제 발생 일시 | 발생 위치 | 발생 조건 | -| --- | --- | --- | -| | | | - -## 💣 증상 - - -## 🎥 스크린샷 - diff --git a/.github/ISSUE_TEMPLATE/meme-issue-template.md b/.github/ISSUE_TEMPLATE/meme-issue-template.md deleted file mode 100644 index ddee7b1..0000000 --- a/.github/ISSUE_TEMPLATE/meme-issue-template.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: MEME ISSUE TEMPLATE -about: 메메 기본 이슈 템플릿 -title: '' -labels: '' -assignees: '' - ---- - -## 💡 Description - - -## 📝 Progress - -- [ ] todo ! diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml deleted file mode 100644 index 4af70f3..0000000 --- a/.github/workflows/docker.yml +++ /dev/null @@ -1,95 +0,0 @@ -name: main Workflow - -on: - push: - branches: - - develop -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'adopt' - - - name: Set .yml for main - run: | - mkdir -p src/main/resources - echo "${{ secrets.MAIN_DATABASE_YML }}" | base64 --decode > src/main/resources/application.yml - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Run chmod to make gradlew executable - run: chmod +x ./gradlew - - - name: Build with Gradle - run: ./gradlew clean build --exclude-task test - - ## 웹 이미지 빌드 및 도커허브에 push - - name: web docker build and push - run: | - docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - docker build -t ${{ secrets.DOCKER_REPO }}/meme-service . - docker push ${{ secrets.DOCKER_REPO }}/meme-service - - - name: EC2 docker remove - uses: appleboy/ssh-action@v0.1.6 - with: - host: ${{ secrets.HOST }} - username: ec2-user - key: ${{ secrets.KEY }} - script: | - if [ "$(sudo docker ps -aq)" ]; then - sudo docker stop $(sudo docker ps -aq) - sudo docker rm -f $(sudo docker ps -aq) - fi - if [ "$(sudo docker images -aq)" ]; then - sudo docker rmi -f $(sudo docker images -aq) - fi - - - name: Copy file to EC2 - uses: appleboy/scp-action@master - with: - host: ${{ secrets.HOST }} - username: ec2-user - key: ${{ secrets.KEY }} - source: ./docker-compose.yaml - target: /home/ec2-user/ - - - name: Create and Copy .env File to EC2 - uses: appleboy/ssh-action@v0.1.6 - with: - host: ${{ secrets.HOST }} - username: ec2-user - key: ${{ secrets.KEY }} - script: | - # Create .env file - echo "DB_URL=${{ secrets.DB_URL }}" > ~/.env - echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> ~/.env - echo "DB_PASS=${{ secrets.DB_PASS }}" >> ~/.env - - # Copy .env file to the project directory - #cp ~/.env /home/ec2-user/.env - - ## docker compose up - - name: Docker Compose on EC2 - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.HOST }} - username: ec2-user - key: ${{ secrets.KEY }} - script: | - # Docker 이미지 다운로드 - sudo docker pull ${{ secrets.DOCKER_REPO }}/meme-service - - # Docker Compose 실행 - sudo docker-compose up -d - sudo docker-compose logs -f - - # 사용하지 않는 Docker 이미지 정리 - sudo docker image prune -f \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index fd5c9d8..0000000 --- a/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -HELP.md -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ -src/main/resources/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -*.xml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 189b146..0000000 --- a/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM openjdk:17-alpine -ARG JAR_FILE=build/libs/*.jar -COPY ${JAR_FILE} app.jar -ENTRYPOINT ["java","-jar","/app.jar"] \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index ee4f75a..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# MEME_SERVICE \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 2822e36..0000000 --- a/build.gradle +++ /dev/null @@ -1,37 +0,0 @@ -plugins { - id 'java' - id 'org.springframework.boot' version '3.2.1' - id 'io.spring.dependency-management' version '1.1.4' -} - -group = 'umc.meme' -version = '0.0.1-SNAPSHOT' - -java { - sourceCompatibility = '17' -} - -configurations { - compileOnly { - extendsFrom annotationProcessor - } -} - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' - compileOnly 'org.projectlombok:lombok' - runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} - -tasks.named('test') { - useJUnitPlatform() -} diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 68df57a..0000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,18 +0,0 @@ -version: '3' -services: - web: - container_name: service - image: sunwupark/meme-service - expose: - - 8080 - ports: - - "8080:8080" - - auth: - container_name: auth - image: sunwupark/meme-auth - expose: - - 8081 - ports: - - "8081:8081" - depends_on: web diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index d64cd4917707c1f8861d8cb53dd15194d4248596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43462 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 1af9e09..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew deleted file mode 100755 index 1aa94a4..0000000 --- a/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 6689b85..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index c1e09f9..0000000 --- a/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'shop' diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index 5a6a5ada3fa1f6dcca6c428d35be9b424607b7e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%Wl&^6rE`Uby`Z@HYpXbu*e3fl?a9M5DVP22vsav#T6uKO0eTeuc=A2kq#qkWb5Ya-ri!dIB#9QwXi>L?cHAB`n4PT`&lDjxN@gl-wxZ9 zy_5uE*l&c4D@@@PC<19ess@;q^Z7vP%uDWOdK$A_kk-44X$ z4h>?^`w<~@vlRvYTC*9Gq{3%tL@W%~SsWw*qtzqcYE8_ZkoGEVGMJIS!CHrh#Scjo z0}kX@s%{jyv_(q0TcPWbaE+E&lCX9qfGYT#iwT^L+X!f@aQCZZF51Bx_b?8GST)C_0_ z{znG*{$N4lXe;bX6k7*$;tBwm0kaU$`CWqNSPE^0eTm=!!7>$4rebx)z%m`|mWs0# z_9e=6gw^E(tC_L7pgl&ns*9>R|jx)gj{XtBA{@;T&{G0o~2-2NqKr`@f zGJrEH&PoYtQ)lZymHe!=pgn=cg~#S5Z-O8O(;SR3Oz1(Eg0($ikA@U3mDOZN^NY=V9ZLAnnNk%tS{t~_&m<+ zZpG3HoOP&I{Ll=e2rcWwmKFt(J8i+{-d32E{1% z2iYa|&ZJDjsXYkK&G%J25}l?svsUlkaBeqr$br#a+D5pRU7DlWm|UNX^+Qy zuGB9$kIfncMzRc zPAdqB0b+m{SQZA%{%5t8Wx_O1Vt^RpM3xRpDm&uF+dFbD+YL@7xa9Xk~v%FCWmLO0KEZ4!MsZ2X9*bUD27}-irb({ Zz%S4M^bA%S!2?1U0Yw8f#K5mI@BvrmO{4$- diff --git a/src/main/java/umc/meme/shop/ShopApplication.java b/src/main/java/umc/meme/shop/ShopApplication.java deleted file mode 100644 index e4d47bc..0000000 --- a/src/main/java/umc/meme/shop/ShopApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package umc.meme.shop; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; - -@SpringBootApplication -@EnableJpaAuditing -public class ShopApplication { - - public static void main(String[] args) { - SpringApplication.run(ShopApplication.class, args); - } - -} diff --git a/src/main/java/umc/meme/shop/domain/artist/controller/ArtistController.java b/src/main/java/umc/meme/shop/domain/artist/controller/ArtistController.java deleted file mode 100644 index 3185ce0..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/controller/ArtistController.java +++ /dev/null @@ -1,37 +0,0 @@ -package umc.meme.shop.domain.artist.controller; - -import io.swagger.v3.oas.annotations.Operation; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; -import umc.meme.shop.domain.artist.dto.request.ArtistProfileDto; -import umc.meme.shop.domain.artist.service.ArtistService; -import umc.meme.shop.global.SuccessStatus; -import umc.meme.shop.global.response.ApiResponse; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1") -public class ArtistController { - private final ArtistService artistService; - - @Operation(summary = "아티스트 프로필 관리") - @PatchMapping("/mypage/profile/artist") - public ApiResponse updateProfile(@RequestBody ArtistProfileDto profileDto){ - artistService.updateArtistProfile(profileDto); - return ApiResponse.SuccessResponse(SuccessStatus.ARTIST_PROFILE_UPDATE); - } - - @Operation(summary = "아티스트 프로필 조회") - @GetMapping("/profile/{artistId}") - public ApiResponse getArtistProfile(@PathVariable Long artistId){ - return ApiResponse.SuccessResponse(SuccessStatus.ARTIST_PROFILE_GET, artistService.getArtistProfile(artistId)); - } - - //temp method for Artist create - @PostMapping("/artist") - public ApiResponse createArtist(@RequestBody ArtistProfileDto profileDto){ - artistService.createArtist(profileDto); - return ApiResponse.SuccessResponse(SuccessStatus.TEMP); - } - -} diff --git a/src/main/java/umc/meme/shop/domain/artist/converter/ArtistConverter.java b/src/main/java/umc/meme/shop/domain/artist/converter/ArtistConverter.java deleted file mode 100644 index af78368..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/converter/ArtistConverter.java +++ /dev/null @@ -1,21 +0,0 @@ -package umc.meme.shop.domain.artist.converter; - -import org.springframework.data.domain.Page; -import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistPageResponseDto; -import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistResponseDto; -import umc.meme.shop.domain.favorite.entity.FavoriteArtist; - -import java.util.List; - -public class ArtistConverter { - public static FavoriteArtistPageResponseDto favoriteArtistPageConverter(Page page, List content) { - - return FavoriteArtistPageResponseDto.builder() - .content(content) - .pageSize(page.getSize()) - .currentPage(page.getNumber()) - .totalNumber(page.getNumberOfElements()) - .totalPage(page.getTotalPages()) - .build(); - } -} diff --git a/src/main/java/umc/meme/shop/domain/artist/dto/request/ArtistProfileDto.java b/src/main/java/umc/meme/shop/domain/artist/dto/request/ArtistProfileDto.java deleted file mode 100644 index ab1bdc9..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/dto/request/ArtistProfileDto.java +++ /dev/null @@ -1,29 +0,0 @@ -package umc.meme.shop.domain.artist.dto.request; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.artist.entity.enums.*; -import umc.meme.shop.domain.portfolio.entity.enums.Category; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; - -import java.util.List; -import java.util.Map; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class ArtistProfileDto { - private Long artistId; - private String profileImg; - private String nickname; - private Gender gender; - private String introduction; - private WorkExperience workExperience; - private List region; - private List specialization; - private MakeupLocation makeupLocation; - private String shopLocation; - private Map availableDayOfWeek; -} diff --git a/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistDto.java b/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistDto.java deleted file mode 100644 index dd648b9..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistDto.java +++ /dev/null @@ -1,75 +0,0 @@ -package umc.meme.shop.domain.artist.dto.response; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.artist.entity.enums.*; -import umc.meme.shop.domain.artist.repository.ArtistRepository; -import umc.meme.shop.domain.favorite.entity.FavoriteArtist; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; -import umc.meme.shop.domain.user.User; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ArtistDto { - private Long artistId; - - private Gender gender; - - private String nickname; - - private String profileImg; - - private String introduction; - - private WorkExperience workExperience; - - private List region; - - private List specialization; - - private MakeupLocation makeupLocation; - - private Map availableDayOfWeekAndTime; - - private List portfolioDtoList; - - - - public static ArtistDto from(Artist artist){ - List portfolioDtoList = artist.getPortfolioList() - .stream() - .map(PortfolioDto::from) - .toList(); - - return ArtistDto.builder() - .artistId(artist.getUserId()) - .gender(artist.getGender()) - .nickname(artist.getNickname()) - .profileImg(artist.getProfileImg()) - .introduction(artist.getIntroduction()) - .workExperience(artist.getWorkExperience()) - .region(artist.getRegion()) - .specialization(artist.getSpecialization()) - .makeupLocation(artist.getMakeupLocation()) - .availableDayOfWeekAndTime(artist.getAvailableDayOfWeekAndTime()) - .portfolioDtoList(portfolioDtoList) - .build(); - } - -} - - diff --git a/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistPageDto.java b/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistPageDto.java deleted file mode 100644 index 622e8f5..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistPageDto.java +++ /dev/null @@ -1,21 +0,0 @@ -package umc.meme.shop.domain.artist.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; - -import java.util.List; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class ArtistPageDto { - private List content; - private int currentPage; //현재 페이지 번호 - private int pageSize; //페이지 크기 - private int totalNumber; //전체 메이크업 개수 - private int totalPage; //전체 페이지 개수 -} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/Artist.java b/src/main/java/umc/meme/shop/domain/artist/entity/Artist.java deleted file mode 100644 index 1157b97..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/entity/Artist.java +++ /dev/null @@ -1,106 +0,0 @@ -package umc.meme.shop.domain.artist.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; -import umc.meme.shop.domain.user.User; -import umc.meme.shop.domain.artist.dto.request.ArtistProfileDto; -import umc.meme.shop.domain.artist.entity.enums.*; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.portfolio.entity.enums.Category; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - -@SuperBuilder -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class Artist extends User { - - @Column(nullable = false, length = 500) - private String introduction; - - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private WorkExperience workExperience; - - @ElementCollection(fetch = FetchType.LAZY) - private List region; - - @ElementCollection(fetch = FetchType.LAZY) - private List specialization; - - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private MakeupLocation makeupLocation; - - @Column(nullable = true) - private String shopLocation; //샵의 위치 - - @Column(nullable = true) - private Date inactiveDate; - - @ElementCollection - @CollectionTable(name = "available_time_mapping", - joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")}) - @MapKeyColumn(name = "day_of_week") - @Enumerated(EnumType.STRING) - @Column(nullable = true) - private Map availableDayOfWeekAndTime; - - @OneToMany(cascade = CascadeType.ALL, mappedBy = "artist") - private List portfolioList; - - - public void updateArtist(ArtistProfileDto request) { - if (request.getProfileImg() != null) - this.profileImg = request.getProfileImg(); - if (request.getNickname() != null) - this.nickname = request.getNickname(); - if (request.getGender() != null) - this.gender = request.getGender(); - if (request.getIntroduction() != null) - this.introduction = request.getIntroduction(); - if (request.getWorkExperience() != null) - this.workExperience = request.getWorkExperience(); - - //region mapping - if (request.getRegion() != null){ - List regionList = new ArrayList<>(); - for(Region region : request.getRegion()) - regionList.add(region.getValue()); - this.region = regionList; - } - - //specialization mapping - if (request.getSpecialization() != null){ - List specialization = new ArrayList<>(); - for(Category category : request.getSpecialization()) - specialization.add(category.getValue()); - this.specialization = specialization; - } - if (request.getMakeupLocation() != null) - this.makeupLocation = request.getMakeupLocation(); - if (request.getShopLocation() != null) - this.shopLocation = request.getShopLocation(); - if (request.getAvailableDayOfWeek() != null) - this.availableDayOfWeekAndTime = request.getAvailableDayOfWeek(); - } - - public void updatePortfolioList(Portfolio portfolio){ - this.portfolioList.add(portfolio); - } - - public void tempMethod(String email, String name){ - this.email = email; - this.name = name; - } -} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/enums/Gender.java b/src/main/java/umc/meme/shop/domain/artist/entity/enums/Gender.java deleted file mode 100644 index cdbc18a..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/entity/enums/Gender.java +++ /dev/null @@ -1,5 +0,0 @@ -package umc.meme.shop.domain.artist.entity.enums; - -public enum Gender { - MALE, FEMALE -} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/enums/MakeupLocation.java b/src/main/java/umc/meme/shop/domain/artist/entity/enums/MakeupLocation.java deleted file mode 100644 index f6e3d45..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/entity/enums/MakeupLocation.java +++ /dev/null @@ -1,5 +0,0 @@ -package umc.meme.shop.domain.artist.entity.enums; - -public enum MakeupLocation { - SHOP, VISIT, BOTH -} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/enums/Region.java b/src/main/java/umc/meme/shop/domain/artist/entity/enums/Region.java deleted file mode 100644 index f025e54..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/entity/enums/Region.java +++ /dev/null @@ -1,22 +0,0 @@ -package umc.meme.shop.domain.artist.entity.enums; - -public enum Region { - JONGNO("jongno"), JUNG("jung"), YONGSAN("yongsan"), SEONGDONG("seongdong"), - GWANGJIN("gwangjin"), DONGDAEMUN("dongdaemun"), - JUNGNANG("jungnang"), SEONGBUK("seongbuk"), GANGBUK("gangbuk"), - DOBONG("dobong"), NOWON("nowon"), EUNPYEONG("eunpyeong"), - SEODAEMUN("seodaemun"), MAPO("mapo"), YANGCHEON("yangcheon"), - GANGSEO("gangseo"), GURO("guro"), GEUMCHEON("geumcheon"), - YEONGDEUNGPO("yeongdeunpo"), DONGJAK("dongjak"), GWANAK("gwanak"), - SEOCHO("seocho"), GANGNAM("gangnam"), SONGPA("songpa"), GANGDONG("gangdong"); - - private String value; - - Region(String value){ - this.value = value; - } - - public String getValue(){ - return this.value; - } -} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/enums/WorkExperience.java b/src/main/java/umc/meme/shop/domain/artist/entity/enums/WorkExperience.java deleted file mode 100644 index 5bd7d94..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/entity/enums/WorkExperience.java +++ /dev/null @@ -1,7 +0,0 @@ -package umc.meme.shop.domain.artist.entity.enums; - -public enum WorkExperience { - ONE, TWO, THREE, FOUR, - FIVE, SIX, SEVEN, EIGHT, - NINE, TEN -} diff --git a/src/main/java/umc/meme/shop/domain/artist/repository/ArtistRepository.java b/src/main/java/umc/meme/shop/domain/artist/repository/ArtistRepository.java deleted file mode 100644 index b753258..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/repository/ArtistRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package umc.meme.shop.domain.artist.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import umc.meme.shop.domain.artist.entity.Artist; - -public interface ArtistRepository extends JpaRepository { -} diff --git a/src/main/java/umc/meme/shop/domain/artist/service/ArtistService.java b/src/main/java/umc/meme/shop/domain/artist/service/ArtistService.java deleted file mode 100644 index 9654cae..0000000 --- a/src/main/java/umc/meme/shop/domain/artist/service/ArtistService.java +++ /dev/null @@ -1,47 +0,0 @@ -package umc.meme.shop.domain.artist.service; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import umc.meme.shop.domain.artist.dto.request.ArtistProfileDto; -import umc.meme.shop.domain.artist.dto.response.ArtistDto; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.artist.entity.enums.*; -import umc.meme.shop.domain.artist.repository.ArtistRepository; -import umc.meme.shop.domain.portfolio.entity.enums.Category; -import umc.meme.shop.global.ErrorStatus; -import umc.meme.shop.global.exception.GlobalException; - -import java.util.List; - - -@Service -@RequiredArgsConstructor -public class ArtistService { - private final ArtistRepository artistRepository; - - //아티스트 프로필 관리/수정 - @Transactional - public void updateArtistProfile(ArtistProfileDto profileDto){ - Artist artist = artistRepository.findById(profileDto.getArtistId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - artist.updateArtist(profileDto); - } - - //아티스트 프로필 조회 - public ArtistDto getArtistProfile(Long artistId){ - Artist artist = artistRepository.findById(artistId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - return ArtistDto.from(artist); - } - - //temp method for create Artist - @Transactional - public void createArtist(ArtistProfileDto dto){ - Artist artist = new Artist(); - artist.updateArtist(dto); - artist.tempMethod("", "testName"); - artistRepository.save(artist); - } - -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoriteArtistDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoriteArtistDto.java deleted file mode 100644 index 89ee784..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoriteArtistDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package umc.meme.shop.domain.favorite.dto.request; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; - -@Data -public class FavoriteArtistDto { - @NotBlank(message = "modelId를 입력해주세요.") - private Long modelId; - @NotBlank(message = "artistId를 입력해주세요.") - private Long artistId; -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoritePortfolioDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoritePortfolioDto.java deleted file mode 100644 index c30ac62..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoritePortfolioDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package umc.meme.shop.domain.favorite.dto.request; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; - -@Data -public class FavoritePortfolioDto { - @NotBlank(message = "modelId를 입력해주세요.") - private Long modelId; - @NotBlank(message = "portfolioId를 입력해주세요.") - private Long portfolioId; -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistPageResponseDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistPageResponseDto.java deleted file mode 100644 index 937cdba..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistPageResponseDto.java +++ /dev/null @@ -1,21 +0,0 @@ -package umc.meme.shop.domain.favorite.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.favorite.entity.FavoriteArtist; - -import java.util.List; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class FavoriteArtistPageResponseDto { - private List content; - private int currentPage; //현재 페이지 번호 - private int pageSize; //페이지 크기 - private int totalNumber; //전체 메이크업 개수 - private int totalPage; //전체 페이지 개수 -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistResponseDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistResponseDto.java deleted file mode 100644 index 12f8315..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistResponseDto.java +++ /dev/null @@ -1,26 +0,0 @@ -package umc.meme.shop.domain.favorite.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.favorite.entity.FavoriteArtist; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class FavoriteArtistResponseDto { - private Long artistId; - private String profileImg; - private String artistNickName; - - public static FavoriteArtistResponseDto from(Artist artist) { - return FavoriteArtistResponseDto.builder() - .artistId(artist.getUserId()) - .profileImg(artist.getProfileImg()) - .artistNickName(artist.getNickname()) - .build(); - } -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponseDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponseDto.java deleted file mode 100644 index 98c3e6f..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponseDto.java +++ /dev/null @@ -1,40 +0,0 @@ -package umc.meme.shop.domain.favorite.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.portfolio.entity.PortfolioImg; -import umc.meme.shop.domain.portfolio.entity.enums.Category; - -import java.util.List; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class FavoritePortfolioResponseDto { - private Long portfolioId; - private String portfolioImg; - private Category category; - private String makeupName; - private int price; - - public static FavoritePortfolioResponseDto from(FavoritePortfolio favoritePortfolio) { - - Portfolio portfolio = favoritePortfolio.getPortfolio(); - - return FavoritePortfolioResponseDto.builder() - .portfolioId(portfolio.getPortfolioId()) - .portfolioImg(portfolio.getPortfolioImgList().get(0).getSrc()) - .category(portfolio.getCategory()) - .makeupName(portfolio.getMakeupName()) - .price(portfolio.getPrice()) - .build(); - - } -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponsePageDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponsePageDto.java deleted file mode 100644 index 1bff5ab..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponsePageDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package umc.meme.shop.domain.favorite.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class FavoritePortfolioResponsePageDto { - private List content; - private int currentPage; //현재 페이지 번호 - private int pageSize; //페이지 크기 - private int totalNumber; //전체 메이크업 개수 - private int totalPage; //전체 페이지 개수 -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/entity/FavoriteArtist.java b/src/main/java/umc/meme/shop/domain/favorite/entity/FavoriteArtist.java deleted file mode 100644 index 6f0a3f2..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/entity/FavoriteArtist.java +++ /dev/null @@ -1,26 +0,0 @@ -package umc.meme.shop.domain.favorite.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.model.entity.Model; - -@Builder -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class FavoriteArtist { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long favoriteArtistId; - - @ManyToOne - @JoinColumn(name="user_id", nullable = false) - private Model model; - - private Long artistId; -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/entity/FavoritePortfolio.java b/src/main/java/umc/meme/shop/domain/favorite/entity/FavoritePortfolio.java deleted file mode 100644 index c4e930e..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/entity/FavoritePortfolio.java +++ /dev/null @@ -1,29 +0,0 @@ -package umc.meme.shop.domain.favorite.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.user.User; - -@Builder -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class FavoritePortfolio { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long favoritePortfolioId; - - @ManyToOne - @JoinColumn(name="user_id", nullable = false) - private User model; - - @ManyToOne - @JoinColumn(name="portfolio_id", nullable = false) - private Portfolio portfolio; -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/repository/FavoriteArtistRepository.java b/src/main/java/umc/meme/shop/domain/favorite/repository/FavoriteArtistRepository.java deleted file mode 100644 index 472285d..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/repository/FavoriteArtistRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package umc.meme.shop.domain.favorite.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.favorite.entity.FavoriteArtist; -import umc.meme.shop.domain.model.entity.Model; - -import java.util.List; -import java.util.Optional; - -public interface FavoriteArtistRepository extends JpaRepository { - List findByModel(Model model); - boolean existsByModelAndArtistId(Model model, Long userId); - Optional findByModelAndArtistId(Model model, Long userId); -} diff --git a/src/main/java/umc/meme/shop/domain/favorite/repository/FavoritePortfolioRepository.java b/src/main/java/umc/meme/shop/domain/favorite/repository/FavoritePortfolioRepository.java deleted file mode 100644 index e6d2c5d..0000000 --- a/src/main/java/umc/meme/shop/domain/favorite/repository/FavoritePortfolioRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package umc.meme.shop.domain.favorite.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; -import umc.meme.shop.domain.model.entity.Model; -import umc.meme.shop.domain.portfolio.entity.Portfolio; - -import java.util.List; -import java.util.Optional; - -public interface FavoritePortfolioRepository extends JpaRepository { - List findByModel(Model model); - boolean existsByModelAndPortfolio(Model model, Portfolio portfolio); - Optional findByModelAndPortfolio(Model model, Portfolio portfolio); -} diff --git a/src/main/java/umc/meme/shop/domain/model/controller/ModelController.java b/src/main/java/umc/meme/shop/domain/model/controller/ModelController.java deleted file mode 100644 index 4eb6ccf..0000000 --- a/src/main/java/umc/meme/shop/domain/model/controller/ModelController.java +++ /dev/null @@ -1,119 +0,0 @@ -package umc.meme.shop.domain.model.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; -import umc.meme.shop.domain.artist.dto.request.ArtistProfileDto; -import umc.meme.shop.domain.favorite.dto.request.FavoriteArtistDto; -import umc.meme.shop.domain.favorite.dto.request.FavoritePortfolioDto; -import umc.meme.shop.domain.model.dto.request.ModelProfileDto; -import umc.meme.shop.domain.model.service.ModelService; -import umc.meme.shop.domain.portfolio.entity.enums.Category; -import umc.meme.shop.global.SuccessStatus; -import umc.meme.shop.global.response.ApiResponse; - - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1") -public class ModelController { - private final ModelService modelService; - - /**temp model create method**/ - @PostMapping("/model") - public ApiResponse createModel(@RequestBody ModelProfileDto profileDto){ - modelService.createModel(profileDto); - return ApiResponse.SuccessResponse(SuccessStatus.TEMP); - } - - @Operation(summary = "모델 프로필 관리") - @PatchMapping("/mypage/profile/model") - public ApiResponse updateModelProfile (@RequestBody ModelProfileDto modelProfileDto){ - modelService.updateModelProfile(modelProfileDto); - return ApiResponse.SuccessResponse(SuccessStatus.MODEL_PROFILE_UPDATE); - } - - /**favorite**/ - - @Operation(summary = "관심 아티스트 조회", description = "관심 아티스트를 조회하는 API입니다.") - @GetMapping("/mypage/{modelId}/favorite/artist") - public ApiResponse getFavoriteArtist(@PathVariable Long modelId, - @RequestParam(value = "page", defaultValue = "0", required = false)int page){ - return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_ARTIST_GET, modelService.getFavoriteArtist(modelId, page)); - } - - @Operation(summary = "관심 메이크업 조회", description = "관심 메이크업을 조회하는 API입니다.") - @GetMapping("/mypage/{modelId}/favorite/portfolio") - public ApiResponse getFavoritePortfolio(@PathVariable Long modelId, - @RequestParam(value = "page", defaultValue = "0", required = false) int page - ){ - return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_PORTFOLIO_GET, modelService.getFavoritePortfolio(modelId, page)); - } - - @Operation(summary = "관심 아티스트 추가", description = "관심 아티스트를 추가하는 API입니다.") - @PostMapping("/mypage/favorite/artist") - public ApiResponse postFavoriteArtist(@RequestBody FavoriteArtistDto favoriteArtistDto) { - modelService.addFavoriteArtist(favoriteArtistDto); - return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_ARTIST_POST); - } - - @Operation(summary = "관심 메이크업 추가", description = "관심 메이크업을 추가하는 API입니다.") - @PostMapping("/mypage/favorite/portfolio") - public ApiResponse postFavoritePortfolio(@RequestBody FavoritePortfolioDto favoritePortfolioDto) { - modelService.addFavoritePortfolio(favoritePortfolioDto); - return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_PORTFOLIO_POST); - } - - @Operation(summary = "관심 아티스트 삭제", description = "관심 아티스트를 삭제하는 API입니다.") - @DeleteMapping("/mypage/favorite/artist") - public ApiResponse deleteFavoriteArtist(@RequestBody FavoriteArtistDto favoriteArtistDto) { - modelService.deleteFavoriteArtist(favoriteArtistDto); - return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_ARTIST_DELETE); - } - - @Operation(summary = "관심 메이크업 삭제", description = "관심 메이크업을 삭제하는 API입니다.") - @DeleteMapping("/mypage/favorite/portfolio") - public ApiResponse deleteFavoritePortfolio(@RequestBody FavoritePortfolioDto favoritePortfolioDto) { - modelService.deleteFavoritePortfolio(favoritePortfolioDto); - return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_PORTFOLIO_DELETE); - } - - - /**search**/ - - @Operation(summary = "메이크업 검색", description = "메이크업을 검색/최근 검색어로 검색하는 API입니다.") - @GetMapping("/search") - public ApiResponse search(@Parameter String query, - @RequestParam(value = "page", defaultValue = "0", required = false) int page, - @RequestParam(value = "sort", defaultValue = "desc") String sort){ - return ApiResponse.SuccessResponse(SuccessStatus.SEARCH_GET, modelService.search(query, page, sort)); - } - - @Operation(summary = "메이크업 검색 - 관심 아티스트", description = "관심 아티스트로 검색하는 API입니다.") - @GetMapping("/search/artist") - public ApiResponse searchArtist(@Parameter Long artistId, - @RequestParam(value = "page", defaultValue = "0", required = false) int page, - @RequestParam(value = "sort", defaultValue = "desc") String sort - ){ - return ApiResponse.SuccessResponse(SuccessStatus.SEARCH_GET, modelService.searchArtist(artistId, page, sort)); - } - - @Operation(summary = "메이크업 검색 - 카테고리", description = "메이크업 카테고리로 검색하는 API입니다.") - @GetMapping("/search/category") - public ApiResponse searchCategory(@Parameter Category category, - @RequestParam(value = "page", defaultValue = "0", required = false) int page, - @RequestParam(value = "sort", defaultValue = "desc") String sort - ){ - return ApiResponse.SuccessResponse(SuccessStatus.SEARCH_GET, modelService.searchCategory(category, page, sort)); - } - - @Operation(summary = "메이크업 검색 - 전체", description = "메이크업 전체를 검색하는 API입니다.") - @GetMapping("/search/all") - public ApiResponse searchAll( @RequestParam(value = "page", defaultValue = "0", required = false) int page, - @RequestParam(value = "sort", defaultValue = "desc") String sort - ){ - return ApiResponse.SuccessResponse(SuccessStatus.SEARCH_GET, modelService.searchAll(page, sort)); - } - -} diff --git a/src/main/java/umc/meme/shop/domain/model/dto/request/ModelProfileDto.java b/src/main/java/umc/meme/shop/domain/model/dto/request/ModelProfileDto.java deleted file mode 100644 index cd72b1d..0000000 --- a/src/main/java/umc/meme/shop/domain/model/dto/request/ModelProfileDto.java +++ /dev/null @@ -1,16 +0,0 @@ -package umc.meme.shop.domain.model.dto.request; - -import lombok.Data; -import umc.meme.shop.domain.artist.entity.enums.Gender; -import umc.meme.shop.domain.model.entity.enums.PersonalColor; -import umc.meme.shop.domain.model.entity.enums.SkinType; - -@Data -public class ModelProfileDto { - private Long modelId; - private String profileImg; - private String nickname; - private Gender gender; - private SkinType skinType; - private PersonalColor personalColor; -} diff --git a/src/main/java/umc/meme/shop/domain/model/entity/Model.java b/src/main/java/umc/meme/shop/domain/model/entity/Model.java deleted file mode 100644 index 9fa7b13..0000000 --- a/src/main/java/umc/meme/shop/domain/model/entity/Model.java +++ /dev/null @@ -1,86 +0,0 @@ -package umc.meme.shop.domain.model.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; -import umc.meme.shop.domain.artist.entity.enums.Gender; -import umc.meme.shop.domain.favorite.entity.FavoriteArtist; -import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; -import umc.meme.shop.domain.model.dto.request.ModelProfileDto; -import umc.meme.shop.domain.model.entity.enums.PersonalColor; -import umc.meme.shop.domain.model.entity.enums.SkinType; -import umc.meme.shop.domain.reservation.entity.Reservation; -import umc.meme.shop.domain.review.entity.Review; -import umc.meme.shop.domain.user.User; - -import java.util.Date; -import java.util.List; - -@SuperBuilder -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class Model extends User { - - @Column(nullable = true, length = 500) - private String introduction; - - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private SkinType skinType; - - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private PersonalColor personalColor; - - private Date inactive; - - @OneToMany(cascade = CascadeType.ALL, mappedBy = "model") - private List favoritePortfolioList; - - @OneToMany(cascade = CascadeType.ALL, mappedBy = "model") - private List favoriteArtistList; - - @OneToMany(cascade = CascadeType.ALL, mappedBy = "model") - private List reservationList; - - @OneToMany(cascade = CascadeType.ALL, mappedBy = "model") - private List reviewList; - - public void updateModel(ModelProfileDto request) { - if(request.getProfileImg() != null){ - this.profileImg = request.getProfileImg(); - } - if(request.getNickname() != null){ - this.nickname = request.getNickname(); - } - if(request.getGender() != null){ - this.gender = request.getGender(); - } - if(request.getSkinType() != null){ - this.skinType = request.getSkinType(); - } - if(request.getPersonalColor() != null){ - this.personalColor = request.getPersonalColor(); - } - } - - public void updateFavoriteArtistList(FavoriteArtist artist){ - this.favoriteArtistList.add(artist); - } - - public void updateFavoritePortfolioList(FavoritePortfolio portfolio){ - this.favoritePortfolioList.add(portfolio); - } - public void updateReservationList(Reservation reservation){ - this.reservationList.add(reservation); - } - - public void updateReviewList(Review review){ - this.reviewList.add(review); - } -} diff --git a/src/main/java/umc/meme/shop/domain/model/entity/enums/PersonalColor.java b/src/main/java/umc/meme/shop/domain/model/entity/enums/PersonalColor.java deleted file mode 100644 index dadc7a1..0000000 --- a/src/main/java/umc/meme/shop/domain/model/entity/enums/PersonalColor.java +++ /dev/null @@ -1,5 +0,0 @@ -package umc.meme.shop.domain.model.entity.enums; - -public enum PersonalColor { - SPRING, SUMMER, AUTUMN, WINTER -} diff --git a/src/main/java/umc/meme/shop/domain/model/entity/enums/SkinType.java b/src/main/java/umc/meme/shop/domain/model/entity/enums/SkinType.java deleted file mode 100644 index 6f169da..0000000 --- a/src/main/java/umc/meme/shop/domain/model/entity/enums/SkinType.java +++ /dev/null @@ -1,5 +0,0 @@ -package umc.meme.shop.domain.model.entity.enums; - -public enum SkinType { - DRY, COMMON, OILY, COMBINATIONAL -} diff --git a/src/main/java/umc/meme/shop/domain/model/repository/ModelRepository.java b/src/main/java/umc/meme/shop/domain/model/repository/ModelRepository.java deleted file mode 100644 index 0dcf9ab..0000000 --- a/src/main/java/umc/meme/shop/domain/model/repository/ModelRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package umc.meme.shop.domain.model.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import umc.meme.shop.domain.model.entity.Model; - -public interface ModelRepository extends JpaRepository { -} diff --git a/src/main/java/umc/meme/shop/domain/model/service/ModelService.java b/src/main/java/umc/meme/shop/domain/model/service/ModelService.java deleted file mode 100644 index 932bf16..0000000 --- a/src/main/java/umc/meme/shop/domain/model/service/ModelService.java +++ /dev/null @@ -1,242 +0,0 @@ -package umc.meme.shop.domain.model.service; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.*; -import org.springframework.stereotype.Service; -import umc.meme.shop.domain.artist.converter.ArtistConverter; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.artist.repository.ArtistRepository; -import umc.meme.shop.domain.favorite.dto.request.FavoriteArtistDto; -import umc.meme.shop.domain.favorite.dto.request.FavoritePortfolioDto; -import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistPageResponseDto; -import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistResponseDto; -import umc.meme.shop.domain.favorite.dto.response.FavoritePortfolioResponsePageDto; -import umc.meme.shop.domain.favorite.entity.FavoriteArtist; -import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; -import umc.meme.shop.domain.favorite.repository.FavoriteArtistRepository; -import umc.meme.shop.domain.favorite.repository.FavoritePortfolioRepository; -import umc.meme.shop.domain.model.dto.request.ModelProfileDto; -import umc.meme.shop.domain.model.entity.Model; -import umc.meme.shop.domain.model.repository.ModelRepository; -import umc.meme.shop.domain.portfolio.converter.PortfolioConverter; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioPageDto; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.portfolio.entity.enums.Category; -import umc.meme.shop.domain.portfolio.repository.PortfolioRepository; -import umc.meme.shop.global.ErrorStatus; -import umc.meme.shop.global.exception.GlobalException; - -import java.util.ArrayList; -import java.util.List; - -@Service -@RequiredArgsConstructor -public class ModelService { - private final ModelRepository modelRepository; - private final ArtistRepository artistRepository; - private final FavoriteArtistRepository favoriteArtistRepository; - private final FavoritePortfolioRepository favoritePortfolioRepository; - private final PortfolioRepository portfolioRepository; - - /**temp model create method**/ - @Transactional - public void createModel(ModelProfileDto dto){ - Model model = Model.builder() - .profileImg(dto.getProfileImg()) - .nickname(dto.getNickname()) - .introduction("") - .email("") - .name("") - .gender(dto.getGender()) - .skinType(dto.getSkinType()) - .personalColor(dto.getPersonalColor()) - .build(); - modelRepository.save(model); - } - - //모델 프로필 관리 - @Transactional - public void updateModelProfile(ModelProfileDto request){ - Model model = modelRepository.findById(request.getModelId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - - model.updateModel(request); - } - - - //관심 아티스트 조회 - @Transactional - public FavoriteArtistPageResponseDto getFavoriteArtist(Long modelId, int page){ - Model model = modelRepository.findById(modelId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - - //paging - List favoriteArtistList = model.getFavoriteArtistList(); - Pageable pageable = PageRequest.of(page, 30); - int start = (int) pageable.getOffset(); - int end = Math.min((start + pageable.getPageSize()), favoriteArtistList.size()); - - Page favoriteArtistPage = new PageImpl<>(favoriteArtistList.subList(start, end), - pageable, favoriteArtistList.size()); - - List content = new ArrayList<>(); - for(int i=0; i new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - FavoriteArtistResponseDto dto = FavoriteArtistResponseDto.from(artist); - content.add(dto); - } - - return ArtistConverter.favoriteArtistPageConverter(favoriteArtistPage, content); - } - - //관심 메이크업 조회 - @Transactional - public FavoritePortfolioResponsePageDto getFavoritePortfolio(Long modelId, int page){ - Model model = modelRepository.findById(modelId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - - //page - List favoritePortfolioList = model.getFavoritePortfolioList(); - Pageable pageable = PageRequest.of(page, 30); - int start = (int) pageable.getOffset(); - int end = Math.min((start + pageable.getPageSize()), favoritePortfolioList.size()); - - //list를 page로 변환 - Page favoritePortfolioPage = new PageImpl<>(favoritePortfolioList.subList(start, end), - pageable, favoritePortfolioList.size()); - - return PortfolioConverter.favoritePortfolioPageConverter(favoritePortfolioPage); - } - - //관심 아티스트 추가 - @Transactional - public void addFavoriteArtist(FavoriteArtistDto favoriteArtistDto) { - Model model = modelRepository.findById(favoriteArtistDto.getModelId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - - Artist artist = artistRepository.findById(favoriteArtistDto.getArtistId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - - //이미 관심 아티스트가 존재하는 경우 - if (favoriteArtistRepository.existsByModelAndArtistId(model, artist.getUserId())) { - throw new GlobalException(ErrorStatus.ALREADY_EXIST_FAVORITE_ARTIST); - } - - FavoriteArtist favoriteArtist = FavoriteArtist.builder() - .artistId(artist.getUserId()) - .model(model) - .build(); - model.updateFavoriteArtistList(favoriteArtist); - favoriteArtistRepository.save(favoriteArtist); - } - - //관심 메이크업 추가 - @Transactional - public void addFavoritePortfolio(FavoritePortfolioDto favoritePortfolioDto) { - Model model = modelRepository.findById(favoritePortfolioDto.getModelId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - - Portfolio portfolio = portfolioRepository.findById(favoritePortfolioDto.getPortfolioId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); - - //이미 관심 포트폴리오가 존재하는 경우 - if (favoritePortfolioRepository.existsByModelAndPortfolio(model,portfolio)) { - throw new GlobalException(ErrorStatus.ALREADY_EXIST_FAVORITE_PORTFOLIO); - } - - FavoritePortfolio favoritePortfolio = FavoritePortfolio.builder() - .model(model) - .portfolio(portfolio) - .build(); - model.updateFavoritePortfolioList(favoritePortfolio); - favoritePortfolioRepository.save(favoritePortfolio); - } - - //관심 아티스트 삭제 - @Transactional - public void deleteFavoriteArtist(FavoriteArtistDto favoriteArtistDto){ - Model model = modelRepository.findById(favoriteArtistDto.getModelId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - - Artist artist = artistRepository.findById(favoriteArtistDto.getArtistId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - - FavoriteArtist favoriteArtist = favoriteArtistRepository.findByModelAndArtistId(model, artist.getUserId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_FAVORITE_ARTIST)); - favoriteArtistRepository.delete(favoriteArtist); - } - - //관심 메이크업 삭제 - @Transactional - public void deleteFavoritePortfolio(FavoritePortfolioDto favoritePortfolioDto) { - Model model = modelRepository.findById(favoritePortfolioDto.getModelId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - - Portfolio portfolio = portfolioRepository.findById(favoritePortfolioDto.getPortfolioId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); - - FavoritePortfolio favoritePortfolio = favoritePortfolioRepository.findByModelAndPortfolio(model, portfolio) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_FAVORITE_PORTFOLIO)); - favoritePortfolioRepository.delete(favoritePortfolio); - } - - - /**search**/ - //검색 - public PortfolioPageDto search(String query, int page, String sortBy){ - Pageable pageable = setPageRequest(page, sortBy); - - //query 검색 - Page portfolioPage = portfolioRepository.search(query, pageable); - - if(portfolioPage.getContent().isEmpty()) - throw new GlobalException(ErrorStatus.SEARCH_NOT_FOUNT); - - return PortfolioConverter.portfolioPageConverter(portfolioPage); - } - - //카테고리 검색 - public PortfolioPageDto searchCategory(Category category, int page, String sortBy){ - Pageable pageable = setPageRequest(page, sortBy); - Page portfolioPage = portfolioRepository.findByCategory(category, pageable); - return PortfolioConverter.portfolioPageConverter(portfolioPage); - } - - //관심 아티스트 검색 - public PortfolioPageDto searchArtist(Long artistId, int page, String sortBy){ - Artist artist = artistRepository.findById(artistId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - - Pageable pageable = setPageRequest(page, sortBy); - Page portfolioPage = portfolioRepository.findByArtist(artist, pageable); - return PortfolioConverter.portfolioPageConverter(portfolioPage); - } - - //전체 조회 - public PortfolioPageDto searchAll(int page, String sortBy){ - Pageable pageable = setPageRequest(page, sortBy); - Page portfolioPage = portfolioRepository.findAllNotBlocked(pageable); - return PortfolioConverter.portfolioPageConverter(portfolioPage); - } - - - //검색하기 정렬 기준 설정 - private Pageable setPageRequest(int page, String sortBy){ - - Sort sort; - if(sortBy.equals("desc")) - sort = Sort.by("price").descending(); - else if(sortBy.equals("asc")) - sort = Sort.by("price").ascending(); - else if(sortBy.equals("review")) - sort = Sort.by("averageStars").descending(); - else - throw new GlobalException(ErrorStatus.INVALID_SORT_CRITERIA); - - return PageRequest.of(page, 30, sort); - } - -} diff --git a/src/main/java/umc/meme/shop/domain/mypage/controller/MyPageController.java b/src/main/java/umc/meme/shop/domain/mypage/controller/MyPageController.java deleted file mode 100644 index 79007df..0000000 --- a/src/main/java/umc/meme/shop/domain/mypage/controller/MyPageController.java +++ /dev/null @@ -1,43 +0,0 @@ -package umc.meme.shop.domain.mypage.controller; - -import io.swagger.v3.oas.annotations.Operation; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; -import umc.meme.shop.domain.mypage.dto.request.MypageInquiryDto; -import umc.meme.shop.domain.mypage.service.MypageService; -import umc.meme.shop.domain.portfolio.dto.request.CreatePortfolioDto; -import umc.meme.shop.global.SuccessStatus; -import umc.meme.shop.global.response.ApiResponse; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1/mypage") -public class MyPageController { - - private final MypageService mypageService; - - @Operation(summary = "마이페이지 조회") - @GetMapping("/profile/{userId}") - public ApiResponse getProfile(@PathVariable Long userId) { - return ApiResponse.SuccessResponse(SuccessStatus.MYPAGE_GET, mypageService.getProfile(userId)); - } - - @Operation(summary = "약관 및 정책", description = "약관 및 정책을 조회하는 API입니다.") - @GetMapping("/tos") - public ApiResponse tos(){ - return ApiResponse.SuccessResponse(SuccessStatus.TOS_GET, mypageService.getTos()); - } - - @Operation(summary = "문의하기", description = "문의하기 API입니다.") - @PostMapping("/contact") - public ApiResponse contact(@RequestBody MypageInquiryDto mypageInquiryDto){ - mypageService.createInquiry(mypageInquiryDto); - return ApiResponse.SuccessResponse(SuccessStatus.CONTACT_CREATE); - } - - @Operation(summary = "문의 조회하기", description = "문의 조회하기 API입니다.") - @GetMapping("/contact/{userId}") - public ApiResponse contact(@PathVariable Long userId){ - return ApiResponse.SuccessResponse(SuccessStatus.CONTACT_GET, mypageService.getInquiry(userId)); - } -} diff --git a/src/main/java/umc/meme/shop/domain/mypage/dto/request/MypageInquiryDto.java b/src/main/java/umc/meme/shop/domain/mypage/dto/request/MypageInquiryDto.java deleted file mode 100644 index ca182bf..0000000 --- a/src/main/java/umc/meme/shop/domain/mypage/dto/request/MypageInquiryDto.java +++ /dev/null @@ -1,24 +0,0 @@ -package umc.meme.shop.domain.mypage.dto.request; - - -import lombok.*; -import umc.meme.shop.domain.mypage.entity.Inquiry; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class MypageInquiryDto { - private Long inquiryId; - private Long userId; - private String inquiryTitle; - private String inquiryText; - - public static MypageInquiryDto from(Inquiry inquiry) { - return MypageInquiryDto.builder() - .inquiryId(inquiry.getInquiryId()) - .inquiryTitle(inquiry.getInquiryTitle()) - .inquiryText(inquiry.getInquiryText()) - .build(); - } -} diff --git a/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageDetailDto.java b/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageDetailDto.java deleted file mode 100644 index b2373c7..0000000 --- a/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageDetailDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package umc.meme.shop.domain.mypage.dto.response; - - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.artist.entity.enums.Gender; - -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Data -public class MypageDetailDto { - private String profileImg; - private String nickname; - private String name; - private Gender gender; - private String email; -} diff --git a/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageTosDto.java b/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageTosDto.java deleted file mode 100644 index 10d45e6..0000000 --- a/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageTosDto.java +++ /dev/null @@ -1,10 +0,0 @@ -package umc.meme.shop.domain.mypage.dto.response; - -import lombok.Builder; -import lombok.Data; - -@Builder -@Data -public class MypageTosDto { - private String tos; -} diff --git a/src/main/java/umc/meme/shop/domain/mypage/entity/Inquiry.java b/src/main/java/umc/meme/shop/domain/mypage/entity/Inquiry.java deleted file mode 100644 index 32b7bdf..0000000 --- a/src/main/java/umc/meme/shop/domain/mypage/entity/Inquiry.java +++ /dev/null @@ -1,36 +0,0 @@ -package umc.meme.shop.domain.mypage.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.mypage.dto.request.MypageInquiryDto; - -@Builder -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class Inquiry { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "inquiry_id") - private Long inquiryId; - - @Column(nullable = false) - private String inquiryTitle; - - @Column(nullable = false) - private String inquiryText; - - - public void updateInquiry(MypageInquiryDto request) { - if (request.getInquiryTitle() != null) { - this.inquiryTitle = request.getInquiryTitle(); - } - if (request.getInquiryText() != null) { - this.inquiryText = request.getInquiryText(); - } - } -} diff --git a/src/main/java/umc/meme/shop/domain/mypage/repository/InquiryRepository.java b/src/main/java/umc/meme/shop/domain/mypage/repository/InquiryRepository.java deleted file mode 100644 index 6005b4c..0000000 --- a/src/main/java/umc/meme/shop/domain/mypage/repository/InquiryRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package umc.meme.shop.domain.mypage.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import umc.meme.shop.domain.mypage.entity.Inquiry; - -public interface InquiryRepository extends JpaRepository { -} diff --git a/src/main/java/umc/meme/shop/domain/mypage/service/MypageService.java b/src/main/java/umc/meme/shop/domain/mypage/service/MypageService.java deleted file mode 100644 index fadca17..0000000 --- a/src/main/java/umc/meme/shop/domain/mypage/service/MypageService.java +++ /dev/null @@ -1,69 +0,0 @@ -package umc.meme.shop.domain.mypage.service; - -import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.artist.repository.ArtistRepository; -import umc.meme.shop.domain.model.entity.Model; -import umc.meme.shop.domain.model.repository.ModelRepository; -import umc.meme.shop.domain.mypage.dto.request.MypageInquiryDto; -import umc.meme.shop.domain.mypage.dto.response.MypageDetailDto; -import umc.meme.shop.domain.mypage.dto.response.MypageTosDto; -import umc.meme.shop.domain.mypage.entity.Inquiry; -import umc.meme.shop.domain.mypage.repository.InquiryRepository; -import umc.meme.shop.domain.mypage.dto.response.MypageDetailDto; -import umc.meme.shop.domain.mypage.dto.response.MypageTosDto; -import umc.meme.shop.domain.user.User; -import umc.meme.shop.domain.user.UserRepository; -import umc.meme.shop.global.ErrorStatus; -import umc.meme.shop.global.exception.GlobalException; - -@Service -@RequiredArgsConstructor -public class MypageService { - - private final ModelRepository modelRepository; - private final ArtistRepository artistRepository; - private final InquiryRepository inquiryRepository; - private final UserRepository userRepository; - @Transactional - public MypageDetailDto getProfile(Long userId) { - User user = userRepository.findById(userId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_USER)); - return MypageDetailDto.builder() - .profileImg(user.getProfileImg()) - .nickname(user.getNickname()) - .name(user.getName()) - .gender(user.getGender()) - .email(user.getEmail()) - .build(); - } - - //약관 조회 - @Transactional - public MypageTosDto getTos() { - return MypageTosDto.builder() - .tos("Example") - .build(); - } - - //문의하기 - @Transactional - public void createInquiry(MypageInquiryDto mypageInquiryDto) { - Inquiry inquiry = new Inquiry(); - inquiry.updateInquiry(mypageInquiryDto); - inquiryRepository.save(inquiry); - } - - // 문의하기 조회 - @Transactional - public MypageInquiryDto getInquiry(Long inquiryId) { - Inquiry inquiry = inquiryRepository.findById(inquiryId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_INQUIRY)); - - return MypageInquiryDto.from(inquiry); - } - -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/controller/PortfolioController.java b/src/main/java/umc/meme/shop/domain/portfolio/controller/PortfolioController.java deleted file mode 100644 index 2a8aaa7..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/controller/PortfolioController.java +++ /dev/null @@ -1,46 +0,0 @@ -package umc.meme.shop.domain.portfolio.controller; - -import io.swagger.v3.oas.annotations.Operation; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; -import umc.meme.shop.domain.portfolio.dto.request.CreatePortfolioDto; -import umc.meme.shop.domain.portfolio.dto.request.UpdatePortfolioDto; -import umc.meme.shop.domain.portfolio.service.PortfolioService; -import umc.meme.shop.global.SuccessStatus; -import umc.meme.shop.global.response.ApiResponse; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1/portfolio") -public class PortfolioController { - private final PortfolioService portfolioService; - - @Operation(summary = "포트폴리오 생성", description = "포트폴리오를 생성하는 API입니다.") - @PostMapping("/") - public ApiResponse createPortfolio(@RequestBody CreatePortfolioDto portfolioDto){ - portfolioService.createPortfolio(portfolioDto); - return ApiResponse.SuccessResponse(SuccessStatus.PORTFOLIO_CREATE); - } - - @Operation(summary = "포트폴리오 전체 조회", description = "포트폴리오 전체를 조회하는 API입니다.") - @GetMapping("/{artistId}") - public ApiResponse getPortfolio(@PathVariable Long artistId, - @RequestParam(value = "page", defaultValue = "0", required = false) int page - ){ - return ApiResponse.SuccessResponse(SuccessStatus.PORTFOLIO_GET, portfolioService.getPortfolio(artistId, page)); - } - - @Operation(summary = "포트폴리오 조회", description = "특정 포트폴리오를 조회하는 API입니다.") - @GetMapping("/{portfolioId}/details") - public ApiResponse getPortfolioDetails(@PathVariable Long portfolioId) { - return ApiResponse.SuccessResponse(SuccessStatus.PORTFOLIO_GET, portfolioService.getPortfolioDetails(portfolioId)); - } - - @Operation(summary = "포트폴리오 수정/삭제", description = "포트폴리오를 수정/삭제하는 API입니다.") - @PatchMapping("/") - public ApiResponse updatePortfolio(@RequestBody UpdatePortfolioDto portfolioDto){ - // TODO: PortfolioImg 추가 - portfolioService.updatePortfolio(portfolioDto); - return ApiResponse.SuccessResponse(SuccessStatus.PORTFOLIO_UPDATE); - } -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/converter/PortfolioConverter.java b/src/main/java/umc/meme/shop/domain/portfolio/converter/PortfolioConverter.java deleted file mode 100644 index fcaefb6..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/converter/PortfolioConverter.java +++ /dev/null @@ -1,47 +0,0 @@ -package umc.meme.shop.domain.portfolio.converter; - -import org.springframework.data.domain.Page; -import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistResponseDto; -import umc.meme.shop.domain.favorite.dto.response.FavoritePortfolioResponseDto; -import umc.meme.shop.domain.favorite.dto.response.FavoritePortfolioResponsePageDto; -import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioPageDto; -import umc.meme.shop.domain.portfolio.entity.Portfolio; - -import java.util.List; - -public class PortfolioConverter { - - public static FavoritePortfolioResponsePageDto favoritePortfolioPageConverter(Page page){ - - List content = page.stream() - .map(FavoritePortfolioResponseDto::from) - .toList(); - - return FavoritePortfolioResponsePageDto.builder() - .content(content) - .pageSize(page.getSize()) - .currentPage(page.getNumber()) - .totalNumber(page.getNumberOfElements()) - .totalPage(page.getTotalPages()) - .build(); - } - - public static PortfolioPageDto portfolioPageConverter(Page page){ - - List content = page.stream() - .map(PortfolioDto::from) - .toList(); - - return PortfolioPageDto.builder() - .content(content) - .pageSize(page.getSize()) - .currentPage(page.getNumber()) - .totalNumber(page.getNumberOfElements()) - .totalPage(page.getTotalPages()) - .build(); - } -} - - diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/request/CreatePortfolioDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/request/CreatePortfolioDto.java deleted file mode 100644 index db068cb..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/dto/request/CreatePortfolioDto.java +++ /dev/null @@ -1,29 +0,0 @@ -package umc.meme.shop.domain.portfolio.dto.request; - -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.portfolio.entity.PortfolioImg; -import umc.meme.shop.domain.portfolio.entity.enums.Category; - -import java.util.List; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CreatePortfolioDto { - @NotBlank(message = "artistId를 입력해주세요.") - private Long artistId; - @NotBlank(message = "카테고리를 입력해주세요") - private Category category; - @NotBlank(message = "메이크업 명을 입력해주세요") - private String makeupName; - @NotBlank(message = "가격을 입력해주세요") - private int price; - @NotBlank(message = "메이크업 정보를 입력해주세요") - private String info; - @NotBlank(message = "포트폴리오 이미지를 업로드해주세요") - private List portfolioImgSrc; -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/request/UpdatePortfolioDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/request/UpdatePortfolioDto.java deleted file mode 100644 index 346865a..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/dto/request/UpdatePortfolioDto.java +++ /dev/null @@ -1,25 +0,0 @@ -package umc.meme.shop.domain.portfolio.dto.request; - -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioImgDto; -import umc.meme.shop.domain.portfolio.entity.PortfolioImg; -import umc.meme.shop.domain.portfolio.entity.enums.Category; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class UpdatePortfolioDto { - @NotBlank(message = "artistId를 입력해주세요.") - private Long artistId; - @NotBlank(message = "portfolioId를 입력해주세요.") - private Long portfolioId; - private Category category; - private String makeupName; - private int price; - private String info; - private Boolean isBlock; - private PortfolioImgDto portfolioImg; -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioDto.java deleted file mode 100644 index 372677a..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioDto.java +++ /dev/null @@ -1,89 +0,0 @@ -package umc.meme.shop.domain.portfolio.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.artist.entity.enums.MakeupLocation; -import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.portfolio.entity.enums.Category; -import umc.meme.shop.domain.review.dto.response.ReviewResponseDto; - -import java.util.List; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class PortfolioDto { - private Long portfolioId; - - private Category category; - - private String artistName; - - private String makeupName; - - private int price; - - private String info; - - private MakeupLocation makeupLocation; //샵 재직 여부 - - private String shopLocation; //샵 위치 - - private List region; //활동 가능 지역 - - private Boolean isBlock; - - private String averageStars; - - private int reviewCount; //리뷰 개수 - - private List portfolioImgDtoList; - - - public static PortfolioDto from(Portfolio portfolio) { - Artist artist = portfolio.getArtist(); - - // PortfolioImg 리스트를 PortfolioImgDto 리스트로 변환 - List portfolioImgDtoList = portfolio.getPortfolioImgList() - .stream() - .map(portfolioImg -> new PortfolioImgDto(portfolioImg.getPortfolioImgId(), portfolioImg.getSrc(), false)) - .toList(); - - return PortfolioDto.builder() - .portfolioId(portfolio.getPortfolioId()) - .category(portfolio.getCategory()) - .artistName(artist.getName()) - .makeupName(portfolio.getMakeupName()) - .price(portfolio.getPrice()) - .info(portfolio.getInfo()) - .makeupLocation(artist.getMakeupLocation()) - .shopLocation(artist.getShopLocation()) - .region(artist.getRegion()) - .isBlock(portfolio.isBlock()) - .portfolioImgDtoList(portfolioImgDtoList) - .averageStars(portfolio.getAverageStars()) - .reviewCount(portfolio.getReviewList().size()) - .build(); - } - - //관심 메이크업 - public static PortfolioDto from(FavoritePortfolio favoritePortfolio){ - Portfolio portfolio = favoritePortfolio.getPortfolio(); - return PortfolioDto.builder() - .portfolioId(portfolio.getPortfolioId()) - .category(portfolio.getCategory()) - .makeupName(portfolio.getMakeupName()) - .price(portfolio.getPrice()) - .info(portfolio.getInfo()) - .isBlock(portfolio.isBlock()) - .averageStars(portfolio.getAverageStars()) - .reviewCount(portfolio.getReviewList().size()) - .build(); - } - -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioImgDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioImgDto.java deleted file mode 100644 index fb3e515..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioImgDto.java +++ /dev/null @@ -1,21 +0,0 @@ -package umc.meme.shop.domain.portfolio.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class PortfolioImgDto { - private Long portfolioImgId; - - //이미지 링크 - private String portfolioImgSrc; - - //삭제 여부 - - private boolean isDelete = false; -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioPageDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioPageDto.java deleted file mode 100644 index 16d6cad..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioPageDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package umc.meme.shop.domain.portfolio.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class PortfolioPageDto { - private List content; - private int currentPage; //현재 페이지 번호 - private int pageSize; //페이지 크기 - private int totalNumber; //전체 메이크업 개수 - private int totalPage; //전체 페이지 개수 -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/entity/Portfolio.java b/src/main/java/umc/meme/shop/domain/portfolio/entity/Portfolio.java deleted file mode 100644 index b0474d9..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/entity/Portfolio.java +++ /dev/null @@ -1,96 +0,0 @@ -package umc.meme.shop.domain.portfolio.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.portfolio.dto.request.UpdatePortfolioDto; -import umc.meme.shop.domain.portfolio.entity.enums.Category; -import umc.meme.shop.domain.portfolio.repository.PortfolioImgRepository; -import umc.meme.shop.domain.review.entity.Review; - -import java.util.List; - - -@Builder -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class Portfolio { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "portfolio_id") - private Long portfolioId; - - @ManyToOne - @JoinColumn(name="user_id", nullable = false) - private Artist artist; - - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private Category category; - - @Column(nullable = false) - private String makeupName; - - @Column(nullable = false) - private int price; - - @Column(nullable = false) - private String info; - - @OneToMany(cascade = CascadeType.ALL, mappedBy = "portfolio") - private List portfolioImgList; - - @Column - private String averageStars; - - @Column(nullable = false, columnDefinition = "TINYINT(1) default 0") - private boolean isBlock; - - @OneToMany(cascade = CascadeType.ALL, mappedBy = "portfolio") - private List reviewList; - - public void updatePortfolio(UpdatePortfolioDto request) { - - if(request.getCategory() != null){ - this.category = request.getCategory(); - } - - if(request.getPrice() >= 0){ - this.price = request.getPrice(); - } - - if(request.getInfo() != null){ - this.info = request.getInfo(); - } - - if(request.getMakeupName() != null){ - this.makeupName = request.getMakeupName(); - } - - this.isBlock = request.getIsBlock(); - } - - public void updateReviewList(Review review){ - this.reviewList.add(review); - } - - public void updateAverageStars(){ - int count = this.reviewList.size(); - if(count == 0) { - this.averageStars = "0.00"; - return; - } - - double stars = 0; - for(Review review : reviewList){ - stars += review.getStar(); - } - this.averageStars = String.format("%.2f", stars/count); - } - -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/entity/PortfolioImg.java b/src/main/java/umc/meme/shop/domain/portfolio/entity/PortfolioImg.java deleted file mode 100644 index ee7c74f..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/entity/PortfolioImg.java +++ /dev/null @@ -1,24 +0,0 @@ -package umc.meme.shop.domain.portfolio.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class PortfolioImg { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long portfolioImgId; - - @ManyToOne - @JoinColumn(name="portfolio_id", nullable = false) - private Portfolio portfolio; - - @Column(nullable = false) - private String src; -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/entity/enums/Category.java b/src/main/java/umc/meme/shop/domain/portfolio/entity/enums/Category.java deleted file mode 100644 index e6a0c21..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/entity/enums/Category.java +++ /dev/null @@ -1,16 +0,0 @@ -package umc.meme.shop.domain.portfolio.entity.enums; - -public enum Category { - DAILY("daily"), INTERVIEW("interview"), ACTOR("actor"), PARTY("party"), - WEDDING("wedding"), PROSTHETIC("prosthetic"), STUDIO("studio"), ETC("etc"); - - private String value; - - Category(String value){ - this.value = value; - } - - public String getValue(){ - return this.value; - } -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioImgRepository.java b/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioImgRepository.java deleted file mode 100644 index 8c50f50..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioImgRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package umc.meme.shop.domain.portfolio.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import umc.meme.shop.domain.portfolio.entity.PortfolioImg; - -public interface PortfolioImgRepository extends JpaRepository { -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioRepository.java b/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioRepository.java deleted file mode 100644 index fae7002..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioRepository.java +++ /dev/null @@ -1,35 +0,0 @@ -package umc.meme.shop.domain.portfolio.repository; - -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.portfolio.entity.enums.Category; - -import javax.sound.sampled.Port; -import java.util.List; - -public interface PortfolioRepository extends JpaRepository { - @Query("SELECT p FROM Portfolio p " + - "WHERE p.artist = :artist " + - "AND p.isBlock = false") - Page findByArtist(@Param("artist") Artist artist, Pageable pageable); - - @Query("SELECT p FROM Portfolio p " + - "WHERE p.category = :category " + - "AND p.isBlock = false ") - Page findByCategory(@Param("category") Category category, Pageable pageable); - - @Query("SELECT p FROM Portfolio p " + - "WHERE (p.makeupName LIKE %:query% OR p.info LIKE %:query%) " + - "AND p.isBlock = false" ) - Page search(@Param("query") String query, Pageable pageable); - - @Query("SELECT p FROM Portfolio p WHERE p.isBlock = false") - Page findAllNotBlocked(Pageable pageable); - - boolean existsByMakeupName(String makeupName); -} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/service/PortfolioService.java b/src/main/java/umc/meme/shop/domain/portfolio/service/PortfolioService.java deleted file mode 100644 index 5dcded1..0000000 --- a/src/main/java/umc/meme/shop/domain/portfolio/service/PortfolioService.java +++ /dev/null @@ -1,149 +0,0 @@ -package umc.meme.shop.domain.portfolio.service; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.artist.repository.ArtistRepository; -import umc.meme.shop.domain.portfolio.converter.PortfolioConverter; -import umc.meme.shop.domain.portfolio.dto.request.CreatePortfolioDto; -import umc.meme.shop.domain.portfolio.dto.request.UpdatePortfolioDto; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioImgDto; -import umc.meme.shop.domain.portfolio.dto.response.PortfolioPageDto; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.portfolio.entity.PortfolioImg; -import umc.meme.shop.domain.portfolio.repository.PortfolioImgRepository; -import umc.meme.shop.domain.portfolio.repository.PortfolioRepository; -import umc.meme.shop.global.ErrorStatus; -import umc.meme.shop.global.exception.GlobalException; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -@Service -@RequiredArgsConstructor -public class PortfolioService { - private final ArtistRepository artistRepository; - private final PortfolioRepository portfolioRepository; - private final PortfolioImgRepository portfolioImgRepository; - - //포트폴리오 생성 - @Transactional - public void createPortfolio(CreatePortfolioDto portfolioDto) { - Artist artist = artistRepository.findById(portfolioDto.getArtistId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - - List portfolioImgList = new ArrayList<>(); - for (String src : portfolioDto.getPortfolioImgSrc()) { - PortfolioImg portfolioImg = new PortfolioImg(); - portfolioImg.setSrc(src); - portfolioImgList.add(portfolioImg); - } - - - //포트폴리오 이름이 이미 존재할 시 - if(portfolioRepository.existsByMakeupName(portfolioDto.getMakeupName())) - throw new GlobalException(ErrorStatus.ALREADY_EXIST_PORTFOLIO); - - Portfolio portfolio = Portfolio.builder() - .artist(artist) - .category(portfolioDto.getCategory()) - .makeupName(portfolioDto.getMakeupName()) - .info(portfolioDto.getInfo()) - .price(portfolioDto.getPrice()) - .portfolioImgList(new ArrayList()) - .averageStars("0.00") - .isBlock(false) - .build(); - - for (PortfolioImg portfolioImg : portfolioImgList) { - portfolioImg.setPortfolio(portfolio); // Portfolio 객체 설정 - portfolio.getPortfolioImgList().add(portfolioImg); // Portfolio의 이미지 리스트에 추가 - } - - artist.updatePortfolioList(portfolio); - portfolioRepository.save(portfolio); - } - - // 포트폴리오 전체 조회 - @Transactional - public PortfolioPageDto getPortfolio(Long artistId, int page) { - Artist artist = artistRepository.findById(artistId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - - List portfolioList = artist.getPortfolioList(); - - //isblock이면 리스트에서 제거 - portfolioList.removeIf(Portfolio::isBlock); - - //page로 mapping - Pageable pageable = PageRequest.of(page, 30); - int start = (int) pageable.getOffset(); - int end = Math.min((start + pageable.getPageSize()), portfolioList.size()); - - //list를 page로 변환 - Page portfolioPage = new PageImpl<>(portfolioList.subList(start, end), - pageable, portfolioList.size()); - - return PortfolioConverter.portfolioPageConverter(portfolioPage); - } - - // 포트폴리오 하나만 조회 - public PortfolioDto getPortfolioDetails(Long portfolioId) { - Portfolio portfolio = portfolioRepository.findById(portfolioId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); - - if(portfolio.isBlock()) - throw new GlobalException(ErrorStatus.BLOCKED_PORTFOLIO); - - return PortfolioDto.from(portfolio); - } - - - // 포트폴리오 수정/삭제 - @Transactional - public void updatePortfolio(UpdatePortfolioDto request) { - Artist artist = artistRepository.findById(request.getArtistId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - - // Portfolio를 getPortfolioDetails 메서드를 이용해 조회 - PortfolioDto portfolioDto = getPortfolioDetails(request.getPortfolioId()); - Portfolio portfolio = portfolioRepository.findById(portfolioDto.getPortfolioId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); - - // 아티스트가 해당 portfolio에 권한이 없을때 (포트폴리오에 있는 artist가 본인이 아닐때) - if (!portfolio.getArtist().equals(artist)) { - throw new GlobalException(ErrorStatus.NOT_AUTHORIZED_PORTFOLIO); - } - - if (request.getPortfolioImg() != null) { - PortfolioImgDto portfolioImgDto = request.getPortfolioImg(); - PortfolioImg portfolioImg = portfolioImgRepository.findById(portfolioImgDto.getPortfolioImgId()) - .orElseThrow(() -> new RuntimeException("포트폴리오 이미지를 찾을 수 없습니다.")); - - if (portfolioImgDto.isDelete()) { - // 이미지 삭제 - portfolio.getPortfolioImgList().remove(portfolioImg); - portfolioImgRepository.delete(portfolioImg); - } else if (portfolioImgDto.getPortfolioImgSrc() != null) { - // 이미지 수정 (src 업데이트) - portfolioImg.setSrc(portfolioImgDto.getPortfolioImgSrc()); - portfolioImgRepository.save(portfolioImg); - - // 업데이트된 이미지 정보를 포트폴리오의 이미지 리스트에 반영 - portfolio.getPortfolioImgList().removeIf(img -> img.getPortfolioImgId().equals(portfolioImg.getPortfolioImgId())); - portfolio.getPortfolioImgList().add(portfolioImg); - } - } - // Portfolio 업데이트 - portfolio.updatePortfolio(request); - } - - -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/controller/ReservationController.java b/src/main/java/umc/meme/shop/domain/reservation/controller/ReservationController.java deleted file mode 100644 index 9560585..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/controller/ReservationController.java +++ /dev/null @@ -1,63 +0,0 @@ -package umc.meme.shop.domain.reservation.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Parameters; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; -import umc.meme.shop.domain.reservation.dto.request.AlterReservationDto; -import umc.meme.shop.domain.reservation.dto.request.ReservationRequestDto; -import umc.meme.shop.domain.reservation.service.ReservationService; -import umc.meme.shop.global.SuccessStatus; -import umc.meme.shop.global.response.ApiResponse; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1/reservation") -public class ReservationController { - private final ReservationService reservationService; - - - @Operation(summary = "예약 상태 변경", description = "예약 상태를 변경하는 API입니다.") - @Parameters({ - @Parameter(name = "status", description = "Status enum 에 있는 값 (EXPECTED, COMPLETE, CANCEL)") - }) - @PatchMapping("/alteration") - public ApiResponse alteration(@RequestBody AlterReservationDto alterReservationDto){ - reservationService.updateReservationStatus(alterReservationDto); - return ApiResponse.SuccessResponse(SuccessStatus.RESERVATION_UPDATE); - } - - @Operation(summary = "예약가능 장소 조회", description = "예약가능 장소 조회 기능을 수행하는 API입니다.") - @GetMapping("/{artistId}/location") - public ApiResponse getArtistLocation(@PathVariable Long artistId){ - return ApiResponse.SuccessResponse(SuccessStatus.ARTIST_LOCATION_GET, reservationService.getArtistLocation(artistId)); - } - - @Operation(summary = "예약가능 시간 조회", description = "예약가능 시간 조회 기능을 수행하는 API입니다.") - @GetMapping("/{artistId}/time") - public ApiResponse getArtistTime(@PathVariable Long artistId){ - return ApiResponse.SuccessResponse(SuccessStatus.ARTIST_TIME_GET, reservationService.getArtistTime(artistId)); - } - - - @Operation(summary = "예약하기", description = "예약하기 기능을 수행하는 API입니다.") - @PostMapping("/") - public ApiResponse createReservation(@RequestBody ReservationRequestDto reservationDto){ - return ApiResponse.SuccessResponse(SuccessStatus.RESERVATION_CREATE, reservationService.createReservation(reservationDto)); - } - - //아티스트 예약 조회 - @Operation(summary = "아티스트 예약 조회", description = "예약 정보를 조회하는 API입니다.") - @GetMapping("/{artistId}/artist") - public ApiResponse getArtistReservation(@PathVariable Long artistId){ - return ApiResponse.SuccessResponse(SuccessStatus.RESERVATION_GET, reservationService.getArtistReservation(artistId)); - } - - //모델 예약 조회 - @Operation(summary = "모델 예약 조회", description = "예약 정보를 조회하는 API입니다.") - @GetMapping("/{modelId}/model") - public ApiResponse getModelReservation(@PathVariable Long modelId){ - return ApiResponse.SuccessResponse(SuccessStatus.RESERVATION_GET, reservationService.getModelReservation(modelId)); - } -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/request/AlterReservationDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/request/AlterReservationDto.java deleted file mode 100644 index 195d450..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/dto/request/AlterReservationDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package umc.meme.shop.domain.reservation.dto.request; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import umc.meme.shop.domain.reservation.entity.enums.Status; - -@Data -public class AlterReservationDto { - @NotBlank(message = "reservationId를 입력해주세요.") - private Long reservationId; - @NotBlank(message = "status를 입력해주세요.") - private Status status; -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/request/ReservationRequestDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/request/ReservationRequestDto.java deleted file mode 100644 index b34c08e..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/dto/request/ReservationRequestDto.java +++ /dev/null @@ -1,24 +0,0 @@ -package umc.meme.shop.domain.reservation.dto.request; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.Data; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; - -import java.util.Date; -import java.util.Map; - -@Data -public class ReservationRequestDto { - @NotBlank(message = "modelId를 입력해주세요") - private Long modelId; - @NotBlank(message = "portfolioId를 입력해주세요") - private Long portfolioId; - @NotBlank(message = "예약날짜를 입력해주세요") - private Date reservationDate; - @NotNull(message = "예약시간을 입력해주세요") - private Map reservationDayOfWeekAndTime; - @NotNull(message = "예약 장소를 입력해주세요") - private String location; -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistLocationDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistLocationDto.java deleted file mode 100644 index 92ca81d..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistLocationDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package umc.meme.shop.domain.reservation.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.artist.entity.enums.MakeupLocation; -import umc.meme.shop.domain.artist.entity.enums.Region; - -import java.util.List; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ArtistLocationDto { - private MakeupLocation makeupLocation; //샵 재직 여부 - private String shopLocation; //샵 위치 - private List region; //활동 가능 지역 -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistTimeDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistTimeDto.java deleted file mode 100644 index 9e93835..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistTimeDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package umc.meme.shop.domain.reservation.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ArtistTimeDto { - private DayOfWeek availableDayOfWeek; - private Times availableTime; -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationCompleteDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationCompleteDto.java deleted file mode 100644 index 032e908..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationCompleteDto.java +++ /dev/null @@ -1,25 +0,0 @@ -package umc.meme.shop.domain.reservation.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; - -import java.sql.Time; -import java.util.Date; -import java.util.Map; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ReservationCompleteDto { - private String makeupName; - private String artist; - private String location; //장소 - private Date reservationDate; //날짜 - private Map reservationDayOfWeekAndTime; //요일과 시간 - -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationResponseDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationResponseDto.java deleted file mode 100644 index 5be5b86..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationResponseDto.java +++ /dev/null @@ -1,57 +0,0 @@ -package umc.meme.shop.domain.reservation.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.reservation.entity.Reservation; -import umc.meme.shop.domain.reservation.entity.enums.Status; -import umc.meme.shop.global.ErrorStatus; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; -import umc.meme.shop.global.exception.GlobalException; - -import java.util.Date; -import java.util.Map; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ReservationResponseDto { - private Long reservationId ; - private Long portfolioId; - private String modelName; - private String artistName; - private String makeupName; - private int price; - - private Date reservationDate; - private Map reservationDayOfWeekAndTime; - private String shopLocation; //샵 위치 - private Status status; - - public static ReservationResponseDto from(Reservation reservation){ - Portfolio portfolio = reservation.getPortfolio(); - if(portfolio == null) - throw new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO); - - Artist artist = reservation.getPortfolio().getArtist(); - - return ReservationResponseDto.builder() - .reservationId(reservation.getReservationId()) - .portfolioId(portfolio.getPortfolioId()) - .modelName(reservation.getModel().getName()) - .artistName(artist.getName()) - .makeupName(portfolio.getMakeupName()) - .price(portfolio.getPrice()) - .reservationDayOfWeekAndTime(reservation.getReservationDayOfWeekAndTime()) - .reservationDate(reservation.getReservationDate()) - .shopLocation(artist.getShopLocation()) - .status(reservation.getStatus()) - .build(); - } - -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/entity/Reservation.java b/src/main/java/umc/meme/shop/domain/reservation/entity/Reservation.java deleted file mode 100644 index d80f30f..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/entity/Reservation.java +++ /dev/null @@ -1,64 +0,0 @@ -package umc.meme.shop.domain.reservation.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.reservation.entity.enums.Status; -import umc.meme.shop.domain.user.User; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; - -import java.util.Date; -import java.util.Map; - -@Builder -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class Reservation { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long reservationId; - - @ManyToOne - @JoinColumn(name="user_id", nullable = false) - private User model; - - @ManyToOne - @JoinColumn(name="portfolio_id", nullable = false) - private Portfolio portfolio; - - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private Status status; - - @Column(nullable = false) - private boolean isReview = false; - - @ElementCollection - @CollectionTable(name = "reservation_time_mapping", - joinColumns = {@JoinColumn(name = "reservation_id", referencedColumnName = "reservationId")}) - @MapKeyColumn(name = "day_of_week") - @Enumerated(EnumType.STRING) - private Map reservationDayOfWeekAndTime; - - @Column(nullable = false) - private Date reservationDate; - - @Column(nullable = false) - private String location; //예약 장소 - - public void updateReservation(Status status){ - if(status != null) - this.status = status; - } - - public void updateIsReview(boolean bool){ - this.isReview = bool; - } -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/entity/enums/Status.java b/src/main/java/umc/meme/shop/domain/reservation/entity/enums/Status.java deleted file mode 100644 index 07c9cdf..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/entity/enums/Status.java +++ /dev/null @@ -1,5 +0,0 @@ -package umc.meme.shop.domain.reservation.entity.enums; - -public enum Status { - EXPECTED, COMPLETE, CANCEL -} diff --git a/src/main/java/umc/meme/shop/domain/reservation/repository/ReservationRepository.java b/src/main/java/umc/meme/shop/domain/reservation/repository/ReservationRepository.java deleted file mode 100644 index 6ff22f0..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/repository/ReservationRepository.java +++ /dev/null @@ -1,26 +0,0 @@ -package umc.meme.shop.domain.reservation.repository; - -import org.springframework.boot.Banner; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.model.entity.Model; -import umc.meme.shop.domain.reservation.entity.Reservation; - -import java.util.List; -import java.util.Optional; - -public interface ReservationRepository extends JpaRepository { - @Query("SELECT r FROM Reservation r WHERE r.portfolio.artist = :artist") - List findByArtist(@Param("artist") Artist artist); - - @Query("SELECT r FROM Reservation r WHERE r.model = :model") - List findByModel(@Param("model") Model model); - - @Query("SELECT r FROM Reservation r JOIN r.model m WHERE r.reservationId = :reservationId AND m.userId = :modelId") - Optional findByReservationIdAndModelId(@Param("reservationId") Long reservationId, @Param("modelId") Long modelId); - -} - - diff --git a/src/main/java/umc/meme/shop/domain/reservation/service/ReservationService.java b/src/main/java/umc/meme/shop/domain/reservation/service/ReservationService.java deleted file mode 100644 index 0eefd29..0000000 --- a/src/main/java/umc/meme/shop/domain/reservation/service/ReservationService.java +++ /dev/null @@ -1,152 +0,0 @@ -package umc.meme.shop.domain.reservation.service; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.artist.repository.ArtistRepository; -import umc.meme.shop.domain.model.entity.Model; -import umc.meme.shop.domain.model.repository.ModelRepository; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.portfolio.repository.PortfolioRepository; -import umc.meme.shop.domain.reservation.dto.request.AlterReservationDto; -import umc.meme.shop.domain.reservation.dto.request.ReservationRequestDto; -import umc.meme.shop.domain.reservation.dto.response.ArtistLocationDto; -import umc.meme.shop.domain.reservation.dto.response.ArtistTimeDto; -import umc.meme.shop.domain.reservation.dto.response.ReservationCompleteDto; -import umc.meme.shop.domain.reservation.dto.response.ReservationResponseDto; -import umc.meme.shop.domain.reservation.entity.Reservation; -import umc.meme.shop.domain.reservation.entity.enums.Status; -import umc.meme.shop.domain.reservation.repository.ReservationRepository; -import umc.meme.shop.global.ErrorStatus; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; -import umc.meme.shop.global.exception.GlobalException; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -@Service -@RequiredArgsConstructor -public class ReservationService { - private final ArtistRepository artistRepository; - private final ModelRepository modelRepository; - private final PortfolioRepository portfolioRepository; - private final ReservationRepository reservationRepository; - - //아티스트 예약 가능 장소 조회 - public ArtistLocationDto getArtistLocation(Long artistId){ - Artist artist = artistRepository.findById(artistId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - - return ArtistLocationDto.builder() - .makeupLocation(artist.getMakeupLocation()) - .shopLocation(artist.getShopLocation()) - .region(artist.getRegion()) - .build(); - } - - //아티스트 예약 가능 시간 조회 - - public List getArtistTime(Long artistId) { - Artist artist = artistRepository.findById(artistId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - - Map availableDayOfWeekAndTime = artist.getAvailableDayOfWeekAndTime(); - - List artistTimeList = new ArrayList<>(); - - for (Map.Entry entry : availableDayOfWeekAndTime.entrySet()) { - DayOfWeek dayOfWeek = entry.getKey(); - Times availableTime = entry.getValue(); - - ArtistTimeDto artistTimeDto = ArtistTimeDto.builder() - .availableDayOfWeek(dayOfWeek) - .availableTime(availableTime) - .build(); - - artistTimeList.add(artistTimeDto); - } - - return artistTimeList; - } - - //예약하기 - @Transactional - public ReservationCompleteDto createReservation(ReservationRequestDto reservationDto){ - Model model = modelRepository.findById(reservationDto.getModelId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - - Portfolio portfolio = portfolioRepository.findById(reservationDto.getPortfolioId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); - - // 두 개 이상의 예약을 한번에 요청한 경우 - if (reservationDto.getReservationDayOfWeekAndTime().size() != 1) { - throw new GlobalException(ErrorStatus.NOT_ALLOW_OVER_ONE_RESERVATION); - } - - Reservation reservation = Reservation.builder() - .model(model) - .portfolio(portfolio) - .status(Status.EXPECTED) - .reservationDayOfWeekAndTime(reservationDto.getReservationDayOfWeekAndTime()) - .reservationDate(reservationDto.getReservationDate()) - .location(reservationDto.getLocation()) - .build(); - - model.updateReservationList(reservation); - reservationRepository.save(reservation); - - return ReservationCompleteDto.builder() - .makeupName(portfolio.getMakeupName()) - .artist(portfolio.getArtist().getName()) - .location(reservation.getLocation()) - .reservationDate(reservation.getReservationDate()) - .reservationDayOfWeekAndTime(reservation.getReservationDayOfWeekAndTime()) - .build(); - } - - //예약하기 상태 변경 - @Transactional - public void updateReservationStatus(AlterReservationDto reservationDto){ - Reservation reservation = reservationRepository.findById(reservationDto.getReservationId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_RESERVATION)); - Status status = reservationDto.getStatus(); - - if(reservation.getStatus() == status) - throw new GlobalException(ErrorStatus.ALREADY_CHANGE_STATUS); - if(reservation.getStatus() == Status.COMPLETE && status == Status.CANCEL) - throw new GlobalException(ErrorStatus.INVALID_CHANGE_STATUS); - if(reservation.getStatus() == Status.CANCEL && status == Status.COMPLETE) - throw new GlobalException(ErrorStatus.INVALID_CHANGE_COMPLETE); - - reservation.updateReservation(status); - } - - //아티스트 예약 조회 - public List getArtistReservation(Long artistId){ - Artist artist = artistRepository.findById(artistId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); - - List reservationList = reservationRepository.findByArtist(artist); - return reservationList.stream() - .map(ReservationResponseDto::from) - .collect(Collectors.toList()); - } - - //모델 예약 조회 - public List getModelReservation(Long modelId) { - Model model = modelRepository.findById(modelId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - - List reservationList = model.getReservationList(); - return reservationList.stream() - .map(ReservationResponseDto::from) - .collect(Collectors.toList()); - } - - -} diff --git a/src/main/java/umc/meme/shop/domain/review/controller/ReviewController.java b/src/main/java/umc/meme/shop/domain/review/controller/ReviewController.java deleted file mode 100644 index 3f7228d..0000000 --- a/src/main/java/umc/meme/shop/domain/review/controller/ReviewController.java +++ /dev/null @@ -1,46 +0,0 @@ -package umc.meme.shop.domain.review.controller; - -import io.swagger.v3.oas.annotations.Operation; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; -import umc.meme.shop.domain.review.dto.request.ReviewDto; -import umc.meme.shop.domain.review.dto.request.DeleteReviewDto; -import umc.meme.shop.domain.review.service.ReviewService; -import umc.meme.shop.global.SuccessStatus; -import umc.meme.shop.global.response.ApiResponse; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1/review") -public class ReviewController { - private final ReviewService reviewService; - - @Operation(summary = "리뷰 리스트 조회", description = "리뷰 리스트를 조회하는 API입니다.") - @GetMapping("/{portfolioId}") - public ApiResponse getReviewList(@PathVariable Long portfolioId, - @RequestParam(value = "page", defaultValue = "0", required = false) int page - ){ - return ApiResponse.SuccessResponse(SuccessStatus.REVIEW_GET, reviewService.getReviewList(portfolioId, page)); - } - - @Operation(summary = "리뷰 작성", description = "리뷰를 작성하는 API입니다.") - @PostMapping("/") - public ApiResponse createReview(@RequestBody ReviewDto reviewDto){ - //TODO: ReviewImg 추가 - reviewService.createReview(reviewDto); - return ApiResponse.SuccessResponse(SuccessStatus.REVIEW_CREATE); - } - - @Operation(summary = "내가 쓴 리뷰 조회", description = "본인이 쓴 리뷰를 조회하는 API입니다.") - @GetMapping("/me/{modelId}") - public ApiResponse getMyReview(@PathVariable Long modelId){ - return ApiResponse.SuccessResponse(SuccessStatus.REVIEW_GET, reviewService.getMyReview(modelId)); - } - - @Operation(summary = "리뷰 삭제", description = "모델이 작성한 리뷰를 삭제하는 API입니다.") - @DeleteMapping("/") - public ApiResponse updateReview(@RequestBody DeleteReviewDto reviewDto){ - reviewService.deleteReview(reviewDto); - return ApiResponse.SuccessResponse(SuccessStatus.REVIEW_DELETE); - } -} diff --git a/src/main/java/umc/meme/shop/domain/review/converter/ReviewConverter.java b/src/main/java/umc/meme/shop/domain/review/converter/ReviewConverter.java deleted file mode 100644 index a018fb8..0000000 --- a/src/main/java/umc/meme/shop/domain/review/converter/ReviewConverter.java +++ /dev/null @@ -1,27 +0,0 @@ -package umc.meme.shop.domain.review.converter; - -import org.springframework.data.domain.Page; -import umc.meme.shop.domain.review.dto.request.ReviewDto; -import umc.meme.shop.domain.review.dto.response.ReviewListPageDto; -import umc.meme.shop.domain.review.dto.response.ReviewResponseDto; -import umc.meme.shop.domain.review.entity.Review; - -import java.util.List; - -public class ReviewConverter { - - public static ReviewListPageDto reviewPageConverter(Page page) { - - List content = page.stream() - .map(ReviewResponseDto::from) - .toList(); - - return ReviewListPageDto.builder() - .content(content) - .pageSize(page.getSize()) - .currentPage(page.getNumber()) - .totalNumber(page.getNumberOfElements()) - .totalPage(page.getTotalPages()) - .build(); - } -} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/request/DeleteReviewDto.java b/src/main/java/umc/meme/shop/domain/review/dto/request/DeleteReviewDto.java deleted file mode 100644 index a5b85dd..0000000 --- a/src/main/java/umc/meme/shop/domain/review/dto/request/DeleteReviewDto.java +++ /dev/null @@ -1,16 +0,0 @@ -package umc.meme.shop.domain.review.dto.request; - -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class DeleteReviewDto { - @NotBlank(message = "modelId를 입력해주세요") - private Long modelId; - @NotBlank(message = "reviewId를 입력해주세요") - private Long reviewId; -} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/request/ReviewDto.java b/src/main/java/umc/meme/shop/domain/review/dto/request/ReviewDto.java deleted file mode 100644 index 687932d..0000000 --- a/src/main/java/umc/meme/shop/domain/review/dto/request/ReviewDto.java +++ /dev/null @@ -1,21 +0,0 @@ -package umc.meme.shop.domain.review.dto.request; - -import jakarta.validation.constraints.NotBlank; -import jdk.dynalink.linker.LinkerServices; -import lombok.Data; -import umc.meme.shop.domain.review.entity.Review; - -import java.util.List; - -@Data -public class ReviewDto { - @NotBlank(message = "modelId를 입력해주세요") - private Long modelId; - @NotBlank(message = "reservationId를 입력해주세요") - private Long reservationId; - @NotBlank(message = "별점을 입력해주세요") - private int star; - private String comment; - private List reviewImgSrc; - -} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewImgDto.java b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewImgDto.java deleted file mode 100644 index 114c4c7..0000000 --- a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewImgDto.java +++ /dev/null @@ -1,14 +0,0 @@ -package umc.meme.shop.domain.review.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class ReviewImgDto { - private Long ReviewImgId; - private String reviewImgSrc; - private boolean isDelete = false; -} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListPageDto.java b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListPageDto.java deleted file mode 100644 index f96790c..0000000 --- a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListPageDto.java +++ /dev/null @@ -1,22 +0,0 @@ -package umc.meme.shop.domain.review.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class ReviewListPageDto { - private List content; - private Map starStatus; - private int currentPage; //현재 페이지 번호 - private int pageSize; //페이지 크기 - private int totalNumber; //전체 메이크업 개수 - private int totalPage; //전체 페이지 개수 -} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListResponseDto.java b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListResponseDto.java deleted file mode 100644 index e5fd828..0000000 --- a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListResponseDto.java +++ /dev/null @@ -1,27 +0,0 @@ -package umc.meme.shop.domain.review.dto.response; - - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.review.entity.Review; - -import java.util.List; -import java.util.Map; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ReviewListResponseDto { - private List reviewResponseDtoList; - private Map starStatus; - - public static ReviewListResponseDto from(List reviewResponseDtoList, Map starStatus) { - return ReviewListResponseDto.builder() - .reviewResponseDtoList(reviewResponseDtoList) - .starStatus(starStatus) - .build(); - } -} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewResponseDto.java b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewResponseDto.java deleted file mode 100644 index 3d4337e..0000000 --- a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewResponseDto.java +++ /dev/null @@ -1,34 +0,0 @@ -package umc.meme.shop.domain.review.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.review.entity.Review; - -import java.util.List; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ReviewResponseDto { - private String modelName; - private int star; - private String comment; - private List reviewImgDtoList; - - public static ReviewResponseDto from(Review review){ - List reviewImgDtoList = review.getReviewImgList() - .stream() - .map(reviewImg -> new ReviewImgDto(reviewImg.getReviewImgId(), reviewImg.getSrc(), false)) - .toList(); - - return ReviewResponseDto.builder() - .modelName(review.getModel().getName()) - .star(review.getStar()) - .comment(review.getComment()) - .reviewImgDtoList(reviewImgDtoList) - .build(); - } -} diff --git a/src/main/java/umc/meme/shop/domain/review/entity/Review.java b/src/main/java/umc/meme/shop/domain/review/entity/Review.java deleted file mode 100644 index 3bec851..0000000 --- a/src/main/java/umc/meme/shop/domain/review/entity/Review.java +++ /dev/null @@ -1,39 +0,0 @@ -package umc.meme.shop.domain.review.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.user.User; - -import java.util.List; - -@Builder -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class Review { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long reviewId; - - @ManyToOne - @JoinColumn(name="portfolio_id", nullable = false) - private Portfolio portfolio; - - @ManyToOne - @JoinColumn(name="user_id", nullable = false) - private User model; - - @OneToMany(cascade = CascadeType.ALL, mappedBy = "review") - private List reviewImgList; - - @Column(nullable = false) - private int star; - - @Column(nullable = true, length = 200) - private String comment; -} diff --git a/src/main/java/umc/meme/shop/domain/review/entity/ReviewImg.java b/src/main/java/umc/meme/shop/domain/review/entity/ReviewImg.java deleted file mode 100644 index 5ba4436..0000000 --- a/src/main/java/umc/meme/shop/domain/review/entity/ReviewImg.java +++ /dev/null @@ -1,24 +0,0 @@ -package umc.meme.shop.domain.review.entity; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Entity -public class ReviewImg { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long reviewImgId; - - @ManyToOne - @JoinColumn(name="review_id", nullable = false) - private Review review; - - @Column(nullable = false) - private String src; -} diff --git a/src/main/java/umc/meme/shop/domain/review/repository/ReviewImgRepository.java b/src/main/java/umc/meme/shop/domain/review/repository/ReviewImgRepository.java deleted file mode 100644 index 45e0442..0000000 --- a/src/main/java/umc/meme/shop/domain/review/repository/ReviewImgRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package umc.meme.shop.domain.review.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import umc.meme.shop.domain.review.entity.ReviewImg; - -public interface ReviewImgRepository extends JpaRepository { -} diff --git a/src/main/java/umc/meme/shop/domain/review/repository/ReviewRepository.java b/src/main/java/umc/meme/shop/domain/review/repository/ReviewRepository.java deleted file mode 100644 index e052a85..0000000 --- a/src/main/java/umc/meme/shop/domain/review/repository/ReviewRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package umc.meme.shop.domain.review.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import umc.meme.shop.domain.model.entity.Model; -import umc.meme.shop.domain.review.entity.Review; - -import java.util.List; - -public interface ReviewRepository extends JpaRepository { - List findByModel(Model model); -} diff --git a/src/main/java/umc/meme/shop/domain/review/service/ReviewService.java b/src/main/java/umc/meme/shop/domain/review/service/ReviewService.java deleted file mode 100644 index 49dc478..0000000 --- a/src/main/java/umc/meme/shop/domain/review/service/ReviewService.java +++ /dev/null @@ -1,146 +0,0 @@ -package umc.meme.shop.domain.review.service; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import umc.meme.shop.domain.model.entity.Model; -import umc.meme.shop.domain.model.repository.ModelRepository; -import umc.meme.shop.domain.portfolio.entity.Portfolio; -import umc.meme.shop.domain.portfolio.repository.PortfolioRepository; -import umc.meme.shop.domain.reservation.entity.Reservation; -import umc.meme.shop.domain.reservation.entity.enums.Status; -import umc.meme.shop.domain.reservation.repository.ReservationRepository; -import umc.meme.shop.domain.review.converter.ReviewConverter; -import umc.meme.shop.domain.review.dto.request.DeleteReviewDto; -import umc.meme.shop.domain.review.dto.request.ReviewDto; -import umc.meme.shop.domain.review.dto.response.ReviewImgDto; -import umc.meme.shop.domain.review.dto.response.ReviewListPageDto; -import umc.meme.shop.domain.review.dto.response.ReviewListResponseDto; -import umc.meme.shop.domain.review.dto.response.ReviewResponseDto; -import umc.meme.shop.domain.review.entity.Review; -import umc.meme.shop.domain.review.entity.ReviewImg; -import umc.meme.shop.domain.review.repository.ReviewImgRepository; -import umc.meme.shop.domain.review.repository.ReviewRepository; -import umc.meme.shop.global.ErrorStatus; -import umc.meme.shop.global.exception.GlobalException; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Service -@RequiredArgsConstructor -public class ReviewService { - private final ModelRepository modelRepository; - private final ReviewRepository reviewRepository; - private final ReservationRepository reservationRepository; - private final PortfolioRepository portfolioRepository; - private final ReviewImgRepository reviewImgRepository; - - //리뷰 작성 - @Transactional - public void createReview(ReviewDto reviewDto){ - Model model = modelRepository.findById(reviewDto.getModelId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - Reservation reservation = reservationRepository.findByReservationIdAndModelId(reviewDto.getReservationId(), reviewDto.getModelId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_RESERVATION)); - - //이미 리뷰 작성 완료 - if(reservation.isReview()) - throw new GlobalException(ErrorStatus.ALREADY_REVIEWED); - - //예약 미완료 - if(reservation.getStatus() != Status.COMPLETE) - throw new GlobalException(ErrorStatus.INVALID_REVIEW_REQUEST); - - Portfolio portfolio = reservation.getPortfolio(); - - List reviewImgList = new ArrayList<>(); - for (String src : reviewDto.getReviewImgSrc()) { - ReviewImg reviewImg = new ReviewImg(); - reviewImg.setSrc(src); - reviewImgList.add(reviewImg); - } - - Review review = Review.builder() - .model(model) - .portfolio(portfolio) - .star(reviewDto.getStar()) - .comment(reviewDto.getComment()) - .reviewImgList(new ArrayList()) - .build(); - - for (ReviewImg reviewImg : reviewImgList) { - reviewImg.setReview(review); - review.getReviewImgList().add(reviewImg); - - } - - portfolio.updateReviewList(review); - portfolio.updateAverageStars(); - model.updateReviewList(review); - - reviewRepository.save(review); - reservation.updateIsReview(true); - } - - //내가 쓴 리뷰 조회 - public List getMyReview(Long modelId){ - Model model = modelRepository.findById(modelId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - List reviewList = reviewRepository.findByModel(model); - return reviewList.stream() - .map(ReviewResponseDto::from) - .toList(); - } - - //리뷰 리스트 조회 - public ReviewListPageDto getReviewList(Long portfolioId, int page) { - Portfolio portfolio = portfolioRepository.findById(portfolioId) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); - - List reviewList = portfolio.getReviewList(); - - // page로 mapping - Pageable pageable = PageRequest.of(page, 30); - int start = (int) pageable.getOffset(); - int end = Math.min((start + pageable.getPageSize()), reviewList.size()); - - // list를 page로 변환 - List pagedReviewList = reviewList.subList(start, end); - Page reviewPage = new PageImpl<>(pagedReviewList, pageable, reviewList.size()); - - // 별점 현황 - Map starStatus = new HashMap<>(Map.of(5, 0, 4, 0, 3, 0, 2, 0, 1, 0)); - for (Review review : pagedReviewList) { - int star = review.getStar(); - starStatus.put(star, starStatus.get(star) + 1); - } - - // ReviewConverter를 사용하여 ReviewListPageDto 생성 - ReviewListPageDto pageDto = ReviewConverter.reviewPageConverter(reviewPage); - - // 별점 현황 추가 - pageDto.setStarStatus(starStatus); - - return pageDto; - } - - //리뷰 삭제 - @Transactional - public void deleteReview(DeleteReviewDto reviewDto){ - Model model = modelRepository.findById(reviewDto.getModelId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); - Review review = reviewRepository.findById(reviewDto.getReviewId()) - .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_REVIEW)); - if(!review.getModel().equals(model)) - throw new GlobalException(ErrorStatus.INVALID_MODEL_FOR_REVIEW); - - reviewRepository.delete(review); - } -} diff --git a/src/main/java/umc/meme/shop/domain/user/User.java b/src/main/java/umc/meme/shop/domain/user/User.java deleted file mode 100644 index 39d30d4..0000000 --- a/src/main/java/umc/meme/shop/domain/user/User.java +++ /dev/null @@ -1,38 +0,0 @@ -package umc.meme.shop.domain.user; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; -import umc.meme.shop.domain.artist.entity.enums.Gender; - -@SuperBuilder -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Entity -@Inheritance(strategy = InheritanceType.JOINED) -public class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "user_id") - protected Long userId; - - @Column(nullable = false) - protected String profileImg; - - @Column(nullable = false, length = 40) - protected String nickname; - - @Column(nullable = false, length = 20) - protected String name; - - @Enumerated(EnumType.STRING) - @Column(nullable = false) - protected Gender gender; - - @Column(nullable = false, length = 40) - protected String email; -} diff --git a/src/main/java/umc/meme/shop/domain/user/UserRepository.java b/src/main/java/umc/meme/shop/domain/user/UserRepository.java deleted file mode 100644 index cc8c7ba..0000000 --- a/src/main/java/umc/meme/shop/domain/user/UserRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package umc.meme.shop.domain.user; - -import org.springframework.data.jpa.repository.JpaRepository; -import umc.meme.shop.domain.artist.entity.Artist; - -public interface UserRepository extends JpaRepository { -} diff --git a/src/main/java/umc/meme/shop/global/ErrorStatus.java b/src/main/java/umc/meme/shop/global/ErrorStatus.java deleted file mode 100644 index 34f0019..0000000 --- a/src/main/java/umc/meme/shop/global/ErrorStatus.java +++ /dev/null @@ -1,77 +0,0 @@ -package umc.meme.shop.global; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public enum ErrorStatus { - - /** - * Error Code - * 400 : 잘못된 요청 - * 401 : JWT에 대한 오류 - * 403 : 요청한 정보에 대한 권한 없음. - * 404 : 존재하지 않는 정보에 대한 요청. - */ - - /** - * TEMP - */ - TEMP(400, "TEMP"), - - /** - * Code : 403 - * Not Authorized - */ - - //portfoilo - NOT_AUTHORIZED_PORTFOLIO(403, "아티스트가 해당 포트폴리오에 수정 권한이 없습니다."), - - - /** - * Code : 400 - * Bad Request - */ - INVALID_REQUEST(400, "유효하지 않은 요청입니다."), - ALREADY_EXIST_FAVORITE_ARTIST(400, "해당 아티스트는 이미 관심 아티스트로 등록되어있습니다."), - ALREADY_EXIST_FAVORITE_PORTFOLIO(400, "해당 포트폴리오는 이미 관심 포트폴리오로 등록되어있습니다."), - - //portfolio - ALREADY_EXIST_PORTFOLIO(400, "해당 포트폴리오 제목이 이미 존재합니다"), - INVALID_SORT_CRITERIA(400, "잘못된 정렬 기준입니다"), - BLOCKED_PORTFOLIO(400, "숨김 처리된 포트폴리오입니다"), - - //review - ALREADY_REVIEWED(400, "이미 리뷰 작성이 완료된 예약입니다."), - INVALID_REVIEW_REQUEST(400, "예약이 완료되지 않아 리뷰를 작성할 수 없습니다."), - INVALID_MODEL_FOR_REVIEW(400, "사용자가 작성하지 않은 리뷰입니다."), - - //reservation - ALREADY_CHANGE_STATUS(400, "이미 예약 상태가 변경되었습니다."), - INVALID_CHANGE_STATUS(400, "이미 완료된 예약은 취소할 수 없습니다."), - - NOT_ALLOW_OVER_ONE_RESERVATION(400,"한 번에 하나의 예약만 가능합니다." ), - INVALID_CHANGE_COMPLETE(400,"취소된 예약을 완료 상태로 변경할 수 없습니다." ), - - - /** - * Code : 404 - * Not Found - */ - NOT_EXIST_USER(404, "존재하지 않는 유저입니다."), - NOT_EXIST_MODEL(404, "존재하지 않는 모델입니다."), - NOT_EXIST_ARTIST(404, "존재하지 않는 아티스트입니다."), - NOT_EXIST_PORTFOLIO(404, "존재하지 않는 포트폴리오입니다."), - NOT_EXIST_RESERVATION(404, "존재하지 않는 예약입니다."), - NOT_EXIST_FAVORITE_ARTIST(404, "존재하지 않는 관심 아티스트입니다."), - NOT_EXIST_FAVORITE_PORTFOLIO(404, "존재하지 않는 관심 메이크업입니다."), - NOT_EXIST_REVIEW(404, "존재하지 않는 리뷰입니다."), - NOT_EXIST_INQUIRY(404, "존재하지 않는 문의입니다."), - SEARCH_NOT_FOUNT(404, "검색 결과가 존재하지 않습니다."), - PAGE_NOT_FOUND(404,"페이지를 찾을 수 없습니다"); - - - private final int code; - private final String message; -} diff --git a/src/main/java/umc/meme/shop/global/SuccessStatus.java b/src/main/java/umc/meme/shop/global/SuccessStatus.java deleted file mode 100644 index 266dc81..0000000 --- a/src/main/java/umc/meme/shop/global/SuccessStatus.java +++ /dev/null @@ -1,55 +0,0 @@ -package umc.meme.shop.global; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public enum SuccessStatus { - - TEMP(200, "TEMP"), - - /**artist**/ - ARTIST_PROFILE_UPDATE(200, "아티스트 프로필 수정이 완료되었습니다"), - ARTIST_PROFILE_GET(200, "아티스트 프로필 조회가 완료되었습니다"), - - PORTFOLIO_CREATE(200, "포트폴리오 생성이 완료되었습니다"), - PORTFOLIO_GET(200, "포트폴리오 조회가 완료되었습니다"), - PORTFOLIO_UPDATE(200, "포트폴리오 수정이 완료되었습니다"), - - /**model**/ - MODEL_PROFILE_UPDATE(200, "모델 프로필 수정이 완료되었습니다"), - - FAVORITE_ARTIST_GET(200, "관심 아티스트 조회가 완료되었습니다"), - FAVORITE_PORTFOLIO_GET(200, "관심 메이크업 조회가 완료되었습니다"), - FAVORITE_ARTIST_POST(200, "관심 아티스트 추가가 완료되었습니다."), - FAVORITE_PORTFOLIO_POST(200, "관심 메이크업 추가가 완료되었습니다."), - FAVORITE_ARTIST_DELETE(200, "관심 아티스트 삭제가 완료되었습니다."), - FAVORITE_PORTFOLIO_DELETE(200, "관심 메이크업 삭제가 완료되었습니다."), - - - SEARCH_GET(200, "조회가 완료되었습니다"), - - /**review**/ - REVIEW_CREATE(200, "리뷰 작성이 완료되었습니다"), - REVIEW_GET(200, "리뷰 조회가 완료되었습니다"), - REVIEW_DELETE(200, "리뷰 삭제가 완료되었습니다"), - - /**reservation**/ - RESERVATION_CREATE(200, "예약이 완료되었습니다"), - RESERVATION_GET(200, "예약 조회가 완료되었습니다"), - RESERVATION_UPDATE(200, "예약 상태 변경이 완료되었습니다"), - ARTIST_LOCATION_GET(200, "아티스트의 예약 가능 장소 조회가 완료되었습니다"), - ARTIST_TIME_GET(200, "아티스트의 예약 가능 시간 조회가 완료되었습니다."), - - /**mypage**/ - MYPAGE_GET(200, "마이페이지 조회가 완료되었습니다"), - DETAILS_GET(200, "내 정보 조회가 완료되었습니다"), - TOS_GET(200, "약관 및 정책 조회가 완료되었습니다"), - CONTACT_CREATE(200, "문의 작성이 완료되었습니다"), - CONTACT_GET(200, "문의 조회가 완료되었습니다."); - - - private final int code; - private final String message; -} diff --git a/src/main/java/umc/meme/shop/global/config/SwaggerConfig.java b/src/main/java/umc/meme/shop/global/config/SwaggerConfig.java deleted file mode 100644 index 630fbc1..0000000 --- a/src/main/java/umc/meme/shop/global/config/SwaggerConfig.java +++ /dev/null @@ -1,40 +0,0 @@ -package umc.meme.shop.global.config; - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.security.SecurityRequirement; -import io.swagger.v3.oas.models.security.SecurityScheme; -import io.swagger.v3.oas.models.servers.Server; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class SwaggerConfig { - // http://localhost:8080/swagger-ui/index.html#/ - @Bean - public OpenAPI MemeAPI() { - Info info = new Info() - .title("MEME_SERVICE API Docs") - .description("MEME_SERVICE API 명세서입니다.") - .version("1.0.0"); - - String jwtSchemeName = "accessToken"; - // API 요청헤더에 인증정보 포함 - SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwtSchemeName); - - // SecuritySchemes 등록 - Components components = new Components() - .addSecuritySchemes(jwtSchemeName, new SecurityScheme() - .name(jwtSchemeName) - .type(SecurityScheme.Type.HTTP) // HTTP 방식 - .scheme("bearer") - .bearerFormat("JWT")); - - return new OpenAPI() - .addServersItem(new Server().url("/")) - .info(info) - .addSecurityItem(securityRequirement) - .components(components); - } -} \ No newline at end of file diff --git a/src/main/java/umc/meme/shop/global/enums/DayOfWeek.java b/src/main/java/umc/meme/shop/global/enums/DayOfWeek.java deleted file mode 100644 index 25a3252..0000000 --- a/src/main/java/umc/meme/shop/global/enums/DayOfWeek.java +++ /dev/null @@ -1,6 +0,0 @@ -package umc.meme.shop.global.enums; - -public enum DayOfWeek { - MON, TUE, WED, THU, FRI, SAT, SUN - -} diff --git a/src/main/java/umc/meme/shop/global/enums/Times.java b/src/main/java/umc/meme/shop/global/enums/Times.java deleted file mode 100644 index 596c449..0000000 --- a/src/main/java/umc/meme/shop/global/enums/Times.java +++ /dev/null @@ -1,28 +0,0 @@ -package umc.meme.shop.global.enums; - -public enum Times { - _00_00, _00_30, - _01_00, _01_30, - _02_00, _02_30, - _03_00, _03_30, - _04_00, _04_30, - _05_00, _05_30, - _06_00, _06_30, - _07_00, _07_30, - _08_00, _08_30, - _09_00, _09_30, - _10_00, _10_30, - _11_00, _11_30, - _12_00, _12_30, - _13_00, _13_30, - _14_00, _14_30, - _15_00, _15_30, - _16_00, _16_30, - _17_00, _17_30, - _18_00, _18_30, - _19_00, _19_30, - _20_00, _20_30, - _21_00, _21_30, - _22_00, _22_30, - _23_00, _23_30 -} diff --git a/src/main/java/umc/meme/shop/global/exception/GlobalException.java b/src/main/java/umc/meme/shop/global/exception/GlobalException.java deleted file mode 100644 index 46b60f3..0000000 --- a/src/main/java/umc/meme/shop/global/exception/GlobalException.java +++ /dev/null @@ -1,11 +0,0 @@ -package umc.meme.shop.global.exception; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import umc.meme.shop.global.ErrorStatus; - -@Getter -@AllArgsConstructor -public class GlobalException extends RuntimeException { - private final ErrorStatus errorStatus; -} diff --git a/src/main/java/umc/meme/shop/global/exception/GlobalExceptionAdvice.java b/src/main/java/umc/meme/shop/global/exception/GlobalExceptionAdvice.java deleted file mode 100644 index 2c41381..0000000 --- a/src/main/java/umc/meme/shop/global/exception/GlobalExceptionAdvice.java +++ /dev/null @@ -1,18 +0,0 @@ -package umc.meme.shop.global.exception; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import umc.meme.shop.global.response.ApiResponse; - -@Slf4j -@RestControllerAdvice(annotations = {RestController.class}) -public class GlobalExceptionAdvice extends ResponseEntityExceptionHandler { - - @ExceptionHandler(value = { GlobalException.class }) - protected ApiResponse handleException(GlobalException e) { - return ApiResponse.FailureResponse(e.getErrorStatus()); - } -} diff --git a/src/main/java/umc/meme/shop/global/exception/GlobalExceptionHandler.java b/src/main/java/umc/meme/shop/global/exception/GlobalExceptionHandler.java deleted file mode 100644 index 5def7f5..0000000 --- a/src/main/java/umc/meme/shop/global/exception/GlobalExceptionHandler.java +++ /dev/null @@ -1,9 +0,0 @@ -package umc.meme.shop.global.exception; - -import umc.meme.shop.global.ErrorStatus; - -public class GlobalExceptionHandler extends GlobalException{ - public GlobalExceptionHandler(ErrorStatus errorStatus) { - super(errorStatus); - } -} diff --git a/src/main/java/umc/meme/shop/global/response/ApiResponse.java b/src/main/java/umc/meme/shop/global/response/ApiResponse.java deleted file mode 100644 index cef2163..0000000 --- a/src/main/java/umc/meme/shop/global/response/ApiResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -package umc.meme.shop.global.response; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import lombok.AllArgsConstructor; -import lombok.Getter; -import umc.meme.shop.global.ErrorStatus; -import umc.meme.shop.global.SuccessStatus; - -@Getter -@AllArgsConstructor -@JsonPropertyOrder({"code", "result", "message", "data"}) -public class ApiResponse { - - private final int statusCode; - private final String result; - private final String message; - @JsonInclude(JsonInclude.Include.NON_NULL) - private final T data; - - public static ApiResponse SuccessResponse(SuccessStatus status, T data){ - return new ApiResponse<>(status.getCode(), "SUCCESS", status.getMessage(), data); - } - public static ApiResponse SuccessResponse(SuccessStatus status){ - return new ApiResponse<>(status.getCode(), "SUCCESS", status.getMessage(), ""); - } - - public static ApiResponse FailureResponse(int statusCode, String message){ - return new ApiResponse<>(statusCode, "FAILURE", message, ""); - } - - public static ApiResponse FailureResponse(ErrorStatus errorStatus){ - return new ApiResponse<>(errorStatus.getCode(), "FAILURE", errorStatus.getMessage(), ""); - } -} diff --git a/src/test/java/umc/meme/shop/ArtistTest.java b/src/test/java/umc/meme/shop/ArtistTest.java deleted file mode 100644 index 9f22d0f..0000000 --- a/src/test/java/umc/meme/shop/ArtistTest.java +++ /dev/null @@ -1,74 +0,0 @@ -package umc.meme.shop; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import umc.meme.shop.domain.artist.entity.Artist; -import umc.meme.shop.domain.artist.entity.enums.*; -import umc.meme.shop.domain.artist.repository.ArtistRepository; -import umc.meme.shop.domain.portfolio.entity.enums.Category; -import umc.meme.shop.global.enums.DayOfWeek; -import umc.meme.shop.global.enums.Times; - -import java.util.List; - -@SpringBootTest -public class ArtistTest { - - private ArtistRepository artistRepository; - - @Test - void createArtist(){ - - List categories = List.of(new String[]{Category.DAILY.getValue(), Category.PARTY.getValue()}); - List regions = List.of(new String[]{Region.DONGJAK.getValue(), Region.GANGNAM.getValue()}); - Artist artist1 = Artist.builder() - .availableDayOfWeekAndTime(null) - .gender(Gender.FEMALE) - .specialization(categories) - .email("") - .name("testName") - .nickname("testNickName") - .makeupLocation(MakeupLocation.SHOP) - .region(regions) - .introduction("Artist1") - .profileImg("") - .workExperience(WorkExperience.EIGHT) - .build(); - artistRepository.save(artist1); - - List categories2 = List.of(new Category[]{Category.STUDIO, Category.ACTOR}); - List regions2 = List.of(new Region[]{Region.GURO, Region.GANGNAM}); - Artist artist2 = Artist.builder() - .availableDayOfWeekAndTime(null) - .gender(Gender.FEMALE) - .profileImg("") - .specialization(categories) - .email("") - .name("test2Name") - .nickname("test2NickName") - .makeupLocation(MakeupLocation.SHOP) - .region(regions) - .introduction("Artist2") - .workExperience(WorkExperience.FIVE) - .build(); - artistRepository.save(artist2); - - List categorie3 = List.of(new Category[]{Category.WEDDING, Category.PROSTHETIC}); - List regions3 = List.of(new Region[]{Region.DONGDAEMUN, Region.SONGPA}); - Artist artist3 = Artist.builder() - .profileImg("") - .availableDayOfWeekAndTime(null) - .gender(Gender.FEMALE) - .specialization(categories) - .email("") - .name("test3Name") - .nickname("test3NickName") - .makeupLocation(MakeupLocation.SHOP) - .region(regions) - .introduction("Artist3") - .workExperience(WorkExperience.ONE) - .build(); - artistRepository.save(artist3); - - } -} diff --git a/src/test/java/umc/meme/shop/ShopApplicationTests.java b/src/test/java/umc/meme/shop/ShopApplicationTests.java deleted file mode 100644 index b6f0a77..0000000 --- a/src/test/java/umc/meme/shop/ShopApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package umc.meme.shop; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class ShopApplicationTests { - - @Test - void contextLoads() { - } - -} From ab728c958f97bc87cc516e523d6d95671c2b275e Mon Sep 17 00:00:00 2001 From: yeopyeop-82 Date: Sat, 3 Feb 2024 18:28:51 +0900 Subject: [PATCH 2/2] =?UTF-8?q?add=20:=20=EB=AC=B8=EC=9D=98=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 8196 bytes .../meme-bug-report-template.md | 19 ++ .github/ISSUE_TEMPLATE/meme-issue-template.md | 15 ++ .github/workflows/docker.yml | 95 +++++++ .gitignore | 40 +++ Dockerfile | 4 + README.md | 1 + build.gradle | 37 +++ docker-compose.yaml | 18 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43462 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 249 ++++++++++++++++++ gradlew.bat | 92 +++++++ settings.gradle | 1 + src/.DS_Store | Bin 0 -> 6148 bytes src/main/.DS_Store | Bin 0 -> 6148 bytes .../java/umc/meme/shop/ShopApplication.java | 15 ++ .../artist/controller/ArtistController.java | 37 +++ .../artist/converter/ArtistConverter.java | 21 ++ .../artist/dto/request/ArtistProfileDto.java | 29 ++ .../domain/artist/dto/response/ArtistDto.java | 75 ++++++ .../artist/dto/response/ArtistPageDto.java | 21 ++ .../shop/domain/artist/entity/Artist.java | 106 ++++++++ .../domain/artist/entity/enums/Gender.java | 5 + .../artist/entity/enums/MakeupLocation.java | 5 + .../domain/artist/entity/enums/Region.java | 22 ++ .../artist/entity/enums/WorkExperience.java | 7 + .../artist/repository/ArtistRepository.java | 7 + .../domain/artist/service/ArtistService.java | 47 ++++ .../dto/request/FavoriteArtistDto.java | 12 + .../dto/request/FavoritePortfolioDto.java | 12 + .../FavoriteArtistPageResponseDto.java | 21 ++ .../response/FavoriteArtistResponseDto.java | 26 ++ .../FavoritePortfolioResponseDto.java | 40 +++ .../FavoritePortfolioResponsePageDto.java | 20 ++ .../favorite/entity/FavoriteArtist.java | 26 ++ .../favorite/entity/FavoritePortfolio.java | 29 ++ .../repository/FavoriteArtistRepository.java | 15 ++ .../FavoritePortfolioRepository.java | 15 ++ .../model/controller/ModelController.java | 119 +++++++++ .../model/dto/request/ModelProfileDto.java | 16 ++ .../meme/shop/domain/model/entity/Model.java | 86 ++++++ .../model/entity/enums/PersonalColor.java | 5 + .../domain/model/entity/enums/SkinType.java | 5 + .../model/repository/ModelRepository.java | 7 + .../domain/model/service/ModelService.java | 242 +++++++++++++++++ .../mypage/controller/MyPageController.java | 43 +++ .../mypage/dto/request/MypageInquiryDto.java | 27 ++ .../mypage/dto/response/MypageDetailDto.java | 20 ++ .../response/MypageInquiryResponseDto.java | 29 ++ .../mypage/dto/response/MypageTosDto.java | 10 + .../shop/domain/mypage/entity/Inquiry.java | 33 +++ .../mypage/repository/InquiryRepository.java | 7 + .../domain/mypage/service/MypageService.java | 83 ++++++ .../controller/PortfolioController.java | 46 ++++ .../converter/PortfolioConverter.java | 47 ++++ .../dto/request/CreatePortfolioDto.java | 29 ++ .../dto/request/UpdatePortfolioDto.java | 25 ++ .../portfolio/dto/response/PortfolioDto.java | 89 +++++++ .../dto/response/PortfolioImgDto.java | 21 ++ .../dto/response/PortfolioPageDto.java | 20 ++ .../domain/portfolio/entity/Portfolio.java | 96 +++++++ .../domain/portfolio/entity/PortfolioImg.java | 24 ++ .../portfolio/entity/enums/Category.java | 16 ++ .../repository/PortfolioImgRepository.java | 7 + .../repository/PortfolioRepository.java | 35 +++ .../portfolio/service/PortfolioService.java | 149 +++++++++++ .../controller/ReservationController.java | 63 +++++ .../dto/request/AlterReservationDto.java | 13 + .../dto/request/ReservationRequestDto.java | 24 ++ .../dto/response/ArtistLocationDto.java | 20 ++ .../dto/response/ArtistTimeDto.java | 17 ++ .../dto/response/ReservationCompleteDto.java | 25 ++ .../dto/response/ReservationResponseDto.java | 57 ++++ .../reservation/entity/Reservation.java | 64 +++++ .../reservation/entity/enums/Status.java | 5 + .../repository/ReservationRepository.java | 26 ++ .../service/ReservationService.java | 152 +++++++++++ .../review/controller/ReviewController.java | 46 ++++ .../review/converter/ReviewConverter.java | 27 ++ .../review/dto/request/DeleteReviewDto.java | 16 ++ .../domain/review/dto/request/ReviewDto.java | 21 ++ .../review/dto/response/ReviewImgDto.java | 14 + .../dto/response/ReviewListPageDto.java | 22 ++ .../dto/response/ReviewListResponseDto.java | 27 ++ .../dto/response/ReviewResponseDto.java | 34 +++ .../shop/domain/review/entity/Review.java | 39 +++ .../shop/domain/review/entity/ReviewImg.java | 24 ++ .../repository/ReviewImgRepository.java | 7 + .../review/repository/ReviewRepository.java | 11 + .../domain/review/service/ReviewService.java | 146 ++++++++++ .../java/umc/meme/shop/domain/user/User.java | 48 ++++ .../meme/shop/domain/user/UserRepository.java | 7 + .../umc/meme/shop/global/ErrorStatus.java | 77 ++++++ .../umc/meme/shop/global/SuccessStatus.java | 55 ++++ .../shop/global/config/SwaggerConfig.java | 40 +++ .../umc/meme/shop/global/enums/DayOfWeek.java | 6 + .../umc/meme/shop/global/enums/Times.java | 28 ++ .../global/exception/GlobalException.java | 11 + .../exception/GlobalExceptionAdvice.java | 18 ++ .../exception/GlobalExceptionHandler.java | 9 + .../shop/global/response/ApiResponse.java | 35 +++ src/test/java/umc/meme/shop/ArtistTest.java | 74 ++++++ .../umc/meme/shop/ShopApplicationTests.java | 13 + 104 files changed, 3848 insertions(+) create mode 100644 .DS_Store create mode 100644 .github/ISSUE_TEMPLATE/meme-bug-report-template.md create mode 100644 .github/ISSUE_TEMPLATE/meme-issue-template.md create mode 100644 .github/workflows/docker.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 build.gradle create mode 100644 docker-compose.yaml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/.DS_Store create mode 100644 src/main/.DS_Store create mode 100644 src/main/java/umc/meme/shop/ShopApplication.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/controller/ArtistController.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/converter/ArtistConverter.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/dto/request/ArtistProfileDto.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistDto.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistPageDto.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/Artist.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/enums/Gender.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/enums/MakeupLocation.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/enums/Region.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/entity/enums/WorkExperience.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/repository/ArtistRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/artist/service/ArtistService.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoriteArtistDto.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoritePortfolioDto.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistPageResponseDto.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistResponseDto.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponseDto.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponsePageDto.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/entity/FavoriteArtist.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/entity/FavoritePortfolio.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/repository/FavoriteArtistRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/favorite/repository/FavoritePortfolioRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/model/controller/ModelController.java create mode 100644 src/main/java/umc/meme/shop/domain/model/dto/request/ModelProfileDto.java create mode 100644 src/main/java/umc/meme/shop/domain/model/entity/Model.java create mode 100644 src/main/java/umc/meme/shop/domain/model/entity/enums/PersonalColor.java create mode 100644 src/main/java/umc/meme/shop/domain/model/entity/enums/SkinType.java create mode 100644 src/main/java/umc/meme/shop/domain/model/repository/ModelRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/model/service/ModelService.java create mode 100644 src/main/java/umc/meme/shop/domain/mypage/controller/MyPageController.java create mode 100644 src/main/java/umc/meme/shop/domain/mypage/dto/request/MypageInquiryDto.java create mode 100644 src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageDetailDto.java create mode 100644 src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageInquiryResponseDto.java create mode 100644 src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageTosDto.java create mode 100644 src/main/java/umc/meme/shop/domain/mypage/entity/Inquiry.java create mode 100644 src/main/java/umc/meme/shop/domain/mypage/repository/InquiryRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/mypage/service/MypageService.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/controller/PortfolioController.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/converter/PortfolioConverter.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/request/CreatePortfolioDto.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/request/UpdatePortfolioDto.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioDto.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioImgDto.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioPageDto.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/entity/Portfolio.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/entity/PortfolioImg.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/entity/enums/Category.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioImgRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/portfolio/service/PortfolioService.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/controller/ReservationController.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/request/AlterReservationDto.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/request/ReservationRequestDto.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistLocationDto.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistTimeDto.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationCompleteDto.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationResponseDto.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/entity/Reservation.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/entity/enums/Status.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/repository/ReservationRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/reservation/service/ReservationService.java create mode 100644 src/main/java/umc/meme/shop/domain/review/controller/ReviewController.java create mode 100644 src/main/java/umc/meme/shop/domain/review/converter/ReviewConverter.java create mode 100644 src/main/java/umc/meme/shop/domain/review/dto/request/DeleteReviewDto.java create mode 100644 src/main/java/umc/meme/shop/domain/review/dto/request/ReviewDto.java create mode 100644 src/main/java/umc/meme/shop/domain/review/dto/response/ReviewImgDto.java create mode 100644 src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListPageDto.java create mode 100644 src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListResponseDto.java create mode 100644 src/main/java/umc/meme/shop/domain/review/dto/response/ReviewResponseDto.java create mode 100644 src/main/java/umc/meme/shop/domain/review/entity/Review.java create mode 100644 src/main/java/umc/meme/shop/domain/review/entity/ReviewImg.java create mode 100644 src/main/java/umc/meme/shop/domain/review/repository/ReviewImgRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/review/repository/ReviewRepository.java create mode 100644 src/main/java/umc/meme/shop/domain/review/service/ReviewService.java create mode 100644 src/main/java/umc/meme/shop/domain/user/User.java create mode 100644 src/main/java/umc/meme/shop/domain/user/UserRepository.java create mode 100644 src/main/java/umc/meme/shop/global/ErrorStatus.java create mode 100644 src/main/java/umc/meme/shop/global/SuccessStatus.java create mode 100644 src/main/java/umc/meme/shop/global/config/SwaggerConfig.java create mode 100644 src/main/java/umc/meme/shop/global/enums/DayOfWeek.java create mode 100644 src/main/java/umc/meme/shop/global/enums/Times.java create mode 100644 src/main/java/umc/meme/shop/global/exception/GlobalException.java create mode 100644 src/main/java/umc/meme/shop/global/exception/GlobalExceptionAdvice.java create mode 100644 src/main/java/umc/meme/shop/global/exception/GlobalExceptionHandler.java create mode 100644 src/main/java/umc/meme/shop/global/response/ApiResponse.java create mode 100644 src/test/java/umc/meme/shop/ArtistTest.java create mode 100644 src/test/java/umc/meme/shop/ShopApplicationTests.java diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..52b68ac73a2790bd5ed2253a0632977fbbca5ad8 GIT binary patch literal 8196 zcmeHM%}*0S6o13#RzQ}IBJm^H*oz4S5yg*qaH$YOjDfTSA%JzaJJb!!PTk#7k&yJP ze}I30R})VrUOjp9=+%S&fEN#*@XbdBTJWZrIFHQyrZexiZ{Ba)oxTD9BwO*W01N|w zfsLcth20Ux*LiEQ7B$0p1o;5oY`}_cz}zNZJ)srQ3TOqi0$KsBz`vmYp4r@tW6piK zs(Y<~R^Y!>fIlBBY#eQcHHqTUft@G;5ZiEC7>=gCaOXqB0BOc;SR)>sC%t|R-jn{e)hM63l;DoI8?v$57HF2 zu{~je+P&`yV^D$!9Pp4w57hmf_qKu8al9|N(BRv7&=;zQuS{Mxcy}H4#$CC%r=)@P zqk)xz9L!*L)9?Us3^p4xZz(k}dLaf13I6#IV$Arr`E%Xg9MG*5{UazI-jz`42rsu9 zm(_15@7;3X$I1BkXVTKz*51)+bQ)d8TK);E<`XBW#91d=;jb1L3*7qHaTk4BEtrFM zS(rF}NFzb;J&G=?5B<<%)hw%oUM#qIxnQJ>RKXnH*_j+4AGNOCoY)<;c5Y4Z@zv|Q zyD1}`xqLfU*a$X5_5$-mBkExcJ@WOhp5G;vvtQg&*^rO*Y`&OgJ)hL6uI`@Gy=Gtk zK;K|rI-MRmlOFCrd#+#(xK44S6!CrDWdVz_L4_8~-Wao;EwXSvqFb2dQbM04dH*>s z^*0c5)O)l)wXj`ApTYeJanXAbrQu2`^1ZqB^_V70JVG&IK`_r^Kk-?(d|-8XRYXtd z=4`mmFe2Z`DnT$p7^!Zw$D%!2P+1jv`2q92wr zcfLsxQyKe`9GQ@*>uL^Qeb}oSeE&?p8hu0~YcRi}FSg zCorPL35d4BnnavI)91gCL3dh#6H}m7Mjqzh0cMW>{r|-FrvqyRv;u!#0n#>|pUz?& zc{Dc% DUQ09U literal 0 HcmV?d00001 diff --git a/.github/ISSUE_TEMPLATE/meme-bug-report-template.md b/.github/ISSUE_TEMPLATE/meme-bug-report-template.md new file mode 100644 index 0000000..1ad06b8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/meme-bug-report-template.md @@ -0,0 +1,19 @@ +--- +name: MEME BUG REPORT TEMPLATE +about: 메메 버그 이슈 템플릿 +title: '' +labels: '' +assignees: '' + +--- + +## 🐞 버그 설명 +| 문제 발생 일시 | 발생 위치 | 발생 조건 | +| --- | --- | --- | +| | | | + +## 💣 증상 + + +## 🎥 스크린샷 + diff --git a/.github/ISSUE_TEMPLATE/meme-issue-template.md b/.github/ISSUE_TEMPLATE/meme-issue-template.md new file mode 100644 index 0000000..ddee7b1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/meme-issue-template.md @@ -0,0 +1,15 @@ +--- +name: MEME ISSUE TEMPLATE +about: 메메 기본 이슈 템플릿 +title: '' +labels: '' +assignees: '' + +--- + +## 💡 Description + + +## 📝 Progress + +- [ ] todo ! diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..4af70f3 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,95 @@ +name: main Workflow + +on: + push: + branches: + - develop +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' + + - name: Set .yml for main + run: | + mkdir -p src/main/resources + echo "${{ secrets.MAIN_DATABASE_YML }}" | base64 --decode > src/main/resources/application.yml + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Run chmod to make gradlew executable + run: chmod +x ./gradlew + + - name: Build with Gradle + run: ./gradlew clean build --exclude-task test + + ## 웹 이미지 빌드 및 도커허브에 push + - name: web docker build and push + run: | + docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} + docker build -t ${{ secrets.DOCKER_REPO }}/meme-service . + docker push ${{ secrets.DOCKER_REPO }}/meme-service + + - name: EC2 docker remove + uses: appleboy/ssh-action@v0.1.6 + with: + host: ${{ secrets.HOST }} + username: ec2-user + key: ${{ secrets.KEY }} + script: | + if [ "$(sudo docker ps -aq)" ]; then + sudo docker stop $(sudo docker ps -aq) + sudo docker rm -f $(sudo docker ps -aq) + fi + if [ "$(sudo docker images -aq)" ]; then + sudo docker rmi -f $(sudo docker images -aq) + fi + + - name: Copy file to EC2 + uses: appleboy/scp-action@master + with: + host: ${{ secrets.HOST }} + username: ec2-user + key: ${{ secrets.KEY }} + source: ./docker-compose.yaml + target: /home/ec2-user/ + + - name: Create and Copy .env File to EC2 + uses: appleboy/ssh-action@v0.1.6 + with: + host: ${{ secrets.HOST }} + username: ec2-user + key: ${{ secrets.KEY }} + script: | + # Create .env file + echo "DB_URL=${{ secrets.DB_URL }}" > ~/.env + echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> ~/.env + echo "DB_PASS=${{ secrets.DB_PASS }}" >> ~/.env + + # Copy .env file to the project directory + #cp ~/.env /home/ec2-user/.env + + ## docker compose up + - name: Docker Compose on EC2 + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST }} + username: ec2-user + key: ${{ secrets.KEY }} + script: | + # Docker 이미지 다운로드 + sudo docker pull ${{ secrets.DOCKER_REPO }}/meme-service + + # Docker Compose 실행 + sudo docker-compose up -d + sudo docker-compose logs -f + + # 사용하지 않는 Docker 이미지 정리 + sudo docker image prune -f \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd5c9d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ +src/main/resources/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +*.xml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..189b146 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:17-alpine +ARG JAR_FILE=build/libs/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["java","-jar","/app.jar"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee4f75a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# MEME_SERVICE \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..2822e36 --- /dev/null +++ b/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.2.1' + id 'io.spring.dependency-management' version '1.1.4' +} + +group = 'umc.meme' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '17' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'com.mysql:mysql-connector-j' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..68df57a --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,18 @@ +version: '3' +services: + web: + container_name: service + image: sunwupark/meme-service + expose: + - 8080 + ports: + - "8080:8080" + + auth: + container_name: auth + image: sunwupark/meme-auth + expose: + - 8081 + ports: + - "8081:8081" + depends_on: web diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..d64cd4917707c1f8861d8cb53dd15194d4248596 GIT binary patch literal 43462 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..1af9e09 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..1aa94a4 --- /dev/null +++ b/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..6689b85 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..c1e09f9 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'shop' diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5a6a5ada3fa1f6dcca6c428d35be9b424607b7e1 GIT binary patch literal 6148 zcmeHK%Wl&^6rE`Uby`Z@HYpXbu*e3fl?a9M5DVP22vsav#T6uKO0eTeuc=A2kq#qkWb5Ya-ri!dIB#9QwXi>L?cHAB`n4PT`&lDjxN@gl-wxZ9 zy_5uE*l&c4D@@@PC<19ess@;q^Z7vP%uDWOdK$A_kk-44X$ z4h>?^`w<~@vlRvYTC*9Gq{3%tL@W%~SsWw*qtzqcYE8_ZkoGEVGMJIS!CHrh#Scjo z0}kX@s%{jyv_(q0TcPWbaE+E&lCX9qfGYT#iwT^L+X!f@aQCZZF51Bx_b?8GST)C_0_ z{znG*{$N4lXe;bX6k7*$;tBwm0kaU$`CWqNSPE^0eTm=!!7>$4rebx)z%m`|mWs0# z_9e=6gw^E(tC_L7pgl&ns*9>R|jx)gj{XtBA{@;T&{G0o~2-2NqKr`@f zGJrEH&PoYtQ)lZymHe!=pgn=cg~#S5Z-O8O(;SR3Oz1(Eg0($ikA@U3mDOZN^NY=V9ZLAnnNk%tS{t~_&m<+ zZpG3HoOP&I{Ll=e2rcWwmKFt(J8i+{-d32E{1% z2iYa|&ZJDjsXYkK&G%J25}l?svsUlkaBeqr$br#a+D5pRU7DlWm|UNX^+Qy zuGB9$kIfncMzRc zPAdqB0b+m{SQZA%{%5t8Wx_O1Vt^RpM3xRpDm&uF+dFbD+YL@7xa9Xk~v%FCWmLO0KEZ4!MsZ2X9*bUD27}-irb({ Zz%S4M^bA%S!2?1U0Yw8f#K5mI@BvrmO{4$- literal 0 HcmV?d00001 diff --git a/src/main/java/umc/meme/shop/ShopApplication.java b/src/main/java/umc/meme/shop/ShopApplication.java new file mode 100644 index 0000000..e4d47bc --- /dev/null +++ b/src/main/java/umc/meme/shop/ShopApplication.java @@ -0,0 +1,15 @@ +package umc.meme.shop; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@SpringBootApplication +@EnableJpaAuditing +public class ShopApplication { + + public static void main(String[] args) { + SpringApplication.run(ShopApplication.class, args); + } + +} diff --git a/src/main/java/umc/meme/shop/domain/artist/controller/ArtistController.java b/src/main/java/umc/meme/shop/domain/artist/controller/ArtistController.java new file mode 100644 index 0000000..3185ce0 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/controller/ArtistController.java @@ -0,0 +1,37 @@ +package umc.meme.shop.domain.artist.controller; + +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import umc.meme.shop.domain.artist.dto.request.ArtistProfileDto; +import umc.meme.shop.domain.artist.service.ArtistService; +import umc.meme.shop.global.SuccessStatus; +import umc.meme.shop.global.response.ApiResponse; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class ArtistController { + private final ArtistService artistService; + + @Operation(summary = "아티스트 프로필 관리") + @PatchMapping("/mypage/profile/artist") + public ApiResponse updateProfile(@RequestBody ArtistProfileDto profileDto){ + artistService.updateArtistProfile(profileDto); + return ApiResponse.SuccessResponse(SuccessStatus.ARTIST_PROFILE_UPDATE); + } + + @Operation(summary = "아티스트 프로필 조회") + @GetMapping("/profile/{artistId}") + public ApiResponse getArtistProfile(@PathVariable Long artistId){ + return ApiResponse.SuccessResponse(SuccessStatus.ARTIST_PROFILE_GET, artistService.getArtistProfile(artistId)); + } + + //temp method for Artist create + @PostMapping("/artist") + public ApiResponse createArtist(@RequestBody ArtistProfileDto profileDto){ + artistService.createArtist(profileDto); + return ApiResponse.SuccessResponse(SuccessStatus.TEMP); + } + +} diff --git a/src/main/java/umc/meme/shop/domain/artist/converter/ArtistConverter.java b/src/main/java/umc/meme/shop/domain/artist/converter/ArtistConverter.java new file mode 100644 index 0000000..af78368 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/converter/ArtistConverter.java @@ -0,0 +1,21 @@ +package umc.meme.shop.domain.artist.converter; + +import org.springframework.data.domain.Page; +import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistPageResponseDto; +import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistResponseDto; +import umc.meme.shop.domain.favorite.entity.FavoriteArtist; + +import java.util.List; + +public class ArtistConverter { + public static FavoriteArtistPageResponseDto favoriteArtistPageConverter(Page page, List content) { + + return FavoriteArtistPageResponseDto.builder() + .content(content) + .pageSize(page.getSize()) + .currentPage(page.getNumber()) + .totalNumber(page.getNumberOfElements()) + .totalPage(page.getTotalPages()) + .build(); + } +} diff --git a/src/main/java/umc/meme/shop/domain/artist/dto/request/ArtistProfileDto.java b/src/main/java/umc/meme/shop/domain/artist/dto/request/ArtistProfileDto.java new file mode 100644 index 0000000..ab1bdc9 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/dto/request/ArtistProfileDto.java @@ -0,0 +1,29 @@ +package umc.meme.shop.domain.artist.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.artist.entity.enums.*; +import umc.meme.shop.domain.portfolio.entity.enums.Category; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; + +import java.util.List; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ArtistProfileDto { + private Long artistId; + private String profileImg; + private String nickname; + private Gender gender; + private String introduction; + private WorkExperience workExperience; + private List region; + private List specialization; + private MakeupLocation makeupLocation; + private String shopLocation; + private Map availableDayOfWeek; +} diff --git a/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistDto.java b/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistDto.java new file mode 100644 index 0000000..dd648b9 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistDto.java @@ -0,0 +1,75 @@ +package umc.meme.shop.domain.artist.dto.response; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.artist.entity.enums.*; +import umc.meme.shop.domain.artist.repository.ArtistRepository; +import umc.meme.shop.domain.favorite.entity.FavoriteArtist; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; +import umc.meme.shop.domain.user.User; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ArtistDto { + private Long artistId; + + private Gender gender; + + private String nickname; + + private String profileImg; + + private String introduction; + + private WorkExperience workExperience; + + private List region; + + private List specialization; + + private MakeupLocation makeupLocation; + + private Map availableDayOfWeekAndTime; + + private List portfolioDtoList; + + + + public static ArtistDto from(Artist artist){ + List portfolioDtoList = artist.getPortfolioList() + .stream() + .map(PortfolioDto::from) + .toList(); + + return ArtistDto.builder() + .artistId(artist.getUserId()) + .gender(artist.getGender()) + .nickname(artist.getNickname()) + .profileImg(artist.getProfileImg()) + .introduction(artist.getIntroduction()) + .workExperience(artist.getWorkExperience()) + .region(artist.getRegion()) + .specialization(artist.getSpecialization()) + .makeupLocation(artist.getMakeupLocation()) + .availableDayOfWeekAndTime(artist.getAvailableDayOfWeekAndTime()) + .portfolioDtoList(portfolioDtoList) + .build(); + } + +} + + diff --git a/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistPageDto.java b/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistPageDto.java new file mode 100644 index 0000000..622e8f5 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/dto/response/ArtistPageDto.java @@ -0,0 +1,21 @@ +package umc.meme.shop.domain.artist.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ArtistPageDto { + private List content; + private int currentPage; //현재 페이지 번호 + private int pageSize; //페이지 크기 + private int totalNumber; //전체 메이크업 개수 + private int totalPage; //전체 페이지 개수 +} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/Artist.java b/src/main/java/umc/meme/shop/domain/artist/entity/Artist.java new file mode 100644 index 0000000..1157b97 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/entity/Artist.java @@ -0,0 +1,106 @@ +package umc.meme.shop.domain.artist.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import umc.meme.shop.domain.user.User; +import umc.meme.shop.domain.artist.dto.request.ArtistProfileDto; +import umc.meme.shop.domain.artist.entity.enums.*; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.portfolio.entity.enums.Category; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +@SuperBuilder +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Artist extends User { + + @Column(nullable = false, length = 500) + private String introduction; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private WorkExperience workExperience; + + @ElementCollection(fetch = FetchType.LAZY) + private List region; + + @ElementCollection(fetch = FetchType.LAZY) + private List specialization; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private MakeupLocation makeupLocation; + + @Column(nullable = true) + private String shopLocation; //샵의 위치 + + @Column(nullable = true) + private Date inactiveDate; + + @ElementCollection + @CollectionTable(name = "available_time_mapping", + joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")}) + @MapKeyColumn(name = "day_of_week") + @Enumerated(EnumType.STRING) + @Column(nullable = true) + private Map availableDayOfWeekAndTime; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "artist") + private List portfolioList; + + + public void updateArtist(ArtistProfileDto request) { + if (request.getProfileImg() != null) + this.profileImg = request.getProfileImg(); + if (request.getNickname() != null) + this.nickname = request.getNickname(); + if (request.getGender() != null) + this.gender = request.getGender(); + if (request.getIntroduction() != null) + this.introduction = request.getIntroduction(); + if (request.getWorkExperience() != null) + this.workExperience = request.getWorkExperience(); + + //region mapping + if (request.getRegion() != null){ + List regionList = new ArrayList<>(); + for(Region region : request.getRegion()) + regionList.add(region.getValue()); + this.region = regionList; + } + + //specialization mapping + if (request.getSpecialization() != null){ + List specialization = new ArrayList<>(); + for(Category category : request.getSpecialization()) + specialization.add(category.getValue()); + this.specialization = specialization; + } + if (request.getMakeupLocation() != null) + this.makeupLocation = request.getMakeupLocation(); + if (request.getShopLocation() != null) + this.shopLocation = request.getShopLocation(); + if (request.getAvailableDayOfWeek() != null) + this.availableDayOfWeekAndTime = request.getAvailableDayOfWeek(); + } + + public void updatePortfolioList(Portfolio portfolio){ + this.portfolioList.add(portfolio); + } + + public void tempMethod(String email, String name){ + this.email = email; + this.name = name; + } +} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/enums/Gender.java b/src/main/java/umc/meme/shop/domain/artist/entity/enums/Gender.java new file mode 100644 index 0000000..cdbc18a --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/entity/enums/Gender.java @@ -0,0 +1,5 @@ +package umc.meme.shop.domain.artist.entity.enums; + +public enum Gender { + MALE, FEMALE +} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/enums/MakeupLocation.java b/src/main/java/umc/meme/shop/domain/artist/entity/enums/MakeupLocation.java new file mode 100644 index 0000000..f6e3d45 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/entity/enums/MakeupLocation.java @@ -0,0 +1,5 @@ +package umc.meme.shop.domain.artist.entity.enums; + +public enum MakeupLocation { + SHOP, VISIT, BOTH +} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/enums/Region.java b/src/main/java/umc/meme/shop/domain/artist/entity/enums/Region.java new file mode 100644 index 0000000..f025e54 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/entity/enums/Region.java @@ -0,0 +1,22 @@ +package umc.meme.shop.domain.artist.entity.enums; + +public enum Region { + JONGNO("jongno"), JUNG("jung"), YONGSAN("yongsan"), SEONGDONG("seongdong"), + GWANGJIN("gwangjin"), DONGDAEMUN("dongdaemun"), + JUNGNANG("jungnang"), SEONGBUK("seongbuk"), GANGBUK("gangbuk"), + DOBONG("dobong"), NOWON("nowon"), EUNPYEONG("eunpyeong"), + SEODAEMUN("seodaemun"), MAPO("mapo"), YANGCHEON("yangcheon"), + GANGSEO("gangseo"), GURO("guro"), GEUMCHEON("geumcheon"), + YEONGDEUNGPO("yeongdeunpo"), DONGJAK("dongjak"), GWANAK("gwanak"), + SEOCHO("seocho"), GANGNAM("gangnam"), SONGPA("songpa"), GANGDONG("gangdong"); + + private String value; + + Region(String value){ + this.value = value; + } + + public String getValue(){ + return this.value; + } +} diff --git a/src/main/java/umc/meme/shop/domain/artist/entity/enums/WorkExperience.java b/src/main/java/umc/meme/shop/domain/artist/entity/enums/WorkExperience.java new file mode 100644 index 0000000..5bd7d94 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/entity/enums/WorkExperience.java @@ -0,0 +1,7 @@ +package umc.meme.shop.domain.artist.entity.enums; + +public enum WorkExperience { + ONE, TWO, THREE, FOUR, + FIVE, SIX, SEVEN, EIGHT, + NINE, TEN +} diff --git a/src/main/java/umc/meme/shop/domain/artist/repository/ArtistRepository.java b/src/main/java/umc/meme/shop/domain/artist/repository/ArtistRepository.java new file mode 100644 index 0000000..b753258 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/repository/ArtistRepository.java @@ -0,0 +1,7 @@ +package umc.meme.shop.domain.artist.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.meme.shop.domain.artist.entity.Artist; + +public interface ArtistRepository extends JpaRepository { +} diff --git a/src/main/java/umc/meme/shop/domain/artist/service/ArtistService.java b/src/main/java/umc/meme/shop/domain/artist/service/ArtistService.java new file mode 100644 index 0000000..9654cae --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/artist/service/ArtistService.java @@ -0,0 +1,47 @@ +package umc.meme.shop.domain.artist.service; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import umc.meme.shop.domain.artist.dto.request.ArtistProfileDto; +import umc.meme.shop.domain.artist.dto.response.ArtistDto; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.artist.entity.enums.*; +import umc.meme.shop.domain.artist.repository.ArtistRepository; +import umc.meme.shop.domain.portfolio.entity.enums.Category; +import umc.meme.shop.global.ErrorStatus; +import umc.meme.shop.global.exception.GlobalException; + +import java.util.List; + + +@Service +@RequiredArgsConstructor +public class ArtistService { + private final ArtistRepository artistRepository; + + //아티스트 프로필 관리/수정 + @Transactional + public void updateArtistProfile(ArtistProfileDto profileDto){ + Artist artist = artistRepository.findById(profileDto.getArtistId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + artist.updateArtist(profileDto); + } + + //아티스트 프로필 조회 + public ArtistDto getArtistProfile(Long artistId){ + Artist artist = artistRepository.findById(artistId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + return ArtistDto.from(artist); + } + + //temp method for create Artist + @Transactional + public void createArtist(ArtistProfileDto dto){ + Artist artist = new Artist(); + artist.updateArtist(dto); + artist.tempMethod("", "testName"); + artistRepository.save(artist); + } + +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoriteArtistDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoriteArtistDto.java new file mode 100644 index 0000000..89ee784 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoriteArtistDto.java @@ -0,0 +1,12 @@ +package umc.meme.shop.domain.favorite.dto.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class FavoriteArtistDto { + @NotBlank(message = "modelId를 입력해주세요.") + private Long modelId; + @NotBlank(message = "artistId를 입력해주세요.") + private Long artistId; +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoritePortfolioDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoritePortfolioDto.java new file mode 100644 index 0000000..c30ac62 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/dto/request/FavoritePortfolioDto.java @@ -0,0 +1,12 @@ +package umc.meme.shop.domain.favorite.dto.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class FavoritePortfolioDto { + @NotBlank(message = "modelId를 입력해주세요.") + private Long modelId; + @NotBlank(message = "portfolioId를 입력해주세요.") + private Long portfolioId; +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistPageResponseDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistPageResponseDto.java new file mode 100644 index 0000000..937cdba --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistPageResponseDto.java @@ -0,0 +1,21 @@ +package umc.meme.shop.domain.favorite.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.favorite.entity.FavoriteArtist; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FavoriteArtistPageResponseDto { + private List content; + private int currentPage; //현재 페이지 번호 + private int pageSize; //페이지 크기 + private int totalNumber; //전체 메이크업 개수 + private int totalPage; //전체 페이지 개수 +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistResponseDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistResponseDto.java new file mode 100644 index 0000000..12f8315 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoriteArtistResponseDto.java @@ -0,0 +1,26 @@ +package umc.meme.shop.domain.favorite.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.favorite.entity.FavoriteArtist; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class FavoriteArtistResponseDto { + private Long artistId; + private String profileImg; + private String artistNickName; + + public static FavoriteArtistResponseDto from(Artist artist) { + return FavoriteArtistResponseDto.builder() + .artistId(artist.getUserId()) + .profileImg(artist.getProfileImg()) + .artistNickName(artist.getNickname()) + .build(); + } +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponseDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponseDto.java new file mode 100644 index 0000000..98c3e6f --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponseDto.java @@ -0,0 +1,40 @@ +package umc.meme.shop.domain.favorite.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.portfolio.entity.PortfolioImg; +import umc.meme.shop.domain.portfolio.entity.enums.Category; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FavoritePortfolioResponseDto { + private Long portfolioId; + private String portfolioImg; + private Category category; + private String makeupName; + private int price; + + public static FavoritePortfolioResponseDto from(FavoritePortfolio favoritePortfolio) { + + Portfolio portfolio = favoritePortfolio.getPortfolio(); + + return FavoritePortfolioResponseDto.builder() + .portfolioId(portfolio.getPortfolioId()) + .portfolioImg(portfolio.getPortfolioImgList().get(0).getSrc()) + .category(portfolio.getCategory()) + .makeupName(portfolio.getMakeupName()) + .price(portfolio.getPrice()) + .build(); + + } +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponsePageDto.java b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponsePageDto.java new file mode 100644 index 0000000..1bff5ab --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/dto/response/FavoritePortfolioResponsePageDto.java @@ -0,0 +1,20 @@ +package umc.meme.shop.domain.favorite.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FavoritePortfolioResponsePageDto { + private List content; + private int currentPage; //현재 페이지 번호 + private int pageSize; //페이지 크기 + private int totalNumber; //전체 메이크업 개수 + private int totalPage; //전체 페이지 개수 +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/entity/FavoriteArtist.java b/src/main/java/umc/meme/shop/domain/favorite/entity/FavoriteArtist.java new file mode 100644 index 0000000..6f0a3f2 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/entity/FavoriteArtist.java @@ -0,0 +1,26 @@ +package umc.meme.shop.domain.favorite.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.model.entity.Model; + +@Builder +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class FavoriteArtist { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long favoriteArtistId; + + @ManyToOne + @JoinColumn(name="user_id", nullable = false) + private Model model; + + private Long artistId; +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/entity/FavoritePortfolio.java b/src/main/java/umc/meme/shop/domain/favorite/entity/FavoritePortfolio.java new file mode 100644 index 0000000..c4e930e --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/entity/FavoritePortfolio.java @@ -0,0 +1,29 @@ +package umc.meme.shop.domain.favorite.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.user.User; + +@Builder +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class FavoritePortfolio { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long favoritePortfolioId; + + @ManyToOne + @JoinColumn(name="user_id", nullable = false) + private User model; + + @ManyToOne + @JoinColumn(name="portfolio_id", nullable = false) + private Portfolio portfolio; +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/repository/FavoriteArtistRepository.java b/src/main/java/umc/meme/shop/domain/favorite/repository/FavoriteArtistRepository.java new file mode 100644 index 0000000..472285d --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/repository/FavoriteArtistRepository.java @@ -0,0 +1,15 @@ +package umc.meme.shop.domain.favorite.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.favorite.entity.FavoriteArtist; +import umc.meme.shop.domain.model.entity.Model; + +import java.util.List; +import java.util.Optional; + +public interface FavoriteArtistRepository extends JpaRepository { + List findByModel(Model model); + boolean existsByModelAndArtistId(Model model, Long userId); + Optional findByModelAndArtistId(Model model, Long userId); +} diff --git a/src/main/java/umc/meme/shop/domain/favorite/repository/FavoritePortfolioRepository.java b/src/main/java/umc/meme/shop/domain/favorite/repository/FavoritePortfolioRepository.java new file mode 100644 index 0000000..e6d2c5d --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/favorite/repository/FavoritePortfolioRepository.java @@ -0,0 +1,15 @@ +package umc.meme.shop.domain.favorite.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; +import umc.meme.shop.domain.model.entity.Model; +import umc.meme.shop.domain.portfolio.entity.Portfolio; + +import java.util.List; +import java.util.Optional; + +public interface FavoritePortfolioRepository extends JpaRepository { + List findByModel(Model model); + boolean existsByModelAndPortfolio(Model model, Portfolio portfolio); + Optional findByModelAndPortfolio(Model model, Portfolio portfolio); +} diff --git a/src/main/java/umc/meme/shop/domain/model/controller/ModelController.java b/src/main/java/umc/meme/shop/domain/model/controller/ModelController.java new file mode 100644 index 0000000..4eb6ccf --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/model/controller/ModelController.java @@ -0,0 +1,119 @@ +package umc.meme.shop.domain.model.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import umc.meme.shop.domain.artist.dto.request.ArtistProfileDto; +import umc.meme.shop.domain.favorite.dto.request.FavoriteArtistDto; +import umc.meme.shop.domain.favorite.dto.request.FavoritePortfolioDto; +import umc.meme.shop.domain.model.dto.request.ModelProfileDto; +import umc.meme.shop.domain.model.service.ModelService; +import umc.meme.shop.domain.portfolio.entity.enums.Category; +import umc.meme.shop.global.SuccessStatus; +import umc.meme.shop.global.response.ApiResponse; + + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class ModelController { + private final ModelService modelService; + + /**temp model create method**/ + @PostMapping("/model") + public ApiResponse createModel(@RequestBody ModelProfileDto profileDto){ + modelService.createModel(profileDto); + return ApiResponse.SuccessResponse(SuccessStatus.TEMP); + } + + @Operation(summary = "모델 프로필 관리") + @PatchMapping("/mypage/profile/model") + public ApiResponse updateModelProfile (@RequestBody ModelProfileDto modelProfileDto){ + modelService.updateModelProfile(modelProfileDto); + return ApiResponse.SuccessResponse(SuccessStatus.MODEL_PROFILE_UPDATE); + } + + /**favorite**/ + + @Operation(summary = "관심 아티스트 조회", description = "관심 아티스트를 조회하는 API입니다.") + @GetMapping("/mypage/{modelId}/favorite/artist") + public ApiResponse getFavoriteArtist(@PathVariable Long modelId, + @RequestParam(value = "page", defaultValue = "0", required = false)int page){ + return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_ARTIST_GET, modelService.getFavoriteArtist(modelId, page)); + } + + @Operation(summary = "관심 메이크업 조회", description = "관심 메이크업을 조회하는 API입니다.") + @GetMapping("/mypage/{modelId}/favorite/portfolio") + public ApiResponse getFavoritePortfolio(@PathVariable Long modelId, + @RequestParam(value = "page", defaultValue = "0", required = false) int page + ){ + return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_PORTFOLIO_GET, modelService.getFavoritePortfolio(modelId, page)); + } + + @Operation(summary = "관심 아티스트 추가", description = "관심 아티스트를 추가하는 API입니다.") + @PostMapping("/mypage/favorite/artist") + public ApiResponse postFavoriteArtist(@RequestBody FavoriteArtistDto favoriteArtistDto) { + modelService.addFavoriteArtist(favoriteArtistDto); + return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_ARTIST_POST); + } + + @Operation(summary = "관심 메이크업 추가", description = "관심 메이크업을 추가하는 API입니다.") + @PostMapping("/mypage/favorite/portfolio") + public ApiResponse postFavoritePortfolio(@RequestBody FavoritePortfolioDto favoritePortfolioDto) { + modelService.addFavoritePortfolio(favoritePortfolioDto); + return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_PORTFOLIO_POST); + } + + @Operation(summary = "관심 아티스트 삭제", description = "관심 아티스트를 삭제하는 API입니다.") + @DeleteMapping("/mypage/favorite/artist") + public ApiResponse deleteFavoriteArtist(@RequestBody FavoriteArtistDto favoriteArtistDto) { + modelService.deleteFavoriteArtist(favoriteArtistDto); + return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_ARTIST_DELETE); + } + + @Operation(summary = "관심 메이크업 삭제", description = "관심 메이크업을 삭제하는 API입니다.") + @DeleteMapping("/mypage/favorite/portfolio") + public ApiResponse deleteFavoritePortfolio(@RequestBody FavoritePortfolioDto favoritePortfolioDto) { + modelService.deleteFavoritePortfolio(favoritePortfolioDto); + return ApiResponse.SuccessResponse(SuccessStatus.FAVORITE_PORTFOLIO_DELETE); + } + + + /**search**/ + + @Operation(summary = "메이크업 검색", description = "메이크업을 검색/최근 검색어로 검색하는 API입니다.") + @GetMapping("/search") + public ApiResponse search(@Parameter String query, + @RequestParam(value = "page", defaultValue = "0", required = false) int page, + @RequestParam(value = "sort", defaultValue = "desc") String sort){ + return ApiResponse.SuccessResponse(SuccessStatus.SEARCH_GET, modelService.search(query, page, sort)); + } + + @Operation(summary = "메이크업 검색 - 관심 아티스트", description = "관심 아티스트로 검색하는 API입니다.") + @GetMapping("/search/artist") + public ApiResponse searchArtist(@Parameter Long artistId, + @RequestParam(value = "page", defaultValue = "0", required = false) int page, + @RequestParam(value = "sort", defaultValue = "desc") String sort + ){ + return ApiResponse.SuccessResponse(SuccessStatus.SEARCH_GET, modelService.searchArtist(artistId, page, sort)); + } + + @Operation(summary = "메이크업 검색 - 카테고리", description = "메이크업 카테고리로 검색하는 API입니다.") + @GetMapping("/search/category") + public ApiResponse searchCategory(@Parameter Category category, + @RequestParam(value = "page", defaultValue = "0", required = false) int page, + @RequestParam(value = "sort", defaultValue = "desc") String sort + ){ + return ApiResponse.SuccessResponse(SuccessStatus.SEARCH_GET, modelService.searchCategory(category, page, sort)); + } + + @Operation(summary = "메이크업 검색 - 전체", description = "메이크업 전체를 검색하는 API입니다.") + @GetMapping("/search/all") + public ApiResponse searchAll( @RequestParam(value = "page", defaultValue = "0", required = false) int page, + @RequestParam(value = "sort", defaultValue = "desc") String sort + ){ + return ApiResponse.SuccessResponse(SuccessStatus.SEARCH_GET, modelService.searchAll(page, sort)); + } + +} diff --git a/src/main/java/umc/meme/shop/domain/model/dto/request/ModelProfileDto.java b/src/main/java/umc/meme/shop/domain/model/dto/request/ModelProfileDto.java new file mode 100644 index 0000000..cd72b1d --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/model/dto/request/ModelProfileDto.java @@ -0,0 +1,16 @@ +package umc.meme.shop.domain.model.dto.request; + +import lombok.Data; +import umc.meme.shop.domain.artist.entity.enums.Gender; +import umc.meme.shop.domain.model.entity.enums.PersonalColor; +import umc.meme.shop.domain.model.entity.enums.SkinType; + +@Data +public class ModelProfileDto { + private Long modelId; + private String profileImg; + private String nickname; + private Gender gender; + private SkinType skinType; + private PersonalColor personalColor; +} diff --git a/src/main/java/umc/meme/shop/domain/model/entity/Model.java b/src/main/java/umc/meme/shop/domain/model/entity/Model.java new file mode 100644 index 0000000..9fa7b13 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/model/entity/Model.java @@ -0,0 +1,86 @@ +package umc.meme.shop.domain.model.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import umc.meme.shop.domain.artist.entity.enums.Gender; +import umc.meme.shop.domain.favorite.entity.FavoriteArtist; +import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; +import umc.meme.shop.domain.model.dto.request.ModelProfileDto; +import umc.meme.shop.domain.model.entity.enums.PersonalColor; +import umc.meme.shop.domain.model.entity.enums.SkinType; +import umc.meme.shop.domain.reservation.entity.Reservation; +import umc.meme.shop.domain.review.entity.Review; +import umc.meme.shop.domain.user.User; + +import java.util.Date; +import java.util.List; + +@SuperBuilder +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Model extends User { + + @Column(nullable = true, length = 500) + private String introduction; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private SkinType skinType; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private PersonalColor personalColor; + + private Date inactive; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "model") + private List favoritePortfolioList; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "model") + private List favoriteArtistList; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "model") + private List reservationList; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "model") + private List reviewList; + + public void updateModel(ModelProfileDto request) { + if(request.getProfileImg() != null){ + this.profileImg = request.getProfileImg(); + } + if(request.getNickname() != null){ + this.nickname = request.getNickname(); + } + if(request.getGender() != null){ + this.gender = request.getGender(); + } + if(request.getSkinType() != null){ + this.skinType = request.getSkinType(); + } + if(request.getPersonalColor() != null){ + this.personalColor = request.getPersonalColor(); + } + } + + public void updateFavoriteArtistList(FavoriteArtist artist){ + this.favoriteArtistList.add(artist); + } + + public void updateFavoritePortfolioList(FavoritePortfolio portfolio){ + this.favoritePortfolioList.add(portfolio); + } + public void updateReservationList(Reservation reservation){ + this.reservationList.add(reservation); + } + + public void updateReviewList(Review review){ + this.reviewList.add(review); + } +} diff --git a/src/main/java/umc/meme/shop/domain/model/entity/enums/PersonalColor.java b/src/main/java/umc/meme/shop/domain/model/entity/enums/PersonalColor.java new file mode 100644 index 0000000..dadc7a1 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/model/entity/enums/PersonalColor.java @@ -0,0 +1,5 @@ +package umc.meme.shop.domain.model.entity.enums; + +public enum PersonalColor { + SPRING, SUMMER, AUTUMN, WINTER +} diff --git a/src/main/java/umc/meme/shop/domain/model/entity/enums/SkinType.java b/src/main/java/umc/meme/shop/domain/model/entity/enums/SkinType.java new file mode 100644 index 0000000..6f169da --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/model/entity/enums/SkinType.java @@ -0,0 +1,5 @@ +package umc.meme.shop.domain.model.entity.enums; + +public enum SkinType { + DRY, COMMON, OILY, COMBINATIONAL +} diff --git a/src/main/java/umc/meme/shop/domain/model/repository/ModelRepository.java b/src/main/java/umc/meme/shop/domain/model/repository/ModelRepository.java new file mode 100644 index 0000000..0dcf9ab --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/model/repository/ModelRepository.java @@ -0,0 +1,7 @@ +package umc.meme.shop.domain.model.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.meme.shop.domain.model.entity.Model; + +public interface ModelRepository extends JpaRepository { +} diff --git a/src/main/java/umc/meme/shop/domain/model/service/ModelService.java b/src/main/java/umc/meme/shop/domain/model/service/ModelService.java new file mode 100644 index 0000000..932bf16 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/model/service/ModelService.java @@ -0,0 +1,242 @@ +package umc.meme.shop.domain.model.service; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.*; +import org.springframework.stereotype.Service; +import umc.meme.shop.domain.artist.converter.ArtistConverter; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.artist.repository.ArtistRepository; +import umc.meme.shop.domain.favorite.dto.request.FavoriteArtistDto; +import umc.meme.shop.domain.favorite.dto.request.FavoritePortfolioDto; +import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistPageResponseDto; +import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistResponseDto; +import umc.meme.shop.domain.favorite.dto.response.FavoritePortfolioResponsePageDto; +import umc.meme.shop.domain.favorite.entity.FavoriteArtist; +import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; +import umc.meme.shop.domain.favorite.repository.FavoriteArtistRepository; +import umc.meme.shop.domain.favorite.repository.FavoritePortfolioRepository; +import umc.meme.shop.domain.model.dto.request.ModelProfileDto; +import umc.meme.shop.domain.model.entity.Model; +import umc.meme.shop.domain.model.repository.ModelRepository; +import umc.meme.shop.domain.portfolio.converter.PortfolioConverter; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioPageDto; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.portfolio.entity.enums.Category; +import umc.meme.shop.domain.portfolio.repository.PortfolioRepository; +import umc.meme.shop.global.ErrorStatus; +import umc.meme.shop.global.exception.GlobalException; + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class ModelService { + private final ModelRepository modelRepository; + private final ArtistRepository artistRepository; + private final FavoriteArtistRepository favoriteArtistRepository; + private final FavoritePortfolioRepository favoritePortfolioRepository; + private final PortfolioRepository portfolioRepository; + + /**temp model create method**/ + @Transactional + public void createModel(ModelProfileDto dto){ + Model model = Model.builder() + .profileImg(dto.getProfileImg()) + .nickname(dto.getNickname()) + .introduction("") + .email("") + .name("") + .gender(dto.getGender()) + .skinType(dto.getSkinType()) + .personalColor(dto.getPersonalColor()) + .build(); + modelRepository.save(model); + } + + //모델 프로필 관리 + @Transactional + public void updateModelProfile(ModelProfileDto request){ + Model model = modelRepository.findById(request.getModelId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + + model.updateModel(request); + } + + + //관심 아티스트 조회 + @Transactional + public FavoriteArtistPageResponseDto getFavoriteArtist(Long modelId, int page){ + Model model = modelRepository.findById(modelId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + + //paging + List favoriteArtistList = model.getFavoriteArtistList(); + Pageable pageable = PageRequest.of(page, 30); + int start = (int) pageable.getOffset(); + int end = Math.min((start + pageable.getPageSize()), favoriteArtistList.size()); + + Page favoriteArtistPage = new PageImpl<>(favoriteArtistList.subList(start, end), + pageable, favoriteArtistList.size()); + + List content = new ArrayList<>(); + for(int i=0; i new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + FavoriteArtistResponseDto dto = FavoriteArtistResponseDto.from(artist); + content.add(dto); + } + + return ArtistConverter.favoriteArtistPageConverter(favoriteArtistPage, content); + } + + //관심 메이크업 조회 + @Transactional + public FavoritePortfolioResponsePageDto getFavoritePortfolio(Long modelId, int page){ + Model model = modelRepository.findById(modelId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + + //page + List favoritePortfolioList = model.getFavoritePortfolioList(); + Pageable pageable = PageRequest.of(page, 30); + int start = (int) pageable.getOffset(); + int end = Math.min((start + pageable.getPageSize()), favoritePortfolioList.size()); + + //list를 page로 변환 + Page favoritePortfolioPage = new PageImpl<>(favoritePortfolioList.subList(start, end), + pageable, favoritePortfolioList.size()); + + return PortfolioConverter.favoritePortfolioPageConverter(favoritePortfolioPage); + } + + //관심 아티스트 추가 + @Transactional + public void addFavoriteArtist(FavoriteArtistDto favoriteArtistDto) { + Model model = modelRepository.findById(favoriteArtistDto.getModelId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + + Artist artist = artistRepository.findById(favoriteArtistDto.getArtistId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + + //이미 관심 아티스트가 존재하는 경우 + if (favoriteArtistRepository.existsByModelAndArtistId(model, artist.getUserId())) { + throw new GlobalException(ErrorStatus.ALREADY_EXIST_FAVORITE_ARTIST); + } + + FavoriteArtist favoriteArtist = FavoriteArtist.builder() + .artistId(artist.getUserId()) + .model(model) + .build(); + model.updateFavoriteArtistList(favoriteArtist); + favoriteArtistRepository.save(favoriteArtist); + } + + //관심 메이크업 추가 + @Transactional + public void addFavoritePortfolio(FavoritePortfolioDto favoritePortfolioDto) { + Model model = modelRepository.findById(favoritePortfolioDto.getModelId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + + Portfolio portfolio = portfolioRepository.findById(favoritePortfolioDto.getPortfolioId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); + + //이미 관심 포트폴리오가 존재하는 경우 + if (favoritePortfolioRepository.existsByModelAndPortfolio(model,portfolio)) { + throw new GlobalException(ErrorStatus.ALREADY_EXIST_FAVORITE_PORTFOLIO); + } + + FavoritePortfolio favoritePortfolio = FavoritePortfolio.builder() + .model(model) + .portfolio(portfolio) + .build(); + model.updateFavoritePortfolioList(favoritePortfolio); + favoritePortfolioRepository.save(favoritePortfolio); + } + + //관심 아티스트 삭제 + @Transactional + public void deleteFavoriteArtist(FavoriteArtistDto favoriteArtistDto){ + Model model = modelRepository.findById(favoriteArtistDto.getModelId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + + Artist artist = artistRepository.findById(favoriteArtistDto.getArtistId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + + FavoriteArtist favoriteArtist = favoriteArtistRepository.findByModelAndArtistId(model, artist.getUserId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_FAVORITE_ARTIST)); + favoriteArtistRepository.delete(favoriteArtist); + } + + //관심 메이크업 삭제 + @Transactional + public void deleteFavoritePortfolio(FavoritePortfolioDto favoritePortfolioDto) { + Model model = modelRepository.findById(favoritePortfolioDto.getModelId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + + Portfolio portfolio = portfolioRepository.findById(favoritePortfolioDto.getPortfolioId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); + + FavoritePortfolio favoritePortfolio = favoritePortfolioRepository.findByModelAndPortfolio(model, portfolio) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_FAVORITE_PORTFOLIO)); + favoritePortfolioRepository.delete(favoritePortfolio); + } + + + /**search**/ + //검색 + public PortfolioPageDto search(String query, int page, String sortBy){ + Pageable pageable = setPageRequest(page, sortBy); + + //query 검색 + Page portfolioPage = portfolioRepository.search(query, pageable); + + if(portfolioPage.getContent().isEmpty()) + throw new GlobalException(ErrorStatus.SEARCH_NOT_FOUNT); + + return PortfolioConverter.portfolioPageConverter(portfolioPage); + } + + //카테고리 검색 + public PortfolioPageDto searchCategory(Category category, int page, String sortBy){ + Pageable pageable = setPageRequest(page, sortBy); + Page portfolioPage = portfolioRepository.findByCategory(category, pageable); + return PortfolioConverter.portfolioPageConverter(portfolioPage); + } + + //관심 아티스트 검색 + public PortfolioPageDto searchArtist(Long artistId, int page, String sortBy){ + Artist artist = artistRepository.findById(artistId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + + Pageable pageable = setPageRequest(page, sortBy); + Page portfolioPage = portfolioRepository.findByArtist(artist, pageable); + return PortfolioConverter.portfolioPageConverter(portfolioPage); + } + + //전체 조회 + public PortfolioPageDto searchAll(int page, String sortBy){ + Pageable pageable = setPageRequest(page, sortBy); + Page portfolioPage = portfolioRepository.findAllNotBlocked(pageable); + return PortfolioConverter.portfolioPageConverter(portfolioPage); + } + + + //검색하기 정렬 기준 설정 + private Pageable setPageRequest(int page, String sortBy){ + + Sort sort; + if(sortBy.equals("desc")) + sort = Sort.by("price").descending(); + else if(sortBy.equals("asc")) + sort = Sort.by("price").ascending(); + else if(sortBy.equals("review")) + sort = Sort.by("averageStars").descending(); + else + throw new GlobalException(ErrorStatus.INVALID_SORT_CRITERIA); + + return PageRequest.of(page, 30, sort); + } + +} diff --git a/src/main/java/umc/meme/shop/domain/mypage/controller/MyPageController.java b/src/main/java/umc/meme/shop/domain/mypage/controller/MyPageController.java new file mode 100644 index 0000000..0281580 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/mypage/controller/MyPageController.java @@ -0,0 +1,43 @@ +package umc.meme.shop.domain.mypage.controller; + +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import umc.meme.shop.domain.mypage.dto.request.MypageInquiryDto; +import umc.meme.shop.domain.mypage.service.MypageService; +import umc.meme.shop.domain.portfolio.dto.request.CreatePortfolioDto; +import umc.meme.shop.global.SuccessStatus; +import umc.meme.shop.global.response.ApiResponse; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/mypage") +public class MyPageController { + + private final MypageService mypageService; + + @Operation(summary = "마이페이지 조회") + @GetMapping("/profile/{userId}") + public ApiResponse getProfile(@PathVariable Long userId) { + return ApiResponse.SuccessResponse(SuccessStatus.MYPAGE_GET, mypageService.getProfile(userId)); + } + + @Operation(summary = "약관 및 정책", description = "약관 및 정책을 조회하는 API입니다.") + @GetMapping("/tos") + public ApiResponse tos(){ + return ApiResponse.SuccessResponse(SuccessStatus.TOS_GET, mypageService.getTos()); + } + + @Operation(summary = "문의하기", description = "문의하기 API입니다.") + @PostMapping("/contact") + public ApiResponse contact(@RequestBody MypageInquiryDto mypageInquiryDto){ + mypageService.createInquiry(mypageInquiryDto); + return ApiResponse.SuccessResponse(SuccessStatus.CONTACT_CREATE); + } + + @Operation(summary = "문의 조회하기", description = "문의 조회하기 API입니다.") + @GetMapping("/contact/{userId}") + public ApiResponse getContact(@PathVariable Long userId){ + return ApiResponse.SuccessResponse(SuccessStatus.CONTACT_GET, mypageService.getInquiry(userId)); + } +} diff --git a/src/main/java/umc/meme/shop/domain/mypage/dto/request/MypageInquiryDto.java b/src/main/java/umc/meme/shop/domain/mypage/dto/request/MypageInquiryDto.java new file mode 100644 index 0000000..68708e0 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/mypage/dto/request/MypageInquiryDto.java @@ -0,0 +1,27 @@ +package umc.meme.shop.domain.mypage.dto.request; + + +import lombok.*; +import umc.meme.shop.domain.mypage.entity.Inquiry; +import umc.meme.shop.domain.user.User; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MypageInquiryDto { + private Long userId; + private String inquiryTitle; + private String inquiryText; + + public static MypageInquiryDto from(Inquiry inquiry) { + + User user = inquiry.getUser(); + + return MypageInquiryDto.builder() + .userId(user.getUserId()) + .inquiryTitle(inquiry.getInquiryTitle()) + .inquiryText(inquiry.getInquiryText()) + .build(); + } +} diff --git a/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageDetailDto.java b/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageDetailDto.java new file mode 100644 index 0000000..b2373c7 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageDetailDto.java @@ -0,0 +1,20 @@ +package umc.meme.shop.domain.mypage.dto.response; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.artist.entity.enums.Gender; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Data +public class MypageDetailDto { + private String profileImg; + private String nickname; + private String name; + private Gender gender; + private String email; +} diff --git a/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageInquiryResponseDto.java b/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageInquiryResponseDto.java new file mode 100644 index 0000000..9d24a8f --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageInquiryResponseDto.java @@ -0,0 +1,29 @@ +package umc.meme.shop.domain.mypage.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.mypage.entity.Inquiry; +import umc.meme.shop.domain.user.User; + +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MypageInquiryResponseDto { + private String userEmail; + private String inquiryTitle; + private String inquiryText; + + public static MypageInquiryResponseDto from(Inquiry inquiry) { + + return MypageInquiryResponseDto.builder() + .inquiryText(inquiry.getInquiryText()) + .inquiryTitle(inquiry.getInquiryTitle()) + .userEmail(inquiry.getUser().getEmail()) + .build(); + } +} diff --git a/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageTosDto.java b/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageTosDto.java new file mode 100644 index 0000000..10d45e6 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/mypage/dto/response/MypageTosDto.java @@ -0,0 +1,10 @@ +package umc.meme.shop.domain.mypage.dto.response; + +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +public class MypageTosDto { + private String tos; +} diff --git a/src/main/java/umc/meme/shop/domain/mypage/entity/Inquiry.java b/src/main/java/umc/meme/shop/domain/mypage/entity/Inquiry.java new file mode 100644 index 0000000..9c8402b --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/mypage/entity/Inquiry.java @@ -0,0 +1,33 @@ +package umc.meme.shop.domain.mypage.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.mypage.dto.request.MypageInquiryDto; +import umc.meme.shop.domain.user.User; +import umc.meme.shop.domain.user.UserRepository; + +@Builder +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Inquiry { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "inquiry_id") + private Long inquiryId; + + @Column(nullable = false) + private String inquiryTitle; + + @Column(nullable = false) + private String inquiryText; + + @ManyToOne + @JoinColumn(name="user_id", nullable = false) + private User user; + +} diff --git a/src/main/java/umc/meme/shop/domain/mypage/repository/InquiryRepository.java b/src/main/java/umc/meme/shop/domain/mypage/repository/InquiryRepository.java new file mode 100644 index 0000000..6005b4c --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/mypage/repository/InquiryRepository.java @@ -0,0 +1,7 @@ +package umc.meme.shop.domain.mypage.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.meme.shop.domain.mypage.entity.Inquiry; + +public interface InquiryRepository extends JpaRepository { +} diff --git a/src/main/java/umc/meme/shop/domain/mypage/service/MypageService.java b/src/main/java/umc/meme/shop/domain/mypage/service/MypageService.java new file mode 100644 index 0000000..0c9abe8 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/mypage/service/MypageService.java @@ -0,0 +1,83 @@ +package umc.meme.shop.domain.mypage.service; + +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.artist.repository.ArtistRepository; +import umc.meme.shop.domain.model.entity.Model; +import umc.meme.shop.domain.model.repository.ModelRepository; +import umc.meme.shop.domain.mypage.dto.request.MypageInquiryDto; +import umc.meme.shop.domain.mypage.dto.response.*; +import umc.meme.shop.domain.mypage.entity.Inquiry; +import umc.meme.shop.domain.mypage.repository.InquiryRepository; +import umc.meme.shop.domain.mypage.dto.response.MypageDetailDto; +import umc.meme.shop.domain.mypage.dto.response.MypageTosDto; +import umc.meme.shop.domain.user.User; +import umc.meme.shop.domain.user.UserRepository; +import umc.meme.shop.global.ErrorStatus; +import umc.meme.shop.global.exception.GlobalException; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class MypageService { + + private final ModelRepository modelRepository; + private final ArtistRepository artistRepository; + private final InquiryRepository inquiryRepository; + private final UserRepository userRepository; + @Transactional + public MypageDetailDto getProfile(Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_USER)); + return MypageDetailDto.builder() + .profileImg(user.getProfileImg()) + .nickname(user.getNickname()) + .name(user.getName()) + .gender(user.getGender()) + .email(user.getEmail()) + .build(); + } + + //약관 조회 + @Transactional + public MypageTosDto getTos() { + return MypageTosDto.builder() + .tos("Example") + .build(); + } + + //문의하기 + @Transactional + public void createInquiry(MypageInquiryDto mypageInquiryDto) { + User user = userRepository.findById(mypageInquiryDto.getUserId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_USER)); + + Inquiry inquiry = Inquiry.builder() + .inquiryText(mypageInquiryDto.getInquiryText()) + .inquiryTitle(mypageInquiryDto.getInquiryTitle()) + .user(user) + .build(); + + user.updateInquiryList(inquiry); + inquiryRepository.save(inquiry); + } + + // 문의하기 조회 + @Transactional + public List getInquiry(Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_USER)); + + List inquiryList = user.getInquiryList(); + + return inquiryList.stream() + .map(MypageInquiryResponseDto::from) + .toList(); + } + +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/controller/PortfolioController.java b/src/main/java/umc/meme/shop/domain/portfolio/controller/PortfolioController.java new file mode 100644 index 0000000..2a8aaa7 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/controller/PortfolioController.java @@ -0,0 +1,46 @@ +package umc.meme.shop.domain.portfolio.controller; + +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import umc.meme.shop.domain.portfolio.dto.request.CreatePortfolioDto; +import umc.meme.shop.domain.portfolio.dto.request.UpdatePortfolioDto; +import umc.meme.shop.domain.portfolio.service.PortfolioService; +import umc.meme.shop.global.SuccessStatus; +import umc.meme.shop.global.response.ApiResponse; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/portfolio") +public class PortfolioController { + private final PortfolioService portfolioService; + + @Operation(summary = "포트폴리오 생성", description = "포트폴리오를 생성하는 API입니다.") + @PostMapping("/") + public ApiResponse createPortfolio(@RequestBody CreatePortfolioDto portfolioDto){ + portfolioService.createPortfolio(portfolioDto); + return ApiResponse.SuccessResponse(SuccessStatus.PORTFOLIO_CREATE); + } + + @Operation(summary = "포트폴리오 전체 조회", description = "포트폴리오 전체를 조회하는 API입니다.") + @GetMapping("/{artistId}") + public ApiResponse getPortfolio(@PathVariable Long artistId, + @RequestParam(value = "page", defaultValue = "0", required = false) int page + ){ + return ApiResponse.SuccessResponse(SuccessStatus.PORTFOLIO_GET, portfolioService.getPortfolio(artistId, page)); + } + + @Operation(summary = "포트폴리오 조회", description = "특정 포트폴리오를 조회하는 API입니다.") + @GetMapping("/{portfolioId}/details") + public ApiResponse getPortfolioDetails(@PathVariable Long portfolioId) { + return ApiResponse.SuccessResponse(SuccessStatus.PORTFOLIO_GET, portfolioService.getPortfolioDetails(portfolioId)); + } + + @Operation(summary = "포트폴리오 수정/삭제", description = "포트폴리오를 수정/삭제하는 API입니다.") + @PatchMapping("/") + public ApiResponse updatePortfolio(@RequestBody UpdatePortfolioDto portfolioDto){ + // TODO: PortfolioImg 추가 + portfolioService.updatePortfolio(portfolioDto); + return ApiResponse.SuccessResponse(SuccessStatus.PORTFOLIO_UPDATE); + } +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/converter/PortfolioConverter.java b/src/main/java/umc/meme/shop/domain/portfolio/converter/PortfolioConverter.java new file mode 100644 index 0000000..fcaefb6 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/converter/PortfolioConverter.java @@ -0,0 +1,47 @@ +package umc.meme.shop.domain.portfolio.converter; + +import org.springframework.data.domain.Page; +import umc.meme.shop.domain.favorite.dto.response.FavoriteArtistResponseDto; +import umc.meme.shop.domain.favorite.dto.response.FavoritePortfolioResponseDto; +import umc.meme.shop.domain.favorite.dto.response.FavoritePortfolioResponsePageDto; +import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioPageDto; +import umc.meme.shop.domain.portfolio.entity.Portfolio; + +import java.util.List; + +public class PortfolioConverter { + + public static FavoritePortfolioResponsePageDto favoritePortfolioPageConverter(Page page){ + + List content = page.stream() + .map(FavoritePortfolioResponseDto::from) + .toList(); + + return FavoritePortfolioResponsePageDto.builder() + .content(content) + .pageSize(page.getSize()) + .currentPage(page.getNumber()) + .totalNumber(page.getNumberOfElements()) + .totalPage(page.getTotalPages()) + .build(); + } + + public static PortfolioPageDto portfolioPageConverter(Page page){ + + List content = page.stream() + .map(PortfolioDto::from) + .toList(); + + return PortfolioPageDto.builder() + .content(content) + .pageSize(page.getSize()) + .currentPage(page.getNumber()) + .totalNumber(page.getNumberOfElements()) + .totalPage(page.getTotalPages()) + .build(); + } +} + + diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/request/CreatePortfolioDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/request/CreatePortfolioDto.java new file mode 100644 index 0000000..db068cb --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/dto/request/CreatePortfolioDto.java @@ -0,0 +1,29 @@ +package umc.meme.shop.domain.portfolio.dto.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.portfolio.entity.PortfolioImg; +import umc.meme.shop.domain.portfolio.entity.enums.Category; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CreatePortfolioDto { + @NotBlank(message = "artistId를 입력해주세요.") + private Long artistId; + @NotBlank(message = "카테고리를 입력해주세요") + private Category category; + @NotBlank(message = "메이크업 명을 입력해주세요") + private String makeupName; + @NotBlank(message = "가격을 입력해주세요") + private int price; + @NotBlank(message = "메이크업 정보를 입력해주세요") + private String info; + @NotBlank(message = "포트폴리오 이미지를 업로드해주세요") + private List portfolioImgSrc; +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/request/UpdatePortfolioDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/request/UpdatePortfolioDto.java new file mode 100644 index 0000000..346865a --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/dto/request/UpdatePortfolioDto.java @@ -0,0 +1,25 @@ +package umc.meme.shop.domain.portfolio.dto.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioImgDto; +import umc.meme.shop.domain.portfolio.entity.PortfolioImg; +import umc.meme.shop.domain.portfolio.entity.enums.Category; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UpdatePortfolioDto { + @NotBlank(message = "artistId를 입력해주세요.") + private Long artistId; + @NotBlank(message = "portfolioId를 입력해주세요.") + private Long portfolioId; + private Category category; + private String makeupName; + private int price; + private String info; + private Boolean isBlock; + private PortfolioImgDto portfolioImg; +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioDto.java new file mode 100644 index 0000000..372677a --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioDto.java @@ -0,0 +1,89 @@ +package umc.meme.shop.domain.portfolio.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.artist.entity.enums.MakeupLocation; +import umc.meme.shop.domain.favorite.entity.FavoritePortfolio; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.portfolio.entity.enums.Category; +import umc.meme.shop.domain.review.dto.response.ReviewResponseDto; + +import java.util.List; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PortfolioDto { + private Long portfolioId; + + private Category category; + + private String artistName; + + private String makeupName; + + private int price; + + private String info; + + private MakeupLocation makeupLocation; //샵 재직 여부 + + private String shopLocation; //샵 위치 + + private List region; //활동 가능 지역 + + private Boolean isBlock; + + private String averageStars; + + private int reviewCount; //리뷰 개수 + + private List portfolioImgDtoList; + + + public static PortfolioDto from(Portfolio portfolio) { + Artist artist = portfolio.getArtist(); + + // PortfolioImg 리스트를 PortfolioImgDto 리스트로 변환 + List portfolioImgDtoList = portfolio.getPortfolioImgList() + .stream() + .map(portfolioImg -> new PortfolioImgDto(portfolioImg.getPortfolioImgId(), portfolioImg.getSrc(), false)) + .toList(); + + return PortfolioDto.builder() + .portfolioId(portfolio.getPortfolioId()) + .category(portfolio.getCategory()) + .artistName(artist.getName()) + .makeupName(portfolio.getMakeupName()) + .price(portfolio.getPrice()) + .info(portfolio.getInfo()) + .makeupLocation(artist.getMakeupLocation()) + .shopLocation(artist.getShopLocation()) + .region(artist.getRegion()) + .isBlock(portfolio.isBlock()) + .portfolioImgDtoList(portfolioImgDtoList) + .averageStars(portfolio.getAverageStars()) + .reviewCount(portfolio.getReviewList().size()) + .build(); + } + + //관심 메이크업 + public static PortfolioDto from(FavoritePortfolio favoritePortfolio){ + Portfolio portfolio = favoritePortfolio.getPortfolio(); + return PortfolioDto.builder() + .portfolioId(portfolio.getPortfolioId()) + .category(portfolio.getCategory()) + .makeupName(portfolio.getMakeupName()) + .price(portfolio.getPrice()) + .info(portfolio.getInfo()) + .isBlock(portfolio.isBlock()) + .averageStars(portfolio.getAverageStars()) + .reviewCount(portfolio.getReviewList().size()) + .build(); + } + +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioImgDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioImgDto.java new file mode 100644 index 0000000..fb3e515 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioImgDto.java @@ -0,0 +1,21 @@ +package umc.meme.shop.domain.portfolio.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PortfolioImgDto { + private Long portfolioImgId; + + //이미지 링크 + private String portfolioImgSrc; + + //삭제 여부 + + private boolean isDelete = false; +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioPageDto.java b/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioPageDto.java new file mode 100644 index 0000000..16d6cad --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/dto/response/PortfolioPageDto.java @@ -0,0 +1,20 @@ +package umc.meme.shop.domain.portfolio.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PortfolioPageDto { + private List content; + private int currentPage; //현재 페이지 번호 + private int pageSize; //페이지 크기 + private int totalNumber; //전체 메이크업 개수 + private int totalPage; //전체 페이지 개수 +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/entity/Portfolio.java b/src/main/java/umc/meme/shop/domain/portfolio/entity/Portfolio.java new file mode 100644 index 0000000..b0474d9 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/entity/Portfolio.java @@ -0,0 +1,96 @@ +package umc.meme.shop.domain.portfolio.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.portfolio.dto.request.UpdatePortfolioDto; +import umc.meme.shop.domain.portfolio.entity.enums.Category; +import umc.meme.shop.domain.portfolio.repository.PortfolioImgRepository; +import umc.meme.shop.domain.review.entity.Review; + +import java.util.List; + + +@Builder +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Portfolio { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "portfolio_id") + private Long portfolioId; + + @ManyToOne + @JoinColumn(name="user_id", nullable = false) + private Artist artist; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private Category category; + + @Column(nullable = false) + private String makeupName; + + @Column(nullable = false) + private int price; + + @Column(nullable = false) + private String info; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "portfolio") + private List portfolioImgList; + + @Column + private String averageStars; + + @Column(nullable = false, columnDefinition = "TINYINT(1) default 0") + private boolean isBlock; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "portfolio") + private List reviewList; + + public void updatePortfolio(UpdatePortfolioDto request) { + + if(request.getCategory() != null){ + this.category = request.getCategory(); + } + + if(request.getPrice() >= 0){ + this.price = request.getPrice(); + } + + if(request.getInfo() != null){ + this.info = request.getInfo(); + } + + if(request.getMakeupName() != null){ + this.makeupName = request.getMakeupName(); + } + + this.isBlock = request.getIsBlock(); + } + + public void updateReviewList(Review review){ + this.reviewList.add(review); + } + + public void updateAverageStars(){ + int count = this.reviewList.size(); + if(count == 0) { + this.averageStars = "0.00"; + return; + } + + double stars = 0; + for(Review review : reviewList){ + stars += review.getStar(); + } + this.averageStars = String.format("%.2f", stars/count); + } + +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/entity/PortfolioImg.java b/src/main/java/umc/meme/shop/domain/portfolio/entity/PortfolioImg.java new file mode 100644 index 0000000..ee7c74f --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/entity/PortfolioImg.java @@ -0,0 +1,24 @@ +package umc.meme.shop.domain.portfolio.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class PortfolioImg { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long portfolioImgId; + + @ManyToOne + @JoinColumn(name="portfolio_id", nullable = false) + private Portfolio portfolio; + + @Column(nullable = false) + private String src; +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/entity/enums/Category.java b/src/main/java/umc/meme/shop/domain/portfolio/entity/enums/Category.java new file mode 100644 index 0000000..e6a0c21 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/entity/enums/Category.java @@ -0,0 +1,16 @@ +package umc.meme.shop.domain.portfolio.entity.enums; + +public enum Category { + DAILY("daily"), INTERVIEW("interview"), ACTOR("actor"), PARTY("party"), + WEDDING("wedding"), PROSTHETIC("prosthetic"), STUDIO("studio"), ETC("etc"); + + private String value; + + Category(String value){ + this.value = value; + } + + public String getValue(){ + return this.value; + } +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioImgRepository.java b/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioImgRepository.java new file mode 100644 index 0000000..8c50f50 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioImgRepository.java @@ -0,0 +1,7 @@ +package umc.meme.shop.domain.portfolio.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.meme.shop.domain.portfolio.entity.PortfolioImg; + +public interface PortfolioImgRepository extends JpaRepository { +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioRepository.java b/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioRepository.java new file mode 100644 index 0000000..fae7002 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/repository/PortfolioRepository.java @@ -0,0 +1,35 @@ +package umc.meme.shop.domain.portfolio.repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.portfolio.entity.enums.Category; + +import javax.sound.sampled.Port; +import java.util.List; + +public interface PortfolioRepository extends JpaRepository { + @Query("SELECT p FROM Portfolio p " + + "WHERE p.artist = :artist " + + "AND p.isBlock = false") + Page findByArtist(@Param("artist") Artist artist, Pageable pageable); + + @Query("SELECT p FROM Portfolio p " + + "WHERE p.category = :category " + + "AND p.isBlock = false ") + Page findByCategory(@Param("category") Category category, Pageable pageable); + + @Query("SELECT p FROM Portfolio p " + + "WHERE (p.makeupName LIKE %:query% OR p.info LIKE %:query%) " + + "AND p.isBlock = false" ) + Page search(@Param("query") String query, Pageable pageable); + + @Query("SELECT p FROM Portfolio p WHERE p.isBlock = false") + Page findAllNotBlocked(Pageable pageable); + + boolean existsByMakeupName(String makeupName); +} diff --git a/src/main/java/umc/meme/shop/domain/portfolio/service/PortfolioService.java b/src/main/java/umc/meme/shop/domain/portfolio/service/PortfolioService.java new file mode 100644 index 0000000..5dcded1 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/portfolio/service/PortfolioService.java @@ -0,0 +1,149 @@ +package umc.meme.shop.domain.portfolio.service; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.artist.repository.ArtistRepository; +import umc.meme.shop.domain.portfolio.converter.PortfolioConverter; +import umc.meme.shop.domain.portfolio.dto.request.CreatePortfolioDto; +import umc.meme.shop.domain.portfolio.dto.request.UpdatePortfolioDto; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioDto; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioImgDto; +import umc.meme.shop.domain.portfolio.dto.response.PortfolioPageDto; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.portfolio.entity.PortfolioImg; +import umc.meme.shop.domain.portfolio.repository.PortfolioImgRepository; +import umc.meme.shop.domain.portfolio.repository.PortfolioRepository; +import umc.meme.shop.global.ErrorStatus; +import umc.meme.shop.global.exception.GlobalException; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class PortfolioService { + private final ArtistRepository artistRepository; + private final PortfolioRepository portfolioRepository; + private final PortfolioImgRepository portfolioImgRepository; + + //포트폴리오 생성 + @Transactional + public void createPortfolio(CreatePortfolioDto portfolioDto) { + Artist artist = artistRepository.findById(portfolioDto.getArtistId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + + List portfolioImgList = new ArrayList<>(); + for (String src : portfolioDto.getPortfolioImgSrc()) { + PortfolioImg portfolioImg = new PortfolioImg(); + portfolioImg.setSrc(src); + portfolioImgList.add(portfolioImg); + } + + + //포트폴리오 이름이 이미 존재할 시 + if(portfolioRepository.existsByMakeupName(portfolioDto.getMakeupName())) + throw new GlobalException(ErrorStatus.ALREADY_EXIST_PORTFOLIO); + + Portfolio portfolio = Portfolio.builder() + .artist(artist) + .category(portfolioDto.getCategory()) + .makeupName(portfolioDto.getMakeupName()) + .info(portfolioDto.getInfo()) + .price(portfolioDto.getPrice()) + .portfolioImgList(new ArrayList()) + .averageStars("0.00") + .isBlock(false) + .build(); + + for (PortfolioImg portfolioImg : portfolioImgList) { + portfolioImg.setPortfolio(portfolio); // Portfolio 객체 설정 + portfolio.getPortfolioImgList().add(portfolioImg); // Portfolio의 이미지 리스트에 추가 + } + + artist.updatePortfolioList(portfolio); + portfolioRepository.save(portfolio); + } + + // 포트폴리오 전체 조회 + @Transactional + public PortfolioPageDto getPortfolio(Long artistId, int page) { + Artist artist = artistRepository.findById(artistId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + + List portfolioList = artist.getPortfolioList(); + + //isblock이면 리스트에서 제거 + portfolioList.removeIf(Portfolio::isBlock); + + //page로 mapping + Pageable pageable = PageRequest.of(page, 30); + int start = (int) pageable.getOffset(); + int end = Math.min((start + pageable.getPageSize()), portfolioList.size()); + + //list를 page로 변환 + Page portfolioPage = new PageImpl<>(portfolioList.subList(start, end), + pageable, portfolioList.size()); + + return PortfolioConverter.portfolioPageConverter(portfolioPage); + } + + // 포트폴리오 하나만 조회 + public PortfolioDto getPortfolioDetails(Long portfolioId) { + Portfolio portfolio = portfolioRepository.findById(portfolioId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); + + if(portfolio.isBlock()) + throw new GlobalException(ErrorStatus.BLOCKED_PORTFOLIO); + + return PortfolioDto.from(portfolio); + } + + + // 포트폴리오 수정/삭제 + @Transactional + public void updatePortfolio(UpdatePortfolioDto request) { + Artist artist = artistRepository.findById(request.getArtistId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + + // Portfolio를 getPortfolioDetails 메서드를 이용해 조회 + PortfolioDto portfolioDto = getPortfolioDetails(request.getPortfolioId()); + Portfolio portfolio = portfolioRepository.findById(portfolioDto.getPortfolioId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); + + // 아티스트가 해당 portfolio에 권한이 없을때 (포트폴리오에 있는 artist가 본인이 아닐때) + if (!portfolio.getArtist().equals(artist)) { + throw new GlobalException(ErrorStatus.NOT_AUTHORIZED_PORTFOLIO); + } + + if (request.getPortfolioImg() != null) { + PortfolioImgDto portfolioImgDto = request.getPortfolioImg(); + PortfolioImg portfolioImg = portfolioImgRepository.findById(portfolioImgDto.getPortfolioImgId()) + .orElseThrow(() -> new RuntimeException("포트폴리오 이미지를 찾을 수 없습니다.")); + + if (portfolioImgDto.isDelete()) { + // 이미지 삭제 + portfolio.getPortfolioImgList().remove(portfolioImg); + portfolioImgRepository.delete(portfolioImg); + } else if (portfolioImgDto.getPortfolioImgSrc() != null) { + // 이미지 수정 (src 업데이트) + portfolioImg.setSrc(portfolioImgDto.getPortfolioImgSrc()); + portfolioImgRepository.save(portfolioImg); + + // 업데이트된 이미지 정보를 포트폴리오의 이미지 리스트에 반영 + portfolio.getPortfolioImgList().removeIf(img -> img.getPortfolioImgId().equals(portfolioImg.getPortfolioImgId())); + portfolio.getPortfolioImgList().add(portfolioImg); + } + } + // Portfolio 업데이트 + portfolio.updatePortfolio(request); + } + + +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/controller/ReservationController.java b/src/main/java/umc/meme/shop/domain/reservation/controller/ReservationController.java new file mode 100644 index 0000000..9560585 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/controller/ReservationController.java @@ -0,0 +1,63 @@ +package umc.meme.shop.domain.reservation.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import umc.meme.shop.domain.reservation.dto.request.AlterReservationDto; +import umc.meme.shop.domain.reservation.dto.request.ReservationRequestDto; +import umc.meme.shop.domain.reservation.service.ReservationService; +import umc.meme.shop.global.SuccessStatus; +import umc.meme.shop.global.response.ApiResponse; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/reservation") +public class ReservationController { + private final ReservationService reservationService; + + + @Operation(summary = "예약 상태 변경", description = "예약 상태를 변경하는 API입니다.") + @Parameters({ + @Parameter(name = "status", description = "Status enum 에 있는 값 (EXPECTED, COMPLETE, CANCEL)") + }) + @PatchMapping("/alteration") + public ApiResponse alteration(@RequestBody AlterReservationDto alterReservationDto){ + reservationService.updateReservationStatus(alterReservationDto); + return ApiResponse.SuccessResponse(SuccessStatus.RESERVATION_UPDATE); + } + + @Operation(summary = "예약가능 장소 조회", description = "예약가능 장소 조회 기능을 수행하는 API입니다.") + @GetMapping("/{artistId}/location") + public ApiResponse getArtistLocation(@PathVariable Long artistId){ + return ApiResponse.SuccessResponse(SuccessStatus.ARTIST_LOCATION_GET, reservationService.getArtistLocation(artistId)); + } + + @Operation(summary = "예약가능 시간 조회", description = "예약가능 시간 조회 기능을 수행하는 API입니다.") + @GetMapping("/{artistId}/time") + public ApiResponse getArtistTime(@PathVariable Long artistId){ + return ApiResponse.SuccessResponse(SuccessStatus.ARTIST_TIME_GET, reservationService.getArtistTime(artistId)); + } + + + @Operation(summary = "예약하기", description = "예약하기 기능을 수행하는 API입니다.") + @PostMapping("/") + public ApiResponse createReservation(@RequestBody ReservationRequestDto reservationDto){ + return ApiResponse.SuccessResponse(SuccessStatus.RESERVATION_CREATE, reservationService.createReservation(reservationDto)); + } + + //아티스트 예약 조회 + @Operation(summary = "아티스트 예약 조회", description = "예약 정보를 조회하는 API입니다.") + @GetMapping("/{artistId}/artist") + public ApiResponse getArtistReservation(@PathVariable Long artistId){ + return ApiResponse.SuccessResponse(SuccessStatus.RESERVATION_GET, reservationService.getArtistReservation(artistId)); + } + + //모델 예약 조회 + @Operation(summary = "모델 예약 조회", description = "예약 정보를 조회하는 API입니다.") + @GetMapping("/{modelId}/model") + public ApiResponse getModelReservation(@PathVariable Long modelId){ + return ApiResponse.SuccessResponse(SuccessStatus.RESERVATION_GET, reservationService.getModelReservation(modelId)); + } +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/request/AlterReservationDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/request/AlterReservationDto.java new file mode 100644 index 0000000..195d450 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/dto/request/AlterReservationDto.java @@ -0,0 +1,13 @@ +package umc.meme.shop.domain.reservation.dto.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import umc.meme.shop.domain.reservation.entity.enums.Status; + +@Data +public class AlterReservationDto { + @NotBlank(message = "reservationId를 입력해주세요.") + private Long reservationId; + @NotBlank(message = "status를 입력해주세요.") + private Status status; +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/request/ReservationRequestDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/request/ReservationRequestDto.java new file mode 100644 index 0000000..b34c08e --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/dto/request/ReservationRequestDto.java @@ -0,0 +1,24 @@ +package umc.meme.shop.domain.reservation.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; + +import java.util.Date; +import java.util.Map; + +@Data +public class ReservationRequestDto { + @NotBlank(message = "modelId를 입력해주세요") + private Long modelId; + @NotBlank(message = "portfolioId를 입력해주세요") + private Long portfolioId; + @NotBlank(message = "예약날짜를 입력해주세요") + private Date reservationDate; + @NotNull(message = "예약시간을 입력해주세요") + private Map reservationDayOfWeekAndTime; + @NotNull(message = "예약 장소를 입력해주세요") + private String location; +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistLocationDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistLocationDto.java new file mode 100644 index 0000000..92ca81d --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistLocationDto.java @@ -0,0 +1,20 @@ +package umc.meme.shop.domain.reservation.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.artist.entity.enums.MakeupLocation; +import umc.meme.shop.domain.artist.entity.enums.Region; + +import java.util.List; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ArtistLocationDto { + private MakeupLocation makeupLocation; //샵 재직 여부 + private String shopLocation; //샵 위치 + private List region; //활동 가능 지역 +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistTimeDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistTimeDto.java new file mode 100644 index 0000000..9e93835 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ArtistTimeDto.java @@ -0,0 +1,17 @@ +package umc.meme.shop.domain.reservation.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ArtistTimeDto { + private DayOfWeek availableDayOfWeek; + private Times availableTime; +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationCompleteDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationCompleteDto.java new file mode 100644 index 0000000..032e908 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationCompleteDto.java @@ -0,0 +1,25 @@ +package umc.meme.shop.domain.reservation.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; + +import java.sql.Time; +import java.util.Date; +import java.util.Map; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ReservationCompleteDto { + private String makeupName; + private String artist; + private String location; //장소 + private Date reservationDate; //날짜 + private Map reservationDayOfWeekAndTime; //요일과 시간 + +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationResponseDto.java b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationResponseDto.java new file mode 100644 index 0000000..5be5b86 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/dto/response/ReservationResponseDto.java @@ -0,0 +1,57 @@ +package umc.meme.shop.domain.reservation.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.reservation.entity.Reservation; +import umc.meme.shop.domain.reservation.entity.enums.Status; +import umc.meme.shop.global.ErrorStatus; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; +import umc.meme.shop.global.exception.GlobalException; + +import java.util.Date; +import java.util.Map; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ReservationResponseDto { + private Long reservationId ; + private Long portfolioId; + private String modelName; + private String artistName; + private String makeupName; + private int price; + + private Date reservationDate; + private Map reservationDayOfWeekAndTime; + private String shopLocation; //샵 위치 + private Status status; + + public static ReservationResponseDto from(Reservation reservation){ + Portfolio portfolio = reservation.getPortfolio(); + if(portfolio == null) + throw new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO); + + Artist artist = reservation.getPortfolio().getArtist(); + + return ReservationResponseDto.builder() + .reservationId(reservation.getReservationId()) + .portfolioId(portfolio.getPortfolioId()) + .modelName(reservation.getModel().getName()) + .artistName(artist.getName()) + .makeupName(portfolio.getMakeupName()) + .price(portfolio.getPrice()) + .reservationDayOfWeekAndTime(reservation.getReservationDayOfWeekAndTime()) + .reservationDate(reservation.getReservationDate()) + .shopLocation(artist.getShopLocation()) + .status(reservation.getStatus()) + .build(); + } + +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/entity/Reservation.java b/src/main/java/umc/meme/shop/domain/reservation/entity/Reservation.java new file mode 100644 index 0000000..d80f30f --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/entity/Reservation.java @@ -0,0 +1,64 @@ +package umc.meme.shop.domain.reservation.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.reservation.entity.enums.Status; +import umc.meme.shop.domain.user.User; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; + +import java.util.Date; +import java.util.Map; + +@Builder +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Reservation { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long reservationId; + + @ManyToOne + @JoinColumn(name="user_id", nullable = false) + private User model; + + @ManyToOne + @JoinColumn(name="portfolio_id", nullable = false) + private Portfolio portfolio; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private Status status; + + @Column(nullable = false) + private boolean isReview = false; + + @ElementCollection + @CollectionTable(name = "reservation_time_mapping", + joinColumns = {@JoinColumn(name = "reservation_id", referencedColumnName = "reservationId")}) + @MapKeyColumn(name = "day_of_week") + @Enumerated(EnumType.STRING) + private Map reservationDayOfWeekAndTime; + + @Column(nullable = false) + private Date reservationDate; + + @Column(nullable = false) + private String location; //예약 장소 + + public void updateReservation(Status status){ + if(status != null) + this.status = status; + } + + public void updateIsReview(boolean bool){ + this.isReview = bool; + } +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/entity/enums/Status.java b/src/main/java/umc/meme/shop/domain/reservation/entity/enums/Status.java new file mode 100644 index 0000000..07c9cdf --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/entity/enums/Status.java @@ -0,0 +1,5 @@ +package umc.meme.shop.domain.reservation.entity.enums; + +public enum Status { + EXPECTED, COMPLETE, CANCEL +} diff --git a/src/main/java/umc/meme/shop/domain/reservation/repository/ReservationRepository.java b/src/main/java/umc/meme/shop/domain/reservation/repository/ReservationRepository.java new file mode 100644 index 0000000..6ff22f0 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/repository/ReservationRepository.java @@ -0,0 +1,26 @@ +package umc.meme.shop.domain.reservation.repository; + +import org.springframework.boot.Banner; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.model.entity.Model; +import umc.meme.shop.domain.reservation.entity.Reservation; + +import java.util.List; +import java.util.Optional; + +public interface ReservationRepository extends JpaRepository { + @Query("SELECT r FROM Reservation r WHERE r.portfolio.artist = :artist") + List findByArtist(@Param("artist") Artist artist); + + @Query("SELECT r FROM Reservation r WHERE r.model = :model") + List findByModel(@Param("model") Model model); + + @Query("SELECT r FROM Reservation r JOIN r.model m WHERE r.reservationId = :reservationId AND m.userId = :modelId") + Optional findByReservationIdAndModelId(@Param("reservationId") Long reservationId, @Param("modelId") Long modelId); + +} + + diff --git a/src/main/java/umc/meme/shop/domain/reservation/service/ReservationService.java b/src/main/java/umc/meme/shop/domain/reservation/service/ReservationService.java new file mode 100644 index 0000000..0eefd29 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/reservation/service/ReservationService.java @@ -0,0 +1,152 @@ +package umc.meme.shop.domain.reservation.service; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.artist.repository.ArtistRepository; +import umc.meme.shop.domain.model.entity.Model; +import umc.meme.shop.domain.model.repository.ModelRepository; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.portfolio.repository.PortfolioRepository; +import umc.meme.shop.domain.reservation.dto.request.AlterReservationDto; +import umc.meme.shop.domain.reservation.dto.request.ReservationRequestDto; +import umc.meme.shop.domain.reservation.dto.response.ArtistLocationDto; +import umc.meme.shop.domain.reservation.dto.response.ArtistTimeDto; +import umc.meme.shop.domain.reservation.dto.response.ReservationCompleteDto; +import umc.meme.shop.domain.reservation.dto.response.ReservationResponseDto; +import umc.meme.shop.domain.reservation.entity.Reservation; +import umc.meme.shop.domain.reservation.entity.enums.Status; +import umc.meme.shop.domain.reservation.repository.ReservationRepository; +import umc.meme.shop.global.ErrorStatus; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; +import umc.meme.shop.global.exception.GlobalException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class ReservationService { + private final ArtistRepository artistRepository; + private final ModelRepository modelRepository; + private final PortfolioRepository portfolioRepository; + private final ReservationRepository reservationRepository; + + //아티스트 예약 가능 장소 조회 + public ArtistLocationDto getArtistLocation(Long artistId){ + Artist artist = artistRepository.findById(artistId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + + return ArtistLocationDto.builder() + .makeupLocation(artist.getMakeupLocation()) + .shopLocation(artist.getShopLocation()) + .region(artist.getRegion()) + .build(); + } + + //아티스트 예약 가능 시간 조회 + + public List getArtistTime(Long artistId) { + Artist artist = artistRepository.findById(artistId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + + Map availableDayOfWeekAndTime = artist.getAvailableDayOfWeekAndTime(); + + List artistTimeList = new ArrayList<>(); + + for (Map.Entry entry : availableDayOfWeekAndTime.entrySet()) { + DayOfWeek dayOfWeek = entry.getKey(); + Times availableTime = entry.getValue(); + + ArtistTimeDto artistTimeDto = ArtistTimeDto.builder() + .availableDayOfWeek(dayOfWeek) + .availableTime(availableTime) + .build(); + + artistTimeList.add(artistTimeDto); + } + + return artistTimeList; + } + + //예약하기 + @Transactional + public ReservationCompleteDto createReservation(ReservationRequestDto reservationDto){ + Model model = modelRepository.findById(reservationDto.getModelId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + + Portfolio portfolio = portfolioRepository.findById(reservationDto.getPortfolioId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); + + // 두 개 이상의 예약을 한번에 요청한 경우 + if (reservationDto.getReservationDayOfWeekAndTime().size() != 1) { + throw new GlobalException(ErrorStatus.NOT_ALLOW_OVER_ONE_RESERVATION); + } + + Reservation reservation = Reservation.builder() + .model(model) + .portfolio(portfolio) + .status(Status.EXPECTED) + .reservationDayOfWeekAndTime(reservationDto.getReservationDayOfWeekAndTime()) + .reservationDate(reservationDto.getReservationDate()) + .location(reservationDto.getLocation()) + .build(); + + model.updateReservationList(reservation); + reservationRepository.save(reservation); + + return ReservationCompleteDto.builder() + .makeupName(portfolio.getMakeupName()) + .artist(portfolio.getArtist().getName()) + .location(reservation.getLocation()) + .reservationDate(reservation.getReservationDate()) + .reservationDayOfWeekAndTime(reservation.getReservationDayOfWeekAndTime()) + .build(); + } + + //예약하기 상태 변경 + @Transactional + public void updateReservationStatus(AlterReservationDto reservationDto){ + Reservation reservation = reservationRepository.findById(reservationDto.getReservationId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_RESERVATION)); + Status status = reservationDto.getStatus(); + + if(reservation.getStatus() == status) + throw new GlobalException(ErrorStatus.ALREADY_CHANGE_STATUS); + if(reservation.getStatus() == Status.COMPLETE && status == Status.CANCEL) + throw new GlobalException(ErrorStatus.INVALID_CHANGE_STATUS); + if(reservation.getStatus() == Status.CANCEL && status == Status.COMPLETE) + throw new GlobalException(ErrorStatus.INVALID_CHANGE_COMPLETE); + + reservation.updateReservation(status); + } + + //아티스트 예약 조회 + public List getArtistReservation(Long artistId){ + Artist artist = artistRepository.findById(artistId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST)); + + List reservationList = reservationRepository.findByArtist(artist); + return reservationList.stream() + .map(ReservationResponseDto::from) + .collect(Collectors.toList()); + } + + //모델 예약 조회 + public List getModelReservation(Long modelId) { + Model model = modelRepository.findById(modelId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + + List reservationList = model.getReservationList(); + return reservationList.stream() + .map(ReservationResponseDto::from) + .collect(Collectors.toList()); + } + + +} diff --git a/src/main/java/umc/meme/shop/domain/review/controller/ReviewController.java b/src/main/java/umc/meme/shop/domain/review/controller/ReviewController.java new file mode 100644 index 0000000..3f7228d --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/controller/ReviewController.java @@ -0,0 +1,46 @@ +package umc.meme.shop.domain.review.controller; + +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import umc.meme.shop.domain.review.dto.request.ReviewDto; +import umc.meme.shop.domain.review.dto.request.DeleteReviewDto; +import umc.meme.shop.domain.review.service.ReviewService; +import umc.meme.shop.global.SuccessStatus; +import umc.meme.shop.global.response.ApiResponse; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/review") +public class ReviewController { + private final ReviewService reviewService; + + @Operation(summary = "리뷰 리스트 조회", description = "리뷰 리스트를 조회하는 API입니다.") + @GetMapping("/{portfolioId}") + public ApiResponse getReviewList(@PathVariable Long portfolioId, + @RequestParam(value = "page", defaultValue = "0", required = false) int page + ){ + return ApiResponse.SuccessResponse(SuccessStatus.REVIEW_GET, reviewService.getReviewList(portfolioId, page)); + } + + @Operation(summary = "리뷰 작성", description = "리뷰를 작성하는 API입니다.") + @PostMapping("/") + public ApiResponse createReview(@RequestBody ReviewDto reviewDto){ + //TODO: ReviewImg 추가 + reviewService.createReview(reviewDto); + return ApiResponse.SuccessResponse(SuccessStatus.REVIEW_CREATE); + } + + @Operation(summary = "내가 쓴 리뷰 조회", description = "본인이 쓴 리뷰를 조회하는 API입니다.") + @GetMapping("/me/{modelId}") + public ApiResponse getMyReview(@PathVariable Long modelId){ + return ApiResponse.SuccessResponse(SuccessStatus.REVIEW_GET, reviewService.getMyReview(modelId)); + } + + @Operation(summary = "리뷰 삭제", description = "모델이 작성한 리뷰를 삭제하는 API입니다.") + @DeleteMapping("/") + public ApiResponse updateReview(@RequestBody DeleteReviewDto reviewDto){ + reviewService.deleteReview(reviewDto); + return ApiResponse.SuccessResponse(SuccessStatus.REVIEW_DELETE); + } +} diff --git a/src/main/java/umc/meme/shop/domain/review/converter/ReviewConverter.java b/src/main/java/umc/meme/shop/domain/review/converter/ReviewConverter.java new file mode 100644 index 0000000..a018fb8 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/converter/ReviewConverter.java @@ -0,0 +1,27 @@ +package umc.meme.shop.domain.review.converter; + +import org.springframework.data.domain.Page; +import umc.meme.shop.domain.review.dto.request.ReviewDto; +import umc.meme.shop.domain.review.dto.response.ReviewListPageDto; +import umc.meme.shop.domain.review.dto.response.ReviewResponseDto; +import umc.meme.shop.domain.review.entity.Review; + +import java.util.List; + +public class ReviewConverter { + + public static ReviewListPageDto reviewPageConverter(Page page) { + + List content = page.stream() + .map(ReviewResponseDto::from) + .toList(); + + return ReviewListPageDto.builder() + .content(content) + .pageSize(page.getSize()) + .currentPage(page.getNumber()) + .totalNumber(page.getNumberOfElements()) + .totalPage(page.getTotalPages()) + .build(); + } +} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/request/DeleteReviewDto.java b/src/main/java/umc/meme/shop/domain/review/dto/request/DeleteReviewDto.java new file mode 100644 index 0000000..a5b85dd --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/dto/request/DeleteReviewDto.java @@ -0,0 +1,16 @@ +package umc.meme.shop.domain.review.dto.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DeleteReviewDto { + @NotBlank(message = "modelId를 입력해주세요") + private Long modelId; + @NotBlank(message = "reviewId를 입력해주세요") + private Long reviewId; +} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/request/ReviewDto.java b/src/main/java/umc/meme/shop/domain/review/dto/request/ReviewDto.java new file mode 100644 index 0000000..687932d --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/dto/request/ReviewDto.java @@ -0,0 +1,21 @@ +package umc.meme.shop.domain.review.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jdk.dynalink.linker.LinkerServices; +import lombok.Data; +import umc.meme.shop.domain.review.entity.Review; + +import java.util.List; + +@Data +public class ReviewDto { + @NotBlank(message = "modelId를 입력해주세요") + private Long modelId; + @NotBlank(message = "reservationId를 입력해주세요") + private Long reservationId; + @NotBlank(message = "별점을 입력해주세요") + private int star; + private String comment; + private List reviewImgSrc; + +} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewImgDto.java b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewImgDto.java new file mode 100644 index 0000000..114c4c7 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewImgDto.java @@ -0,0 +1,14 @@ +package umc.meme.shop.domain.review.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ReviewImgDto { + private Long ReviewImgId; + private String reviewImgSrc; + private boolean isDelete = false; +} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListPageDto.java b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListPageDto.java new file mode 100644 index 0000000..f96790c --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListPageDto.java @@ -0,0 +1,22 @@ +package umc.meme.shop.domain.review.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ReviewListPageDto { + private List content; + private Map starStatus; + private int currentPage; //현재 페이지 번호 + private int pageSize; //페이지 크기 + private int totalNumber; //전체 메이크업 개수 + private int totalPage; //전체 페이지 개수 +} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListResponseDto.java b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListResponseDto.java new file mode 100644 index 0000000..e5fd828 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewListResponseDto.java @@ -0,0 +1,27 @@ +package umc.meme.shop.domain.review.dto.response; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.review.entity.Review; + +import java.util.List; +import java.util.Map; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ReviewListResponseDto { + private List reviewResponseDtoList; + private Map starStatus; + + public static ReviewListResponseDto from(List reviewResponseDtoList, Map starStatus) { + return ReviewListResponseDto.builder() + .reviewResponseDtoList(reviewResponseDtoList) + .starStatus(starStatus) + .build(); + } +} diff --git a/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewResponseDto.java b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewResponseDto.java new file mode 100644 index 0000000..3d4337e --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/dto/response/ReviewResponseDto.java @@ -0,0 +1,34 @@ +package umc.meme.shop.domain.review.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.review.entity.Review; + +import java.util.List; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ReviewResponseDto { + private String modelName; + private int star; + private String comment; + private List reviewImgDtoList; + + public static ReviewResponseDto from(Review review){ + List reviewImgDtoList = review.getReviewImgList() + .stream() + .map(reviewImg -> new ReviewImgDto(reviewImg.getReviewImgId(), reviewImg.getSrc(), false)) + .toList(); + + return ReviewResponseDto.builder() + .modelName(review.getModel().getName()) + .star(review.getStar()) + .comment(review.getComment()) + .reviewImgDtoList(reviewImgDtoList) + .build(); + } +} diff --git a/src/main/java/umc/meme/shop/domain/review/entity/Review.java b/src/main/java/umc/meme/shop/domain/review/entity/Review.java new file mode 100644 index 0000000..3bec851 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/entity/Review.java @@ -0,0 +1,39 @@ +package umc.meme.shop.domain.review.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.user.User; + +import java.util.List; + +@Builder +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Review { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long reviewId; + + @ManyToOne + @JoinColumn(name="portfolio_id", nullable = false) + private Portfolio portfolio; + + @ManyToOne + @JoinColumn(name="user_id", nullable = false) + private User model; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "review") + private List reviewImgList; + + @Column(nullable = false) + private int star; + + @Column(nullable = true, length = 200) + private String comment; +} diff --git a/src/main/java/umc/meme/shop/domain/review/entity/ReviewImg.java b/src/main/java/umc/meme/shop/domain/review/entity/ReviewImg.java new file mode 100644 index 0000000..5ba4436 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/entity/ReviewImg.java @@ -0,0 +1,24 @@ +package umc.meme.shop.domain.review.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class ReviewImg { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long reviewImgId; + + @ManyToOne + @JoinColumn(name="review_id", nullable = false) + private Review review; + + @Column(nullable = false) + private String src; +} diff --git a/src/main/java/umc/meme/shop/domain/review/repository/ReviewImgRepository.java b/src/main/java/umc/meme/shop/domain/review/repository/ReviewImgRepository.java new file mode 100644 index 0000000..45e0442 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/repository/ReviewImgRepository.java @@ -0,0 +1,7 @@ +package umc.meme.shop.domain.review.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.meme.shop.domain.review.entity.ReviewImg; + +public interface ReviewImgRepository extends JpaRepository { +} diff --git a/src/main/java/umc/meme/shop/domain/review/repository/ReviewRepository.java b/src/main/java/umc/meme/shop/domain/review/repository/ReviewRepository.java new file mode 100644 index 0000000..e052a85 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/repository/ReviewRepository.java @@ -0,0 +1,11 @@ +package umc.meme.shop.domain.review.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.meme.shop.domain.model.entity.Model; +import umc.meme.shop.domain.review.entity.Review; + +import java.util.List; + +public interface ReviewRepository extends JpaRepository { + List findByModel(Model model); +} diff --git a/src/main/java/umc/meme/shop/domain/review/service/ReviewService.java b/src/main/java/umc/meme/shop/domain/review/service/ReviewService.java new file mode 100644 index 0000000..49dc478 --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/review/service/ReviewService.java @@ -0,0 +1,146 @@ +package umc.meme.shop.domain.review.service; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import umc.meme.shop.domain.model.entity.Model; +import umc.meme.shop.domain.model.repository.ModelRepository; +import umc.meme.shop.domain.portfolio.entity.Portfolio; +import umc.meme.shop.domain.portfolio.repository.PortfolioRepository; +import umc.meme.shop.domain.reservation.entity.Reservation; +import umc.meme.shop.domain.reservation.entity.enums.Status; +import umc.meme.shop.domain.reservation.repository.ReservationRepository; +import umc.meme.shop.domain.review.converter.ReviewConverter; +import umc.meme.shop.domain.review.dto.request.DeleteReviewDto; +import umc.meme.shop.domain.review.dto.request.ReviewDto; +import umc.meme.shop.domain.review.dto.response.ReviewImgDto; +import umc.meme.shop.domain.review.dto.response.ReviewListPageDto; +import umc.meme.shop.domain.review.dto.response.ReviewListResponseDto; +import umc.meme.shop.domain.review.dto.response.ReviewResponseDto; +import umc.meme.shop.domain.review.entity.Review; +import umc.meme.shop.domain.review.entity.ReviewImg; +import umc.meme.shop.domain.review.repository.ReviewImgRepository; +import umc.meme.shop.domain.review.repository.ReviewRepository; +import umc.meme.shop.global.ErrorStatus; +import umc.meme.shop.global.exception.GlobalException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class ReviewService { + private final ModelRepository modelRepository; + private final ReviewRepository reviewRepository; + private final ReservationRepository reservationRepository; + private final PortfolioRepository portfolioRepository; + private final ReviewImgRepository reviewImgRepository; + + //리뷰 작성 + @Transactional + public void createReview(ReviewDto reviewDto){ + Model model = modelRepository.findById(reviewDto.getModelId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + Reservation reservation = reservationRepository.findByReservationIdAndModelId(reviewDto.getReservationId(), reviewDto.getModelId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_RESERVATION)); + + //이미 리뷰 작성 완료 + if(reservation.isReview()) + throw new GlobalException(ErrorStatus.ALREADY_REVIEWED); + + //예약 미완료 + if(reservation.getStatus() != Status.COMPLETE) + throw new GlobalException(ErrorStatus.INVALID_REVIEW_REQUEST); + + Portfolio portfolio = reservation.getPortfolio(); + + List reviewImgList = new ArrayList<>(); + for (String src : reviewDto.getReviewImgSrc()) { + ReviewImg reviewImg = new ReviewImg(); + reviewImg.setSrc(src); + reviewImgList.add(reviewImg); + } + + Review review = Review.builder() + .model(model) + .portfolio(portfolio) + .star(reviewDto.getStar()) + .comment(reviewDto.getComment()) + .reviewImgList(new ArrayList()) + .build(); + + for (ReviewImg reviewImg : reviewImgList) { + reviewImg.setReview(review); + review.getReviewImgList().add(reviewImg); + + } + + portfolio.updateReviewList(review); + portfolio.updateAverageStars(); + model.updateReviewList(review); + + reviewRepository.save(review); + reservation.updateIsReview(true); + } + + //내가 쓴 리뷰 조회 + public List getMyReview(Long modelId){ + Model model = modelRepository.findById(modelId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + List reviewList = reviewRepository.findByModel(model); + return reviewList.stream() + .map(ReviewResponseDto::from) + .toList(); + } + + //리뷰 리스트 조회 + public ReviewListPageDto getReviewList(Long portfolioId, int page) { + Portfolio portfolio = portfolioRepository.findById(portfolioId) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_PORTFOLIO)); + + List reviewList = portfolio.getReviewList(); + + // page로 mapping + Pageable pageable = PageRequest.of(page, 30); + int start = (int) pageable.getOffset(); + int end = Math.min((start + pageable.getPageSize()), reviewList.size()); + + // list를 page로 변환 + List pagedReviewList = reviewList.subList(start, end); + Page reviewPage = new PageImpl<>(pagedReviewList, pageable, reviewList.size()); + + // 별점 현황 + Map starStatus = new HashMap<>(Map.of(5, 0, 4, 0, 3, 0, 2, 0, 1, 0)); + for (Review review : pagedReviewList) { + int star = review.getStar(); + starStatus.put(star, starStatus.get(star) + 1); + } + + // ReviewConverter를 사용하여 ReviewListPageDto 생성 + ReviewListPageDto pageDto = ReviewConverter.reviewPageConverter(reviewPage); + + // 별점 현황 추가 + pageDto.setStarStatus(starStatus); + + return pageDto; + } + + //리뷰 삭제 + @Transactional + public void deleteReview(DeleteReviewDto reviewDto){ + Model model = modelRepository.findById(reviewDto.getModelId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_MODEL)); + Review review = reviewRepository.findById(reviewDto.getReviewId()) + .orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_REVIEW)); + if(!review.getModel().equals(model)) + throw new GlobalException(ErrorStatus.INVALID_MODEL_FOR_REVIEW); + + reviewRepository.delete(review); + } +} diff --git a/src/main/java/umc/meme/shop/domain/user/User.java b/src/main/java/umc/meme/shop/domain/user/User.java new file mode 100644 index 0000000..3e7be8f --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/user/User.java @@ -0,0 +1,48 @@ +package umc.meme.shop.domain.user; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import umc.meme.shop.domain.artist.entity.enums.Gender; +import umc.meme.shop.domain.mypage.entity.Inquiry; + +import java.util.List; + +@SuperBuilder +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Inheritance(strategy = InheritanceType.JOINED) +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_id") + protected Long userId; + + @Column(nullable = false) + protected String profileImg; + + @Column(nullable = false, length = 40) + protected String nickname; + + @Column(nullable = false, length = 20) + protected String name; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + protected Gender gender; + + @Column(nullable = false, length = 40) + protected String email; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "user") + protected List inquiryList; + + public void updateInquiryList(Inquiry inquiry) { + this.inquiryList.add(inquiry); + } +} diff --git a/src/main/java/umc/meme/shop/domain/user/UserRepository.java b/src/main/java/umc/meme/shop/domain/user/UserRepository.java new file mode 100644 index 0000000..cc8c7ba --- /dev/null +++ b/src/main/java/umc/meme/shop/domain/user/UserRepository.java @@ -0,0 +1,7 @@ +package umc.meme.shop.domain.user; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.meme.shop.domain.artist.entity.Artist; + +public interface UserRepository extends JpaRepository { +} diff --git a/src/main/java/umc/meme/shop/global/ErrorStatus.java b/src/main/java/umc/meme/shop/global/ErrorStatus.java new file mode 100644 index 0000000..34f0019 --- /dev/null +++ b/src/main/java/umc/meme/shop/global/ErrorStatus.java @@ -0,0 +1,77 @@ +package umc.meme.shop.global; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ErrorStatus { + + /** + * Error Code + * 400 : 잘못된 요청 + * 401 : JWT에 대한 오류 + * 403 : 요청한 정보에 대한 권한 없음. + * 404 : 존재하지 않는 정보에 대한 요청. + */ + + /** + * TEMP + */ + TEMP(400, "TEMP"), + + /** + * Code : 403 + * Not Authorized + */ + + //portfoilo + NOT_AUTHORIZED_PORTFOLIO(403, "아티스트가 해당 포트폴리오에 수정 권한이 없습니다."), + + + /** + * Code : 400 + * Bad Request + */ + INVALID_REQUEST(400, "유효하지 않은 요청입니다."), + ALREADY_EXIST_FAVORITE_ARTIST(400, "해당 아티스트는 이미 관심 아티스트로 등록되어있습니다."), + ALREADY_EXIST_FAVORITE_PORTFOLIO(400, "해당 포트폴리오는 이미 관심 포트폴리오로 등록되어있습니다."), + + //portfolio + ALREADY_EXIST_PORTFOLIO(400, "해당 포트폴리오 제목이 이미 존재합니다"), + INVALID_SORT_CRITERIA(400, "잘못된 정렬 기준입니다"), + BLOCKED_PORTFOLIO(400, "숨김 처리된 포트폴리오입니다"), + + //review + ALREADY_REVIEWED(400, "이미 리뷰 작성이 완료된 예약입니다."), + INVALID_REVIEW_REQUEST(400, "예약이 완료되지 않아 리뷰를 작성할 수 없습니다."), + INVALID_MODEL_FOR_REVIEW(400, "사용자가 작성하지 않은 리뷰입니다."), + + //reservation + ALREADY_CHANGE_STATUS(400, "이미 예약 상태가 변경되었습니다."), + INVALID_CHANGE_STATUS(400, "이미 완료된 예약은 취소할 수 없습니다."), + + NOT_ALLOW_OVER_ONE_RESERVATION(400,"한 번에 하나의 예약만 가능합니다." ), + INVALID_CHANGE_COMPLETE(400,"취소된 예약을 완료 상태로 변경할 수 없습니다." ), + + + /** + * Code : 404 + * Not Found + */ + NOT_EXIST_USER(404, "존재하지 않는 유저입니다."), + NOT_EXIST_MODEL(404, "존재하지 않는 모델입니다."), + NOT_EXIST_ARTIST(404, "존재하지 않는 아티스트입니다."), + NOT_EXIST_PORTFOLIO(404, "존재하지 않는 포트폴리오입니다."), + NOT_EXIST_RESERVATION(404, "존재하지 않는 예약입니다."), + NOT_EXIST_FAVORITE_ARTIST(404, "존재하지 않는 관심 아티스트입니다."), + NOT_EXIST_FAVORITE_PORTFOLIO(404, "존재하지 않는 관심 메이크업입니다."), + NOT_EXIST_REVIEW(404, "존재하지 않는 리뷰입니다."), + NOT_EXIST_INQUIRY(404, "존재하지 않는 문의입니다."), + SEARCH_NOT_FOUNT(404, "검색 결과가 존재하지 않습니다."), + PAGE_NOT_FOUND(404,"페이지를 찾을 수 없습니다"); + + + private final int code; + private final String message; +} diff --git a/src/main/java/umc/meme/shop/global/SuccessStatus.java b/src/main/java/umc/meme/shop/global/SuccessStatus.java new file mode 100644 index 0000000..266dc81 --- /dev/null +++ b/src/main/java/umc/meme/shop/global/SuccessStatus.java @@ -0,0 +1,55 @@ +package umc.meme.shop.global; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum SuccessStatus { + + TEMP(200, "TEMP"), + + /**artist**/ + ARTIST_PROFILE_UPDATE(200, "아티스트 프로필 수정이 완료되었습니다"), + ARTIST_PROFILE_GET(200, "아티스트 프로필 조회가 완료되었습니다"), + + PORTFOLIO_CREATE(200, "포트폴리오 생성이 완료되었습니다"), + PORTFOLIO_GET(200, "포트폴리오 조회가 완료되었습니다"), + PORTFOLIO_UPDATE(200, "포트폴리오 수정이 완료되었습니다"), + + /**model**/ + MODEL_PROFILE_UPDATE(200, "모델 프로필 수정이 완료되었습니다"), + + FAVORITE_ARTIST_GET(200, "관심 아티스트 조회가 완료되었습니다"), + FAVORITE_PORTFOLIO_GET(200, "관심 메이크업 조회가 완료되었습니다"), + FAVORITE_ARTIST_POST(200, "관심 아티스트 추가가 완료되었습니다."), + FAVORITE_PORTFOLIO_POST(200, "관심 메이크업 추가가 완료되었습니다."), + FAVORITE_ARTIST_DELETE(200, "관심 아티스트 삭제가 완료되었습니다."), + FAVORITE_PORTFOLIO_DELETE(200, "관심 메이크업 삭제가 완료되었습니다."), + + + SEARCH_GET(200, "조회가 완료되었습니다"), + + /**review**/ + REVIEW_CREATE(200, "리뷰 작성이 완료되었습니다"), + REVIEW_GET(200, "리뷰 조회가 완료되었습니다"), + REVIEW_DELETE(200, "리뷰 삭제가 완료되었습니다"), + + /**reservation**/ + RESERVATION_CREATE(200, "예약이 완료되었습니다"), + RESERVATION_GET(200, "예약 조회가 완료되었습니다"), + RESERVATION_UPDATE(200, "예약 상태 변경이 완료되었습니다"), + ARTIST_LOCATION_GET(200, "아티스트의 예약 가능 장소 조회가 완료되었습니다"), + ARTIST_TIME_GET(200, "아티스트의 예약 가능 시간 조회가 완료되었습니다."), + + /**mypage**/ + MYPAGE_GET(200, "마이페이지 조회가 완료되었습니다"), + DETAILS_GET(200, "내 정보 조회가 완료되었습니다"), + TOS_GET(200, "약관 및 정책 조회가 완료되었습니다"), + CONTACT_CREATE(200, "문의 작성이 완료되었습니다"), + CONTACT_GET(200, "문의 조회가 완료되었습니다."); + + + private final int code; + private final String message; +} diff --git a/src/main/java/umc/meme/shop/global/config/SwaggerConfig.java b/src/main/java/umc/meme/shop/global/config/SwaggerConfig.java new file mode 100644 index 0000000..630fbc1 --- /dev/null +++ b/src/main/java/umc/meme/shop/global/config/SwaggerConfig.java @@ -0,0 +1,40 @@ +package umc.meme.shop.global.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + // http://localhost:8080/swagger-ui/index.html#/ + @Bean + public OpenAPI MemeAPI() { + Info info = new Info() + .title("MEME_SERVICE API Docs") + .description("MEME_SERVICE API 명세서입니다.") + .version("1.0.0"); + + String jwtSchemeName = "accessToken"; + // API 요청헤더에 인증정보 포함 + SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwtSchemeName); + + // SecuritySchemes 등록 + Components components = new Components() + .addSecuritySchemes(jwtSchemeName, new SecurityScheme() + .name(jwtSchemeName) + .type(SecurityScheme.Type.HTTP) // HTTP 방식 + .scheme("bearer") + .bearerFormat("JWT")); + + return new OpenAPI() + .addServersItem(new Server().url("/")) + .info(info) + .addSecurityItem(securityRequirement) + .components(components); + } +} \ No newline at end of file diff --git a/src/main/java/umc/meme/shop/global/enums/DayOfWeek.java b/src/main/java/umc/meme/shop/global/enums/DayOfWeek.java new file mode 100644 index 0000000..25a3252 --- /dev/null +++ b/src/main/java/umc/meme/shop/global/enums/DayOfWeek.java @@ -0,0 +1,6 @@ +package umc.meme.shop.global.enums; + +public enum DayOfWeek { + MON, TUE, WED, THU, FRI, SAT, SUN + +} diff --git a/src/main/java/umc/meme/shop/global/enums/Times.java b/src/main/java/umc/meme/shop/global/enums/Times.java new file mode 100644 index 0000000..596c449 --- /dev/null +++ b/src/main/java/umc/meme/shop/global/enums/Times.java @@ -0,0 +1,28 @@ +package umc.meme.shop.global.enums; + +public enum Times { + _00_00, _00_30, + _01_00, _01_30, + _02_00, _02_30, + _03_00, _03_30, + _04_00, _04_30, + _05_00, _05_30, + _06_00, _06_30, + _07_00, _07_30, + _08_00, _08_30, + _09_00, _09_30, + _10_00, _10_30, + _11_00, _11_30, + _12_00, _12_30, + _13_00, _13_30, + _14_00, _14_30, + _15_00, _15_30, + _16_00, _16_30, + _17_00, _17_30, + _18_00, _18_30, + _19_00, _19_30, + _20_00, _20_30, + _21_00, _21_30, + _22_00, _22_30, + _23_00, _23_30 +} diff --git a/src/main/java/umc/meme/shop/global/exception/GlobalException.java b/src/main/java/umc/meme/shop/global/exception/GlobalException.java new file mode 100644 index 0000000..46b60f3 --- /dev/null +++ b/src/main/java/umc/meme/shop/global/exception/GlobalException.java @@ -0,0 +1,11 @@ +package umc.meme.shop.global.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import umc.meme.shop.global.ErrorStatus; + +@Getter +@AllArgsConstructor +public class GlobalException extends RuntimeException { + private final ErrorStatus errorStatus; +} diff --git a/src/main/java/umc/meme/shop/global/exception/GlobalExceptionAdvice.java b/src/main/java/umc/meme/shop/global/exception/GlobalExceptionAdvice.java new file mode 100644 index 0000000..2c41381 --- /dev/null +++ b/src/main/java/umc/meme/shop/global/exception/GlobalExceptionAdvice.java @@ -0,0 +1,18 @@ +package umc.meme.shop.global.exception; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +import umc.meme.shop.global.response.ApiResponse; + +@Slf4j +@RestControllerAdvice(annotations = {RestController.class}) +public class GlobalExceptionAdvice extends ResponseEntityExceptionHandler { + + @ExceptionHandler(value = { GlobalException.class }) + protected ApiResponse handleException(GlobalException e) { + return ApiResponse.FailureResponse(e.getErrorStatus()); + } +} diff --git a/src/main/java/umc/meme/shop/global/exception/GlobalExceptionHandler.java b/src/main/java/umc/meme/shop/global/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..5def7f5 --- /dev/null +++ b/src/main/java/umc/meme/shop/global/exception/GlobalExceptionHandler.java @@ -0,0 +1,9 @@ +package umc.meme.shop.global.exception; + +import umc.meme.shop.global.ErrorStatus; + +public class GlobalExceptionHandler extends GlobalException{ + public GlobalExceptionHandler(ErrorStatus errorStatus) { + super(errorStatus); + } +} diff --git a/src/main/java/umc/meme/shop/global/response/ApiResponse.java b/src/main/java/umc/meme/shop/global/response/ApiResponse.java new file mode 100644 index 0000000..cef2163 --- /dev/null +++ b/src/main/java/umc/meme/shop/global/response/ApiResponse.java @@ -0,0 +1,35 @@ +package umc.meme.shop.global.response; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.AllArgsConstructor; +import lombok.Getter; +import umc.meme.shop.global.ErrorStatus; +import umc.meme.shop.global.SuccessStatus; + +@Getter +@AllArgsConstructor +@JsonPropertyOrder({"code", "result", "message", "data"}) +public class ApiResponse { + + private final int statusCode; + private final String result; + private final String message; + @JsonInclude(JsonInclude.Include.NON_NULL) + private final T data; + + public static ApiResponse SuccessResponse(SuccessStatus status, T data){ + return new ApiResponse<>(status.getCode(), "SUCCESS", status.getMessage(), data); + } + public static ApiResponse SuccessResponse(SuccessStatus status){ + return new ApiResponse<>(status.getCode(), "SUCCESS", status.getMessage(), ""); + } + + public static ApiResponse FailureResponse(int statusCode, String message){ + return new ApiResponse<>(statusCode, "FAILURE", message, ""); + } + + public static ApiResponse FailureResponse(ErrorStatus errorStatus){ + return new ApiResponse<>(errorStatus.getCode(), "FAILURE", errorStatus.getMessage(), ""); + } +} diff --git a/src/test/java/umc/meme/shop/ArtistTest.java b/src/test/java/umc/meme/shop/ArtistTest.java new file mode 100644 index 0000000..9f22d0f --- /dev/null +++ b/src/test/java/umc/meme/shop/ArtistTest.java @@ -0,0 +1,74 @@ +package umc.meme.shop; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import umc.meme.shop.domain.artist.entity.Artist; +import umc.meme.shop.domain.artist.entity.enums.*; +import umc.meme.shop.domain.artist.repository.ArtistRepository; +import umc.meme.shop.domain.portfolio.entity.enums.Category; +import umc.meme.shop.global.enums.DayOfWeek; +import umc.meme.shop.global.enums.Times; + +import java.util.List; + +@SpringBootTest +public class ArtistTest { + + private ArtistRepository artistRepository; + + @Test + void createArtist(){ + + List categories = List.of(new String[]{Category.DAILY.getValue(), Category.PARTY.getValue()}); + List regions = List.of(new String[]{Region.DONGJAK.getValue(), Region.GANGNAM.getValue()}); + Artist artist1 = Artist.builder() + .availableDayOfWeekAndTime(null) + .gender(Gender.FEMALE) + .specialization(categories) + .email("") + .name("testName") + .nickname("testNickName") + .makeupLocation(MakeupLocation.SHOP) + .region(regions) + .introduction("Artist1") + .profileImg("") + .workExperience(WorkExperience.EIGHT) + .build(); + artistRepository.save(artist1); + + List categories2 = List.of(new Category[]{Category.STUDIO, Category.ACTOR}); + List regions2 = List.of(new Region[]{Region.GURO, Region.GANGNAM}); + Artist artist2 = Artist.builder() + .availableDayOfWeekAndTime(null) + .gender(Gender.FEMALE) + .profileImg("") + .specialization(categories) + .email("") + .name("test2Name") + .nickname("test2NickName") + .makeupLocation(MakeupLocation.SHOP) + .region(regions) + .introduction("Artist2") + .workExperience(WorkExperience.FIVE) + .build(); + artistRepository.save(artist2); + + List categorie3 = List.of(new Category[]{Category.WEDDING, Category.PROSTHETIC}); + List regions3 = List.of(new Region[]{Region.DONGDAEMUN, Region.SONGPA}); + Artist artist3 = Artist.builder() + .profileImg("") + .availableDayOfWeekAndTime(null) + .gender(Gender.FEMALE) + .specialization(categories) + .email("") + .name("test3Name") + .nickname("test3NickName") + .makeupLocation(MakeupLocation.SHOP) + .region(regions) + .introduction("Artist3") + .workExperience(WorkExperience.ONE) + .build(); + artistRepository.save(artist3); + + } +} diff --git a/src/test/java/umc/meme/shop/ShopApplicationTests.java b/src/test/java/umc/meme/shop/ShopApplicationTests.java new file mode 100644 index 0000000..b6f0a77 --- /dev/null +++ b/src/test/java/umc/meme/shop/ShopApplicationTests.java @@ -0,0 +1,13 @@ +package umc.meme.shop; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ShopApplicationTests { + + @Test + void contextLoads() { + } + +}