diff --git a/.github/workflows/ci-develop.yml b/.github/workflows/ci-develop.yml index b11b3193..f6d142dc 100644 --- a/.github/workflows/ci-develop.yml +++ b/.github/workflows/ci-develop.yml @@ -47,7 +47,7 @@ jobs: run: | mkdir -p src/main/resources echo "${{ secrets.APPLICATION_YML_CONTENT }}" > src/main/resources/application.yml - echo "${{ secrets.APPLICATION_COMMERCIAL_YML_CONTENT }}" > src/main/resources/application-commercial.yml + echo "${{ secrets.APPLICATION_PROD_YML_CONTENT }}" > src/main/resources/application-prod.yml echo "${{ secrets.APPLICATION_DEV_YML_CONTENT }}" > src/main/resources/application-dev.yml echo "${{ secrets.APPLICATION_OAUTH_YML_CONTENT }}" > src/main/resources/application-oauth.yml diff --git a/.github/workflows/develop-cicd.yml b/.github/workflows/develop-cicd.yml index afdc7bc2..5fa6f77e 100644 --- a/.github/workflows/develop-cicd.yml +++ b/.github/workflows/develop-cicd.yml @@ -47,7 +47,7 @@ jobs: run: | mkdir -p src/main/resources echo "${{ secrets.APPLICATION_YML_CONTENT }}" > src/main/resources/application.yml - echo "${{ secrets.APPLICATION_COMMERCIAL_YML_CONTENT }}" > src/main/resources/application-commercial.yml + echo "${{ secrets.APPLICATION_PROD_YML_CONTENT }}" > src/main/resources/application-prod.yml echo "${{ secrets.APPLICATION_DEV_YML_CONTENT }}" > src/main/resources/application-dev.yml echo "${{ secrets.APPLICATION_OAUTH_YML_CONTENT }}" > src/main/resources/application-oauth.yml diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/AcademyController.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/AcademyController.java index df18ea72..32728fa4 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/AcademyController.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/AcademyController.java @@ -3,12 +3,16 @@ import jakarta.validation.Valid; import org.guzzing.studayserver.domain.academy.controller.dto.request.AcademiesByLocationRequest; import org.guzzing.studayserver.domain.academy.controller.dto.request.AcademiesByNameRequest; +import org.guzzing.studayserver.domain.academy.controller.dto.request.AcademyFilterRequest; import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademiesByLocationResponses; import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademiesByNameResponses; +import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademyFilterResponses; import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademyGetResponse; import org.guzzing.studayserver.domain.academy.service.AcademyService; import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationResults; import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByNameResults; +import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFilterResults; +import org.guzzing.studayserver.domain.auth.memberId.MemberId; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -31,18 +35,23 @@ public AcademyController(AcademyService academyService) { @GetMapping( path = "/{academyId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity getAcademy(@PathVariable Long academyId) { + public ResponseEntity getAcademy( + @PathVariable Long academyId, + @MemberId Long memberId + ) { return ResponseEntity.status(HttpStatus.OK) - .body(AcademyGetResponse.from(academyService.getAcademy(academyId))); + .body(AcademyGetResponse.from(academyService.getAcademy(academyId, memberId))); } @GetMapping( path = "/complexes", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity findByLocation( - @ModelAttribute @Valid AcademiesByLocationRequest request) { + @ModelAttribute @Valid AcademiesByLocationRequest request, + @MemberId Long memberId + ) { AcademiesByLocationResults academiesByLocation = - academyService.findAcademiesByLocation(AcademiesByLocationRequest.to(request)); + academyService.findAcademiesByLocation(AcademiesByLocationRequest.to(request), memberId); return ResponseEntity.status(HttpStatus.OK) .body(AcademiesByLocationResponses.from(academiesByLocation)); @@ -51,7 +60,9 @@ public ResponseEntity findByLocation( @GetMapping( path = "/search", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity findByName(@ModelAttribute @Valid AcademiesByNameRequest request) { + public ResponseEntity findByName( + @ModelAttribute @Valid AcademiesByNameRequest request + ) { AcademiesByNameResults academiesByNameResults = academyService.findAcademiesByName( AcademiesByNameRequest.to(request)); @@ -59,4 +70,17 @@ public ResponseEntity findByName(@ModelAttribute @Vali .body(AcademiesByNameResponses.from(academiesByNameResults)); } + @GetMapping( + path = "/filter", + produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity filterAcademies( + @ModelAttribute @Valid AcademyFilterRequest request, + @MemberId Long memberId + ) { + AcademyFilterResults academyFilterResults = academyService.filterAcademies( + AcademyFilterRequest.to(request), memberId); + + return ResponseEntity.status(HttpStatus.OK) + .body(AcademyFilterResponses.from(academyFilterResults)); + } } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/request/AcademyFilterRequest.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/request/AcademyFilterRequest.java new file mode 100644 index 00000000..f1e09745 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/request/AcademyFilterRequest.java @@ -0,0 +1,39 @@ +package org.guzzing.studayserver.domain.academy.controller.dto.request; + +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import org.guzzing.studayserver.domain.academy.controller.dto.validation.ValidAreaOfExpertise; +import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterParam; + +import java.util.List; + +public record AcademyFilterRequest( + @NotNull(message = "Latitude cannot be null") + @DecimalMin(value = "-90", message = "Invalid latitude") + Double lat, + + @NotNull(message = "Longitude cannot be null") + @DecimalMin(value = "-180", message = "Invalid longitude") + Double lng, + + + @ValidAreaOfExpertise + List areaOfExpertises, + + @Positive + Long desiredMinAmount, + + @Positive + Long desiredMaxAmount +){ + public static AcademyFilterParam to(AcademyFilterRequest request) { + return new AcademyFilterParam ( + request.lat, + request.lng, + request.areaOfExpertises(), + request.desiredMinAmount, + request.desiredMaxAmount + ); + } +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByLocationResponse.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByLocationResponse.java index ad540e43..6c605f76 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByLocationResponse.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByLocationResponse.java @@ -9,9 +9,10 @@ public record AcademiesByLocationResponse( String contact, String areaOfExpertise, Double latitude, - Double longitude + Double longitude, + String shuttleAvailable, + boolean isLiked ) { - public static AcademiesByLocationResponse from(AcademiesByLocationResult academiesByLocationResult) { return new AcademiesByLocationResponse( academiesByLocationResult.academyId(), @@ -20,7 +21,9 @@ public static AcademiesByLocationResponse from(AcademiesByLocationResult academi academiesByLocationResult.contact(), academiesByLocationResult.areaOfExpertise(), academiesByLocationResult.latitude(), - academiesByLocationResult.longitude() + academiesByLocationResult.longitude(), + academiesByLocationResult.shuttleAvailable(), + academiesByLocationResult.isLiked() ); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByLocationResponses.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByLocationResponses.java index 40b62cef..4ee4cb27 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByLocationResponses.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByLocationResponses.java @@ -1,6 +1,7 @@ package org.guzzing.studayserver.domain.academy.controller.dto.response; import java.util.List; + import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationResults; public record AcademiesByLocationResponses( @@ -15,5 +16,4 @@ public static AcademiesByLocationResponses from(AcademiesByLocationResults acade .toList() ); } - } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByNameResponse.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByNameResponse.java index 044a336f..86415795 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByNameResponse.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByNameResponse.java @@ -9,7 +9,6 @@ public record AcademiesByNameResponse( Double latitude, Double longitude ) { - public static AcademiesByNameResponse from(AcademiesByNameResult academiesByNameResult) { return new AcademiesByNameResponse( academiesByNameResult.academyId(), diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByNameResponses.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByNameResponses.java index 724be7cf..e1a0eda6 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByNameResponses.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademiesByNameResponses.java @@ -3,11 +3,9 @@ import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByNameResults; import org.springframework.data.domain.Slice; - public record AcademiesByNameResponses( Slice academiesByNameResponses ) { - public static AcademiesByNameResponses from(AcademiesByNameResults academiesByNameResults) { return new AcademiesByNameResponses( academiesByNameResults.academiesByNameResults() diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyFilterResponse.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyFilterResponse.java new file mode 100644 index 00000000..25f09d1c --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyFilterResponse.java @@ -0,0 +1,29 @@ +package org.guzzing.studayserver.domain.academy.controller.dto.response; + +import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFilterResult; + +public record AcademyFilterResponse( + Long academyId, + String academyName, + String fullAddress, + String contact, + String areaOfExpertise, + Double latitude, + Double longitude, + String shuttleAvailable, + boolean isLiked +) { + public static AcademyFilterResponse from(AcademyFilterResult academyFilterResult) { + return new AcademyFilterResponse( + academyFilterResult.academyId(), + academyFilterResult.academyName(), + academyFilterResult.fullAddress(), + academyFilterResult.contact(), + academyFilterResult.areaOfExpertise(), + academyFilterResult.latitude(), + academyFilterResult.longitude(), + academyFilterResult.shuttleAvailable(), + academyFilterResult.isLiked() + ); + } +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyFilterResponses.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyFilterResponses.java new file mode 100644 index 00000000..c497c2f9 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyFilterResponses.java @@ -0,0 +1,19 @@ +package org.guzzing.studayserver.domain.academy.controller.dto.response; + +import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFilterResults; + +import java.util.List; + +public record AcademyFilterResponses( + List academyFilterResponses +) { + public static AcademyFilterResponses from(AcademyFilterResults academyFilterResults) { + return new AcademyFilterResponses( + academyFilterResults.academyFilterResults() + .stream() + .map(academyFilterResult -> AcademyFilterResponse.from(academyFilterResult)) + .toList() + ); + } +} + diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyGetResponse.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyGetResponse.java index e4b94836..57142293 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyGetResponse.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyGetResponse.java @@ -11,9 +11,9 @@ public record AcademyGetResponse( String updatedDate, String areaOfExpertise, LessonGetResponses lessonGetResponses, - ReviewPercentGetResponse reviewPercentGetResponse + ReviewPercentGetResponse reviewPercentGetResponse, + boolean isLiked ) { - public static AcademyGetResponse from(AcademyGetResult academyGetResult) { return new AcademyGetResponse( academyGetResult.academyName(), @@ -25,7 +25,8 @@ public static AcademyGetResponse from(AcademyGetResult academyGetResult) { academyGetResult.areaOfExpertise(), LessonGetResponses.from(academyGetResult.lessonGetResults()), - ReviewPercentGetResponse.from(academyGetResult.reviewPercentGetResult()) + ReviewPercentGetResponse.from(academyGetResult.reviewPercentGetResult()), + academyGetResult.isLiked() ); } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/LessonGetResponse.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/LessonGetResponse.java index 1f119df5..c3f76470 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/LessonGetResponse.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/LessonGetResponse.java @@ -9,7 +9,6 @@ public record LessonGetResponse( String duration, Long totalFee ) { - public static LessonGetResponse from(LessonGetResult lesson) { return new LessonGetResponse( lesson.lessonId(), diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/LessonGetResponses.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/LessonGetResponses.java index 48022e74..b7e1c0cc 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/LessonGetResponses.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/LessonGetResponses.java @@ -1,12 +1,12 @@ package org.guzzing.studayserver.domain.academy.controller.dto.response; import java.util.List; + import org.guzzing.studayserver.domain.academy.service.dto.result.LessonGetResults; public record LessonGetResponses( List lessons ) { - public static LessonGetResponses from(LessonGetResults lessonGetResults) { return new LessonGetResponses( lessonGetResults diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/ReviewPercentGetResponse.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/ReviewPercentGetResponse.java index 1aeead0d..bd480610 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/ReviewPercentGetResponse.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/ReviewPercentGetResponse.java @@ -9,7 +9,6 @@ public record ReviewPercentGetResponse( int goodManagementPercent, int lovelyTeachingPercent ) { - public static ReviewPercentGetResponse from(ReviewPercentGetResult response) { return new ReviewPercentGetResponse( response.kindnessPercent(), diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/validation/AreaOfExpertise.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/validation/AreaOfExpertise.java new file mode 100644 index 00000000..0a7db003 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/validation/AreaOfExpertise.java @@ -0,0 +1,24 @@ +package org.guzzing.studayserver.domain.academy.controller.dto.validation; + +public enum AreaOfExpertise { + + FOREIGN_LANGUAGE("국제화"), + DANCE("기예(대)"), + ETC("기타(대)"), + READING_ROOM("독서실"), + ART_AND_MUSIC("예능(대)"), + HUMANITIES_AND_HISTORY("인문사회(대)"), + TUTORING_SCHOOL("입시.검정 및 보습"), + COMPREHENSIVE("종합(대)"); + + private String kind; + + AreaOfExpertise(String kind) { + this.kind = kind; + } + + public String getAreaOfExpertise() { + return kind; + } + +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/validation/ValidAreaOfExpertise.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/validation/ValidAreaOfExpertise.java new file mode 100644 index 00000000..694e40e8 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/validation/ValidAreaOfExpertise.java @@ -0,0 +1,20 @@ +package org.guzzing.studayserver.domain.academy.controller.dto.validation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ValidAreaOfExpertiseValidator.class) +public @interface ValidAreaOfExpertise { + String message() default "유효하지 않은 학원 분야입니다."; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/validation/ValidAreaOfExpertiseValidator.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/validation/ValidAreaOfExpertiseValidator.java new file mode 100644 index 00000000..efee5d6e --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/validation/ValidAreaOfExpertiseValidator.java @@ -0,0 +1,34 @@ +package org.guzzing.studayserver.domain.academy.controller.dto.validation; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +import java.util.Arrays; +import java.util.List; + +public class ValidAreaOfExpertiseValidator implements ConstraintValidator> { + + @Override + public void initialize(ValidAreaOfExpertise constraintAnnotation) { + } + + @Override + public boolean isValid(List value, ConstraintValidatorContext context) { + if (value == null || value.isEmpty()) { + return false; + } + + for (String areaOfExpertise : value) { + if (!isValidAreaOfExpertise(areaOfExpertise)) { + return false; + } + } + + return true; + } + + private boolean isValidAreaOfExpertise(String areaOfExpertise) { + return Arrays.stream(AreaOfExpertise.values()) + .anyMatch(enumValue -> enumValue.getAreaOfExpertise().equals(areaOfExpertise)); + } +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/model/Academy.java b/src/main/java/org/guzzing/studayserver/domain/academy/model/Academy.java index 0e086a2b..c98c3e42 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/model/Academy.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/model/Academy.java @@ -7,7 +7,9 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; + import java.util.Objects; + import lombok.Getter; import org.guzzing.studayserver.domain.academy.model.vo.Address; import org.guzzing.studayserver.domain.academy.model.vo.Location; @@ -68,7 +70,7 @@ public String getAcademyName() { } public String getContact() { - return academyInfo.getContact(); + return academyInfo.getPhoneNumber(); } public String getShuttleAvailability() { @@ -101,4 +103,4 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(id, academyInfo, fullAddress, location, maxEducationFee, point); } -} \ No newline at end of file +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/model/Lesson.java b/src/main/java/org/guzzing/studayserver/domain/academy/model/Lesson.java index 784f267f..82c127ca 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/model/Lesson.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/model/Lesson.java @@ -10,7 +10,9 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; + import java.util.Objects; + import lombok.Getter; import org.springframework.util.Assert; diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java b/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java index 48768834..5d419930 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java @@ -34,6 +34,7 @@ public class ReviewCount { private int goodManagementCount; @Column(nullable = false, name = "lovely_teaching_count") + private int lovelyTeachingCount; @Column(nullable = false, name = "reviewers_count") @@ -56,7 +57,7 @@ protected ReviewCount() { } protected ReviewCount(int kindnessCount, int goodFacilityCount, int cheapFeeCount, int goodManagementCount, - int lovelyTeachingCount, int reviewersCount, Academy academy) { + int lovelyTeachingCount, int reviewersCount, Academy academy) { this.kindnessCount = kindnessCount; this.goodFacilityCount = goodFacilityCount; this.cheapFeeCount = cheapFeeCount; @@ -70,4 +71,4 @@ public static ReviewCount makeDefaultReviewCount(Academy academy) { return new ReviewCount(INIT_VALUE, INIT_VALUE, INIT_VALUE, INIT_VALUE, INIT_VALUE, INIT_VALUE, academy); } -} \ No newline at end of file +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/Address.java b/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/Address.java index 1ae9611d..24965e9a 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/Address.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/Address.java @@ -3,7 +3,9 @@ import io.micrometer.common.util.StringUtils; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; + import java.util.Objects; + import lombok.Getter; import org.springframework.util.Assert; diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/Location.java b/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/Location.java index dbe322ca..0116c36f 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/Location.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/Location.java @@ -2,7 +2,9 @@ import jakarta.persistence.Column; import jakarta.persistence.Embeddable; + import java.util.Objects; + import lombok.Getter; @Getter diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/academyinfo/AcademyInfo.java b/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/academyinfo/AcademyInfo.java index 570c4b7f..b4fb0b9a 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/academyinfo/AcademyInfo.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/academyinfo/AcademyInfo.java @@ -6,7 +6,9 @@ import jakarta.persistence.Embedded; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; + import java.util.Objects; + import lombok.Getter; import org.springframework.util.Assert; @@ -18,7 +20,7 @@ public class AcademyInfo { private String academyName; @Embedded - private PhoneNumber contact; + private PhoneNumber phoneNumber; @Enumerated(value = EnumType.STRING) private ShuttleAvailability shuttle; @@ -26,26 +28,25 @@ public class AcademyInfo { @Column(name = "area_of_expertise", nullable = false) private String areaOfExpertise; - protected AcademyInfo(final String academyName, final String contact, final String shuttle, - final String areaOfExpertise) { + protected AcademyInfo(final String academyName, final String phoneNumber, final String shuttle, final String areaOfExpertise) { Assert.isTrue(StringUtils.isNotBlank(academyName), "학원명이 주어지지 않았습니다."); this.academyName = academyName; - this.contact = new PhoneNumber(contact); + this.phoneNumber = new PhoneNumber(phoneNumber); this.shuttle = ShuttleAvailability.getShuttleAvailability(shuttle); this.areaOfExpertise = areaOfExpertise; } public static AcademyInfo of(final String name, final String contact, final String shuttle, - final String areaOfExpertise) { + final String areaOfExpertise) { return new AcademyInfo(name, contact, shuttle, areaOfExpertise); } protected AcademyInfo() { } - public String getContact() { - return contact.getContact(); + public String getPhoneNumber() { + return phoneNumber.getPhoneNumber(); } public String getShuttle() { @@ -65,13 +66,13 @@ public boolean equals(Object o) { return false; } AcademyInfo that = (AcademyInfo) o; - return Objects.equals(academyName, that.academyName) && Objects.equals(contact, that.contact) - && shuttle == that.shuttle; + + return Objects.equals(academyName, that.academyName) && Objects.equals(phoneNumber, that.phoneNumber) && shuttle == that.shuttle; } @Override public int hashCode() { - return Objects.hash(academyName, contact, shuttle); + return Objects.hash(academyName, phoneNumber, shuttle); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/academyinfo/PhoneNumber.java b/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/academyinfo/PhoneNumber.java index 6c3b7a09..934f533a 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/academyinfo/PhoneNumber.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/model/vo/academyinfo/PhoneNumber.java @@ -3,8 +3,10 @@ import jakarta.persistence.Column; import jakarta.persistence.Embeddable; import jakarta.persistence.Transient; + import java.util.Objects; import java.util.regex.Pattern; + import lombok.Getter; @Getter @@ -14,20 +16,20 @@ public class PhoneNumber { @Transient private final String REGEX = "^\\d{2,3}-\\d{3,4}-\\d{3,4}$"; - @Column(name = "contact", nullable = true) - private String contact; + @Column(name = "phone_number", nullable = true) + private String phoneNumber; - public PhoneNumber(final String contact) { - validate(contact); - this.contact = contact; + public PhoneNumber(final String phoneNumber) { + validate(phoneNumber); + this.phoneNumber = phoneNumber; } protected PhoneNumber() { } - private void validate(final String contact) { - if (!contact.isBlank()) { - if (!Pattern.matches(REGEX, contact)) { + private void validate(final String phoneNumber) { + if (!phoneNumber.isBlank()) { + if (!Pattern.matches(REGEX, phoneNumber)) { throw new IllegalArgumentException("올바른 전화번호 형식이 아닙니다."); } } @@ -42,12 +44,12 @@ public boolean equals(Object o) { return false; } PhoneNumber that = (PhoneNumber) o; - return Objects.equals(REGEX, that.REGEX) && Objects.equals(contact, that.contact); + return Objects.equals(REGEX, that.REGEX) && Objects.equals(phoneNumber, that.phoneNumber); } @Override public int hashCode() { - return Objects.hash(REGEX, contact); + return Objects.hash(REGEX, phoneNumber); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademiesByLocation.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademiesByLocation.java index 4cb1ea88..d68fac58 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademiesByLocation.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademiesByLocation.java @@ -4,10 +4,12 @@ public record AcademiesByLocation( Long academyId, String academyName, String fullAddress, - String contact, + String phoneNumber, String areaOfExpertise, Double latitude, - Double longitude + Double longitude, + String shuttleAvailable, + boolean isLiked ) { } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademiesByName.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademiesByName.java index 7bb6df49..cd056af6 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademiesByName.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademiesByName.java @@ -13,5 +13,3 @@ public interface AcademiesByName { Double getLatitude(); } - - diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademyByFiltering.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademyByFiltering.java new file mode 100644 index 00000000..a4af9556 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademyByFiltering.java @@ -0,0 +1,14 @@ +package org.guzzing.studayserver.domain.academy.repository; + +public record AcademyByFiltering( + Long academyId, + String academyName, + String fullAddress, + String phoneNumber, + String areaOfExpertise, + Double latitude, + Double longitude, + String shuttleAvailable, + boolean isLiked +) { +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademyFee.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademyFee.java new file mode 100644 index 00000000..1b4b37c1 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademyFee.java @@ -0,0 +1,9 @@ +package org.guzzing.studayserver.domain.academy.repository; + +public interface AcademyFee { + + Long getMaxEducationFee(); + + String getAcademyName(); + +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademyFilterCondition.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademyFilterCondition.java new file mode 100644 index 00000000..e10ecfdd --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/AcademyFilterCondition.java @@ -0,0 +1,9 @@ +package org.guzzing.studayserver.domain.academy.repository; + +public record AcademyFilterCondition( + String pointFormat, + String areaOfExpertises, + Long desiredMinAmount, + Long desiredMaxAmount +) { +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyJpaRepository.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyJpaRepository.java index 343f67cc..6541aaea 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyJpaRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyJpaRepository.java @@ -3,6 +3,7 @@ import jakarta.persistence.EntityNotFoundException; import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.academy.repository.AcademiesByName; +import org.guzzing.studayserver.domain.academy.repository.AcademyFee; import org.guzzing.studayserver.global.error.response.ErrorCode; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -10,7 +11,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -public interface AcademyJpaRepository extends JpaRepository { +public interface AcademyJpaRepository extends JpaRepository, AcademyQueryRepository, AcademyRepository { default Academy getById(Long academyId) { return findById(academyId) @@ -26,4 +27,11 @@ default Academy getById(Long academyId) { nativeQuery = true) Slice findAcademiesByName(@Param("academyName") String academyName, Pageable pageable); + + @Query("SELECT a.maxEducationFee, a.academyInfo.academyName FROM Academy AS a WHERE a.id = :academyId") + AcademyFee findAcademyFeeInfo(@Param("academyId") Long academyId); + + @Query("SELECT CASE WHEN EXISTS (SELECT 1 FROM Academy a WHERE a.id = :academyId) THEN true ELSE false END") + boolean existsByAcademyId(@Param("academyId") Long academyId); + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepository.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepository.java index 1db006c4..6d9e383c 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepository.java @@ -1,9 +1,14 @@ package org.guzzing.studayserver.domain.academy.repository.academy; import java.util.List; + import org.guzzing.studayserver.domain.academy.repository.AcademiesByLocation; +import org.guzzing.studayserver.domain.academy.repository.AcademyByFiltering; +import org.guzzing.studayserver.domain.academy.repository.AcademyFilterCondition; public interface AcademyQueryRepository { - List findAcademiesByLocation(String pointFormat); + List findAcademiesByLocation(String pointFormat, Long memberId); + + List filterAcademies(AcademyFilterCondition academyFilterCondition, Long memberId); } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepositoryImpl.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepositoryImpl.java index 006aff8e..5bbfe463 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepositoryImpl.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepositoryImpl.java @@ -2,8 +2,12 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.Query; + import java.util.List; + import org.guzzing.studayserver.domain.academy.repository.AcademiesByLocation; +import org.guzzing.studayserver.domain.academy.repository.AcademyByFiltering; +import org.guzzing.studayserver.domain.academy.repository.AcademyFilterCondition; import org.hibernate.transform.ResultTransformer; import org.hibernate.type.StandardBasicTypes; @@ -15,22 +19,27 @@ public AcademyQueryRepositoryImpl(EntityManager em) { this.em = em; } - public List findAcademiesByLocation(String pointFormat) { + public List findAcademiesByLocation(String pointFormat, Long memberId) { Query query = em.createNativeQuery( - "SELECT a.id AS academyId, a.academy_name AS academyName, a.contact , a.full_address AS fullAddress," + - " a.area_of_expertise AS areaOfExpertise, a.latitude AS latitude , a.longitude AS longitude FROM academies AS a " - + - "WHERE MBRContains(ST_LINESTRINGFROMTEXT(" + pointFormat + ", a.point)=1"); + "SELECT a.id AS academyId, a.academy_name AS academyName, a.phone_number AS phoneNumber, a.full_address AS fullAddress," + + " a.area_of_expertise AS areaOfExpertise, a.latitude AS latitude , a.longitude AS longitude, a.shuttle AS shuttleAvailable," + + " (CASE WHEN l.academy_id IS NOT NULL THEN true ELSE false END) AS isLiked " + + " FROM academies AS a" + + " LEFT JOIN likes AS l" + + " ON a.id = l.academy_id AND l.member_id = " + memberId + + " WHERE MBRContains(ST_LINESTRINGFROMTEXT(" + pointFormat + ", a.point)=1"); List academies = query.unwrap(org.hibernate.query.NativeQuery.class) .addScalar("academyId", StandardBasicTypes.LONG) .addScalar("academyName", StandardBasicTypes.STRING) - .addScalar("contact", StandardBasicTypes.STRING) + .addScalar("phoneNumber", StandardBasicTypes.STRING) .addScalar("fullAddress", StandardBasicTypes.STRING) .addScalar("areaOfExpertise", StandardBasicTypes.STRING) .addScalar("latitude", StandardBasicTypes.DOUBLE) .addScalar("longitude", StandardBasicTypes.DOUBLE) + .addScalar("shuttleAvailable", StandardBasicTypes.STRING) + .addScalar("isLiked", StandardBasicTypes.BOOLEAN) .setResultTransformer( new ResultTransformer() { @Override @@ -42,7 +51,9 @@ public Object transformTuple(Object[] tuple, String[] aliases) { (String) tuple[3], (String) tuple[4], (Double) tuple[5], - (Double) tuple[6] + (Double) tuple[6], + (String) tuple[7], + (boolean) tuple[8] ); } @@ -57,4 +68,59 @@ public List transformList(List collection) { return academies; } + public List filterAcademies(AcademyFilterCondition academyFilterCondition, Long memberId) { + String nativeQuery = "SELECT a.id AS academyId, a.academy_name AS academyName, a.full_address AS fullAddress, " + + "a.phone_number AS phoneNumber, a.area_of_expertise AS areaOfExpertise, a.latitude, a.longitude, a.shuttle AS shuttleAvailable, " + + "(CASE WHEN l.academy_id IS NOT NULL THEN true ELSE false END) AS isLiked " + + "FROM academies AS a " + + "LEFT JOIN likes AS l " + + "ON a.id = l.academy_id AND l.member_id = " + memberId + + " WHERE MBRContains(ST_LINESTRINGFROMTEXT(" + academyFilterCondition.pointFormat() + ", a.point)=1 "; + + if (academyFilterCondition.areaOfExpertises() != null && !academyFilterCondition.areaOfExpertises().isEmpty()) { + nativeQuery += " AND area_of_expertise IN " + academyFilterCondition.areaOfExpertises(); + } + + if (academyFilterCondition.desiredMinAmount() != null && academyFilterCondition.desiredMaxAmount() != null) { + nativeQuery += " AND max_education_fee BETWEEN " + academyFilterCondition.desiredMinAmount() + " AND " + academyFilterCondition.desiredMaxAmount(); + } + + Query query = em.createNativeQuery(nativeQuery); + + return query.unwrap(org.hibernate.query.NativeQuery.class) + .addScalar("academyId", StandardBasicTypes.LONG) + .addScalar("academyName", StandardBasicTypes.STRING) + .addScalar("fullAddress", StandardBasicTypes.STRING) + .addScalar("phoneNumber", StandardBasicTypes.STRING) + .addScalar("areaOfExpertise", StandardBasicTypes.STRING) + .addScalar("latitude", StandardBasicTypes.DOUBLE) + .addScalar("longitude", StandardBasicTypes.DOUBLE) + .addScalar("shuttleAvailable", StandardBasicTypes.STRING) + .addScalar("isLiked", StandardBasicTypes.BOOLEAN) + .setResultTransformer( + new ResultTransformer() { + @Override + public Object transformTuple(Object[] tuple, String[] aliases) { + return new AcademyByFiltering( + (Long) tuple[0], + (String) tuple[1], + (String) tuple[2], + (String) tuple[3], + (String) tuple[4], + (Double) tuple[5], + (Double) tuple[6], + (String) tuple[7], + (boolean) tuple[8] + ); + } + + @Override + public List transformList(List collection) { + return collection; + } + } + ) + .getResultList(); + } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyRepository.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyRepository.java index 52faa995..634cff9b 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyRepository.java @@ -1,15 +1,15 @@ package org.guzzing.studayserver.domain.academy.repository.academy; import java.util.List; + import org.guzzing.studayserver.domain.academy.model.Academy; -import org.guzzing.studayserver.domain.academy.repository.AcademiesByLocation; -import org.guzzing.studayserver.domain.academy.repository.AcademiesByName; +import org.guzzing.studayserver.domain.academy.repository.*; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -@Repository -public interface AcademyRepository extends AcademyJpaRepository, AcademyQueryRepository { +public interface AcademyRepository { Academy getById(Long academyId); @@ -17,6 +17,13 @@ public interface AcademyRepository extends AcademyJpaRepository, AcademyQueryRep Slice findAcademiesByName(String academyName, Pageable pageable); - List findAcademiesByLocation(String pointFormat); + List findAcademiesByLocation(String pointFormat, Long memberId); + + List filterAcademies(AcademyFilterCondition academyFilterCondition, Long memberId); + + AcademyFee findAcademyFeeInfo(Long academyId); + + boolean existsByAcademyId(Long academyId); + void deleteAll(); } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/lesson/LessonJpaRepository.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/lesson/LessonJpaRepository.java index 15c96199..5cecc731 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/lesson/LessonJpaRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/lesson/LessonJpaRepository.java @@ -1,10 +1,11 @@ package org.guzzing.studayserver.domain.academy.repository.lesson; import java.util.List; + import org.guzzing.studayserver.domain.academy.model.Lesson; import org.springframework.data.jpa.repository.JpaRepository; -public interface LessonJpaRepository extends JpaRepository { +public interface LessonJpaRepository extends JpaRepository, LessonRepository { List findAllByAcademyId(Long academyId); diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/lesson/LessonRepository.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/lesson/LessonRepository.java index d6298e9d..99a86b13 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/lesson/LessonRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/lesson/LessonRepository.java @@ -1,12 +1,15 @@ package org.guzzing.studayserver.domain.academy.repository.lesson; import java.util.List; + import org.guzzing.studayserver.domain.academy.model.Lesson; -public interface LessonRepository extends LessonJpaRepository { +public interface LessonRepository { List findAllByAcademyId(Long academyId); Lesson save(Lesson lesson); + void deleteAll(); + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java index c2ee629d..2e5bb4a7 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java @@ -4,7 +4,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -public interface ReviewCountJpaRepository extends JpaRepository { +public interface ReviewCountJpaRepository extends JpaRepository, ReviewCountRepository { @Query("select rc from ReviewCount rc where rc.academy.id =:academyId") ReviewCount getByAcademyId(Long academyId); diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountRepository.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountRepository.java index a1bb40b5..b56e3fe1 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountRepository.java @@ -2,9 +2,11 @@ import org.guzzing.studayserver.domain.academy.model.ReviewCount; -public interface ReviewCountRepository extends ReviewCountJpaRepository { +public interface ReviewCountRepository { ReviewCount getByAcademyId(Long academyId); ReviewCount save(ReviewCount reviewCount); + + void deleteAll(); } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyAccessServiceImpl.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyAccessServiceImpl.java index d11d1ddd..56660f51 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyAccessServiceImpl.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyAccessServiceImpl.java @@ -1,5 +1,6 @@ package org.guzzing.studayserver.domain.academy.service; +import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; import org.guzzing.studayserver.domain.like.service.dto.response.AcademyFeeInfo; import org.springframework.stereotype.Service; @@ -7,14 +8,20 @@ public class AcademyAccessServiceImpl implements AcademyAccessService { + private final AcademyRepository academyRepository; + + public AcademyAccessServiceImpl(AcademyRepository academyRepository) { + this.academyRepository = academyRepository; + } + @Override public AcademyFeeInfo findAcademyFeeInfo(Long academyId) { - return null; + return AcademyFeeInfo.to(academyRepository.findAcademyFeeInfo(academyId)); } @Override public boolean existsAcademy(Long academyId) { - return false; + return academyRepository.existsByAcademyId(academyId); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java index 05480cec..0a2027c6 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java @@ -1,20 +1,18 @@ package org.guzzing.studayserver.domain.academy.service; -import java.util.List; -import org.guzzing.studayserver.domain.academy.model.Academy; -import org.guzzing.studayserver.domain.academy.model.Lesson; -import org.guzzing.studayserver.domain.academy.model.ReviewCount; import org.guzzing.studayserver.domain.academy.model.vo.Location; + import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; import org.guzzing.studayserver.domain.academy.repository.lesson.LessonRepository; import org.guzzing.studayserver.domain.academy.repository.review.ReviewCountRepository; import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByLocationParam; import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByNameParam; -import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationResults; -import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByNameResults; -import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyGetResult; +import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterParam; +import org.guzzing.studayserver.domain.academy.service.dto.result.*; import org.guzzing.studayserver.domain.academy.util.GeometryUtil; +import org.guzzing.studayserver.domain.academy.util.SqlFormatter; import org.guzzing.studayserver.domain.academy.util.model.Direction; +import org.guzzing.studayserver.domain.like.service.LikeAccessService; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,7 +20,8 @@ @Service public class AcademyService { - private static final Double DISTANCE = 5.0; + private static final Double DISTANCE = 2.0; + private static final int PAGE_SIZE = 5; private final AcademyRepository academyRepository; @@ -31,39 +30,39 @@ public class AcademyService { private final ReviewCountRepository reviewCountRepository; + private final LikeAccessService likeAccessService; + public AcademyService(AcademyRepository academyRepository, LessonRepository lessonRepository, - ReviewCountRepository reviewCountRepository) { + ReviewCountRepository reviewCountRepository, LikeAccessService likeAccessService) { this.academyRepository = academyRepository; this.lessonRepository = lessonRepository; this.reviewCountRepository = reviewCountRepository; + this.likeAccessService = likeAccessService; } + //캐시 이용하기(지금 상황에서는 백오피스가 없기 때문에 3달에 한 번 업데이트 되기 때문에 가능) @Transactional(readOnly = true) - public AcademyGetResult getAcademy(Long academyId) { - Academy academy = academyRepository.getById(academyId); - List lessons = lessonRepository.findAllByAcademyId(academyId); - ReviewCount reviewCount = reviewCountRepository.getByAcademyId(academyId); - - return AcademyGetResult.from(academy, lessons, reviewCount); + public AcademyGetResult getAcademy(Long academyId, Long memberId) { + return AcademyGetResult.from( + academyRepository.getById(academyId), + lessonRepository.findAllByAcademyId(academyId), + reviewCountRepository.getByAcademyId(academyId), + isLiked(academyId, memberId)); } @Transactional(readOnly = true) - public AcademiesByLocationResults findAcademiesByLocation(AcademiesByLocationParam param) { - Location northEast = GeometryUtil.calculateLocationWithinRadiusInDirection( + public AcademiesByLocationResults findAcademiesByLocation(AcademiesByLocationParam param, Long memberId) { + Location northEast = calculateLocationWithinRadiusInDirection( param.baseLatitude(), param.baseLongitude(), - Direction.NORTHEAST.getBearing(), - DISTANCE); - Location southWest = GeometryUtil.calculateLocationWithinRadiusInDirection( + Direction.NORTHEAST); + Location southWest = calculateLocationWithinRadiusInDirection( param.baseLatitude(), param.baseLongitude(), - Direction.SOUTHWEST.getBearing(), - DISTANCE); - String diagonal = GeometryUtil.makeDiagonalByLineString(northEast, southWest); + Direction.SOUTHWEST); + String diagonal = SqlFormatter.makeDiagonalByLineString(northEast, southWest); - return AcademiesByLocationResults.to( - academyRepository.findAcademiesByLocation(diagonal) - ); + return AcademiesByLocationResults.to(academyRepository.findAcademiesByLocation(diagonal, memberId)); } @Transactional(readOnly = true) @@ -75,4 +74,41 @@ public AcademiesByNameResults findAcademiesByName(AcademiesByNameParam param) { ); } + @Transactional(readOnly = true) + public AcademyFilterResults filterAcademies(AcademyFilterParam param, Long memberId) { + Location northEast = calculateLocationWithinRadiusInDirection( + param.baseLatitude(), + param.baseLongitude(), + Direction.NORTHEAST); + Location southWest = calculateLocationWithinRadiusInDirection( + param.baseLatitude(), + param.baseLongitude(), + Direction.SOUTHWEST); + String diagonal = SqlFormatter.makeDiagonalByLineString(northEast, southWest); + + return AcademyFilterResults.from( + academyRepository.filterAcademies( + AcademyFilterParam.to( + param, + diagonal), + memberId) + ); + } + + private Location calculateLocationWithinRadiusInDirection( + double latitude, + double longitude, + Direction direction) { + + return GeometryUtil.calculateLocationWithinRadiusInDirection( + latitude, + longitude, + direction.getBearing(), + DISTANCE); + } + + private boolean isLiked(Long academyId, Long memberId) { + return likeAccessService.isLiked(academyId, memberId); + } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademiesByLocationParam.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademiesByLocationParam.java index ccba306a..7b352745 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademiesByLocationParam.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademiesByLocationParam.java @@ -4,9 +4,9 @@ public record AcademiesByLocationParam( Double baseLatitude, Double baseLongitude ) { - public static AcademiesByLocationParam of(Double baseLatitude, - Double baseLongitude) { + Double baseLongitude) { return new AcademiesByLocationParam(baseLatitude, baseLongitude); } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademiesByNameParam.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademiesByNameParam.java index 51168bd1..e9f9e98c 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademiesByNameParam.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademiesByNameParam.java @@ -4,8 +4,9 @@ public record AcademiesByNameParam( String academyName, int pageNumber ) { - - public static AcademiesByNameParam of(String academyName, int pageNumber) { + public static AcademiesByNameParam of(String academyName, + int pageNumber) { return new AcademiesByNameParam(academyName, pageNumber); } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademyFilterParam.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademyFilterParam.java new file mode 100644 index 00000000..8caf085a --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/param/AcademyFilterParam.java @@ -0,0 +1,25 @@ +package org.guzzing.studayserver.domain.academy.service.dto.param; + +import org.guzzing.studayserver.domain.academy.repository.AcademyFilterCondition; +import org.guzzing.studayserver.domain.academy.util.SqlFormatter; + +import java.util.List; + +public record AcademyFilterParam( + Double baseLatitude, + Double baseLongitude, + List areaOfExpertises, + Long desiredMinAmount, + Long desiredMaxAmount +) { + public static AcademyFilterCondition to(AcademyFilterParam param, + String pointFormat) { + return new AcademyFilterCondition( + pointFormat, + SqlFormatter.makeWhereInString(param.areaOfExpertises), + param.desiredMinAmount, + param.desiredMaxAmount + ); + } + +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationResult.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationResult.java index 6d38e23f..b9e1088e 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationResult.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationResult.java @@ -9,18 +9,22 @@ public record AcademiesByLocationResult( String contact, String areaOfExpertise, Double latitude, - Double longitude + Double longitude, + String shuttleAvailable, + boolean isLiked ) { - public static AcademiesByLocationResult from(AcademiesByLocation academiesByLocation) { return new AcademiesByLocationResult( academiesByLocation.academyId(), academiesByLocation.academyName(), academiesByLocation.fullAddress(), - academiesByLocation.contact(), + academiesByLocation.phoneNumber(), academiesByLocation.areaOfExpertise(), academiesByLocation.latitude(), - academiesByLocation.longitude() + academiesByLocation.longitude(), + academiesByLocation.shuttleAvailable(), + academiesByLocation.isLiked() ); } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationResults.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationResults.java index cad8a0b6..f00a05ef 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationResults.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationResults.java @@ -1,16 +1,17 @@ package org.guzzing.studayserver.domain.academy.service.dto.result; import java.util.List; + import org.guzzing.studayserver.domain.academy.repository.AcademiesByLocation; public record AcademiesByLocationResults( List academiesByLocationResults ) { - public static AcademiesByLocationResults to(List academiesByLocations) { return new AcademiesByLocationResults( academiesByLocations.stream() .map(AcademiesByLocationResult::from) .toList()); } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByNameResult.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByNameResult.java index 0aa5dde0..c4531a2b 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByNameResult.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByNameResult.java @@ -9,7 +9,6 @@ public record AcademiesByNameResult( Double latitude, Double longitude ) { - public static AcademiesByNameResult from(AcademiesByName academiesByName) { return new AcademiesByNameResult( academiesByName.getAcademyId(), diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByNameResults.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByNameResults.java index 4a8460a2..2e0bffab 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByNameResults.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByNameResults.java @@ -6,9 +6,9 @@ public record AcademiesByNameResults( Slice academiesByNameResults ) { - public static AcademiesByNameResults to(Slice academiesByNames) { return new AcademiesByNameResults( academiesByNames.map(AcademiesByNameResult::from)); } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFilterResult.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFilterResult.java new file mode 100644 index 00000000..5d3bcd45 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFilterResult.java @@ -0,0 +1,30 @@ +package org.guzzing.studayserver.domain.academy.service.dto.result; + +import org.guzzing.studayserver.domain.academy.repository.AcademyByFiltering; + +public record AcademyFilterResult( + Long academyId, + String academyName, + String fullAddress, + String contact, + String areaOfExpertise, + Double latitude, + Double longitude, + String shuttleAvailable, + boolean isLiked +) { + public static AcademyFilterResult from(AcademyByFiltering academyByFiltering) { + return new AcademyFilterResult( + academyByFiltering.academyId(), + academyByFiltering.academyName(), + academyByFiltering.fullAddress(), + academyByFiltering.phoneNumber(), + academyByFiltering.areaOfExpertise(), + academyByFiltering.latitude(), + academyByFiltering.longitude(), + academyByFiltering.shuttleAvailable(), + academyByFiltering.isLiked() + ); + } + +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFilterResults.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFilterResults.java new file mode 100644 index 00000000..fea96518 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFilterResults.java @@ -0,0 +1,18 @@ +package org.guzzing.studayserver.domain.academy.service.dto.result; + +import org.guzzing.studayserver.domain.academy.repository.AcademyByFiltering; + +import java.util.List; + +public record AcademyFilterResults( + List academyFilterResults +) { + public static AcademyFilterResults from(List academiesByFiltering) { + return new AcademyFilterResults( + academiesByFiltering.stream() + .map(academyByFiltering -> AcademyFilterResult.from(academyByFiltering)) + .toList() + ); + } + +} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyGetResult.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyGetResult.java index 5cb66317..457b9408 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyGetResult.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyGetResult.java @@ -1,6 +1,7 @@ package org.guzzing.studayserver.domain.academy.service.dto.result; import java.util.List; + import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.academy.model.Lesson; import org.guzzing.studayserver.domain.academy.model.ReviewCount; @@ -14,12 +15,14 @@ public record AcademyGetResult( String updatedDate, String areaOfExpertise, LessonGetResults lessonGetResults, - ReviewPercentGetResult reviewPercentGetResult + ReviewPercentGetResult reviewPercentGetResult, + boolean isLiked ) { - - public static AcademyGetResult from(Academy academy, + public static AcademyGetResult from( + Academy academy, List lessons, - ReviewCount reviewCount) { + ReviewCount reviewCount, + boolean isLiked) { return new AcademyGetResult( academy.getAcademyName(), academy.getContact(), @@ -30,9 +33,10 @@ public static AcademyGetResult from(Academy academy, academy.getAreaOfExpertise(), LessonGetResults.from(lessons), - ReviewPercentGetResult.from(reviewCount) - ); + ReviewPercentGetResult.from(reviewCount), + isLiked + ); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/LessonGetResults.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/LessonGetResults.java index 67b4189b..9cf0eb78 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/LessonGetResults.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/LessonGetResults.java @@ -1,12 +1,12 @@ package org.guzzing.studayserver.domain.academy.service.dto.result; import java.util.List; + import org.guzzing.studayserver.domain.academy.model.Lesson; public record LessonGetResults( List lessonGetResults ) { - public static LessonGetResults from(List lessons) { return new LessonGetResults( lessons @@ -14,4 +14,5 @@ public static LessonGetResults from(List lessons) { .map(lesson -> LessonGetResult.from(lesson)) .toList()); } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/ReviewPercentGetResult.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/ReviewPercentGetResult.java index 47aa4078..ae45b8f0 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/ReviewPercentGetResult.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/ReviewPercentGetResult.java @@ -9,7 +9,6 @@ public record ReviewPercentGetResult( int goodManagementPercent, int lovelyTeachingPercent ) { - public static ReviewPercentGetResult from(ReviewCount reviewCount) { return new ReviewPercentGetResult( reviewCount.makePercent(reviewCount.getKindnessCount()), @@ -19,4 +18,5 @@ public static ReviewPercentGetResult from(ReviewCount reviewCount) { reviewCount.makePercent(reviewCount.getLovelyTeachingCount()) ); } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/util/GeometryUtil.java b/src/main/java/org/guzzing/studayserver/domain/academy/util/GeometryUtil.java index fb5d03e8..e82e6515 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/util/GeometryUtil.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/util/GeometryUtil.java @@ -6,13 +6,10 @@ public class GeometryUtil { private static final Double EARTH_RADIUS = 6371.01; - private static final String LINESTRING_SQL = "'LINESTRING(%f %f, %f %f)')"; - ; - public static Location calculateLocationWithinRadiusInDirection(Double baseLatitude, - Double baseLongitude, - Double bearing, - Double distance) { + Double baseLongitude, + Double bearing, + Double distance) { Double radianLatitude = toRadian(baseLatitude); Double radianLongitude = toRadian(baseLongitude); Double radianAngle = toRadian(bearing); @@ -48,12 +45,4 @@ private static Double normalizeLongitude(Double longitude) { return (longitude + 540) % 360 - 180; } - public static String makeDiagonalByLineString(Location northEast, Location southWest) { - return String.format( - LINESTRING_SQL, - northEast.getLongitude(), northEast.getLatitude(), southWest.getLongitude(), southWest.getLatitude() - ); - - } - } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/util/SqlFormatter.java b/src/main/java/org/guzzing/studayserver/domain/academy/util/SqlFormatter.java new file mode 100644 index 00000000..00ab9627 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/academy/util/SqlFormatter.java @@ -0,0 +1,31 @@ +package org.guzzing.studayserver.domain.academy.util; + +import org.guzzing.studayserver.domain.academy.model.vo.Location; + +import java.util.List; + +public class SqlFormatter { + private static final String LINESTRING_SQL = "'LINESTRING(%f %f, %f %f)')"; + + public static String makeWhereInString(List values) { + StringBuilder builder = new StringBuilder("("); + for (int i = 0; i < values.size(); i++) { + builder.append("'"); + builder.append(values.get(i)); + builder.append("'"); + if (i < values.size() - 1) { + builder.append(", "); + } + } + builder.append(")"); + return builder.toString(); + } + + public static String makeDiagonalByLineString(Location northEast, Location southWest) { + return String.format( + LINESTRING_SQL, + northEast.getLongitude(), northEast.getLatitude(), southWest.getLongitude(), southWest.getLatitude() + ); + + } +} diff --git a/src/main/java/org/guzzing/studayserver/domain/auth/jwt/JwtAuthenticationFilter.java b/src/main/java/org/guzzing/studayserver/domain/auth/jwt/JwtAuthenticationFilter.java index e5f9899e..e9e102d0 100644 --- a/src/main/java/org/guzzing/studayserver/domain/auth/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/org/guzzing/studayserver/domain/auth/jwt/JwtAuthenticationFilter.java @@ -24,7 +24,6 @@ protected void doFilterInternal(HttpServletRequest request, final String AUTHORIZATION_HEADER = request.getHeader("Authorization"); - //Authrization Berear if (AUTHORIZATION_HEADER != null && AUTHORIZATION_HEADER.startsWith("Bearer ")) { String tokenStr = JwtHeaderUtil.getAccessToken(request); AuthToken token = tokenProvider.convertAuthToken(tokenStr); @@ -37,7 +36,6 @@ protected void doFilterInternal(HttpServletRequest request, filterChain.doFilter(request, response); return; } - filterChain.doFilter(request, response); } diff --git a/src/main/java/org/guzzing/studayserver/domain/child/model/Child.java b/src/main/java/org/guzzing/studayserver/domain/child/model/Child.java index 3d208ee1..bd0e2bdb 100644 --- a/src/main/java/org/guzzing/studayserver/domain/child/model/Child.java +++ b/src/main/java/org/guzzing/studayserver/domain/child/model/Child.java @@ -26,7 +26,7 @@ public class Child { private Long id; @Embedded - @Column(nullable = false) + @Column(nullable = false,name = "nick_name") private NickName nickName; @Enumerated(EnumType.STRING) diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeAccessService.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeAccessService.java new file mode 100644 index 00000000..a92a728e --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeAccessService.java @@ -0,0 +1,6 @@ +package org.guzzing.studayserver.domain.like.service; + +public interface LikeAccessService { + + boolean isLiked(Long academyId, Long memberId); +} diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeAccessServiceImpl.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeAccessServiceImpl.java new file mode 100644 index 00000000..e78c4efb --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeAccessServiceImpl.java @@ -0,0 +1,11 @@ +package org.guzzing.studayserver.domain.like.service; + +import org.springframework.stereotype.Service; + +@Service +public class LikeAccessServiceImpl implements LikeAccessService { + @Override + public boolean isLiked(Long academyId, Long memberId) { + return false; + } +} diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/AcademyFeeInfo.java b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/AcademyFeeInfo.java index eb1421d5..3e4e6afb 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/AcademyFeeInfo.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/AcademyFeeInfo.java @@ -1,8 +1,17 @@ package org.guzzing.studayserver.domain.like.service.dto.response; +import org.guzzing.studayserver.domain.academy.repository.AcademyFee; + public record AcademyFeeInfo( String academyName, long expectedFee ) { + public static AcademyFeeInfo to(AcademyFee academyFee) { + return new AcademyFeeInfo( + academyFee.getAcademyName(), + academyFee.getMaxEducationFee() + ); + } + } diff --git a/src/main/java/org/guzzing/studayserver/domain/member/model/Member.java b/src/main/java/org/guzzing/studayserver/domain/member/model/Member.java index 4c344c18..3c9516a9 100644 --- a/src/main/java/org/guzzing/studayserver/domain/member/model/Member.java +++ b/src/main/java/org/guzzing/studayserver/domain/member/model/Member.java @@ -24,7 +24,7 @@ import org.guzzing.studayserver.domain.member.model.vo.RoleType; @Getter -@Table(name = "members", uniqueConstraints = @UniqueConstraint(columnNames = {"socialId", "memberProvider"})) +@Table(name = "members", uniqueConstraints = @UniqueConstraint(columnNames = {"social_Id", "member_provider"})) @Entity public class Member { @@ -36,22 +36,22 @@ public class Member { private Long id; @Embedded - @Column + @Column(name = "nick_name") private NickName nickName; @Embedded @Column private Email email; - @Column(nullable = false) + @Column(nullable = false, name = "social_id") private String socialId; @Enumerated(EnumType.STRING) - @Column(nullable = false) + @Column(nullable = false, name = "member_provider") private MemberProvider memberProvider; @Enumerated(EnumType.STRING) - @Column(nullable = false) + @Column(nullable = false, name = "role_type") private RoleType roleType; @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) diff --git a/src/test/java/org/guzzing/studayserver/domain/academy/service/AcademyServiceTest.java b/src/test/java/org/guzzing/studayserver/domain/academy/service/AcademyServiceTest.java index 5fa9273f..c15968bd 100644 --- a/src/test/java/org/guzzing/studayserver/domain/academy/service/AcademyServiceTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/academy/service/AcademyServiceTest.java @@ -1,22 +1,40 @@ package org.guzzing.studayserver.domain.academy.service; +import static org.assertj.core.api.Assertions.assertThat; + import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.academy.model.Lesson; import org.guzzing.studayserver.domain.academy.model.ReviewCount; import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; import org.guzzing.studayserver.domain.academy.repository.lesson.LessonRepository; import org.guzzing.studayserver.domain.academy.repository.review.ReviewCountRepository; +import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByNameParam; +import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterParam; +import org.guzzing.studayserver.domain.academy.service.dto.result.*; +import org.guzzing.studayserver.domain.member.model.Member; +import org.guzzing.studayserver.domain.member.repository.MemberRepository; +import org.guzzing.studayserver.testutil.fixture.academy.AcademyFixture; +import org.guzzing.studayserver.testutil.fixture.member.MemberFixture; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.Random; + @Transactional @ActiveProfiles({"oauth", "dev"}) @SpringBootTest class AcademyServiceTest { private static final String ACADEMY_NAME_FOR_SEARCH = "코딩"; + private double LATITUDE = 37.4449168; + private double LONGITUDE = 127.1388684; @Autowired private AcademyService academyService; @@ -30,92 +48,143 @@ class AcademyServiceTest { @Autowired private ReviewCountRepository reviewCountRepository; + @Autowired + private MemberRepository memberRepository; + + private Member savedMember; + private Academy savedAcademyAboutSungnam; private Lesson savedALessonAboutSungnam; private ReviewCount savedReviewCountAboutSungnam; -// @BeforeEach -// void setUp() { -// Academy academyAboutSungnam = AcademyFixture.academySungnam(); -// academyAboutSungnam.changeEducationFee(100000L); -// savedAcademyAboutSungnam = academyRepository.save(academyAboutSungnam); -// -// Lesson lessonAboutSungnam = AcademyFixture.lessonForSunganm(savedAcademyAboutSungnam); -// savedALessonAboutSungnam = lessonRepository.save(lessonAboutSungnam); -// -// savedReviewCountAboutSungnam = reviewCountRepository.save( -// AcademyFixture.reviewCountDefault(savedAcademyAboutSungnam)); -// } -// -// @Test -// @DisplayName("학원 ID로 학원 정보를 조회할 때 학원 정보, 수업 정보, 리뷰를 확인할 수 있다.") -// void getAcademy_academyId_reviewsAndLessons() { -// //When -// AcademyGetResult academyGetResult = academyService.getAcademy(savedAcademyAboutSungnam.getId()); -// -// //Then -// assertThat(academyGetResult.academyName()).isEqualTo(savedAcademyAboutSungnam.getAcademyName()); -// assertThat(academyGetResult.contact()).isEqualTo(savedAcademyAboutSungnam.getContact()); -// assertThat(academyGetResult.fullAddress()).isEqualTo(savedAcademyAboutSungnam.getFullAddress()); -// assertThat(academyGetResult.shuttleAvailability()).isEqualTo( -// savedAcademyAboutSungnam.getShuttleAvailability().toString()); -// assertThat(academyGetResult.expectedFee()).isEqualTo(savedAcademyAboutSungnam.getMaxEducationFee()); -// assertThat(academyGetResult.updatedDate()).isEqualTo(savedAcademyAboutSungnam.getUpdatedDate().toString()); -// assertThat(academyGetResult.areaOfExpertise()).isEqualTo(savedAcademyAboutSungnam.getAreaOfExpertise()); -// assertThat(academyGetResult.lessonGetResults().lessonGetResults()).contains( -// LessonGetResult.from(savedALessonAboutSungnam)); -// assertThat(academyGetResult.reviewPercentGetResult()).isEqualTo( -// ReviewPercentGetResult.from(savedReviewCountAboutSungnam)); -// } -// -// @Test -// @DisplayName("사용자의 중심 위치가 주어졌을 때 반경 거리 이내의 학원 목록이 조회된다.") -// void findAcademiesByLocation_academiesWithinDistance_equalsSize() { -// //Given -// lessonRepository.deleteAll(); -// reviewCountRepository.deleteAll(); -// academyRepository.deleteAll(); -// -// double latitude = 37.4449168; -// double longitude = 127.1388684; -// -// List academies = AcademyFixture.randomAcademiesWithinDistance(latitude, longitude); -// for (Academy academy : academies) { -// Academy savedAcademy = academyRepository.save(academy); -// lessonRepository.save(AcademyFixture.lessonForSunganm(savedAcademy)); -// reviewCountRepository.save(AcademyFixture.reviewCountDefault(savedAcademy)); -// } -// -// //When -// AcademiesByLocationResults academiesByLocations = academyService.findAcademiesByLocation( -// AcademyFixture.academiesByLocationParam(latitude, longitude)); -// -// //Then -// assertThat(academiesByLocations.academiesByLocationResults().size()).isEqualTo(academies.size()); -// } -// -// @Test -// @DisplayName("학원 이름(ACADEMY_NAME_FOR_SEARCH)으로 검색하면 자동완성 기능으로 관련 학원들을 보여준다.") -// void findAcademiesByName_academyName_relatedAcademies() { -// //Given -// List academies = AcademyFixture.academies(); -// for (Academy academy : academies) { -// Academy savedAcademy = academyRepository.save(academy); -// lessonRepository.save(AcademyFixture.lessonForSunganm(savedAcademy)); -// reviewCountRepository.save(AcademyFixture.reviewCountDefault(savedAcademy)); -// } -// -// //When -// AcademiesByNameResults academiesByNameResults = academyService.findAcademiesByName( -// AcademiesByNameParam.of(ACADEMY_NAME_FOR_SEARCH, 0) -// ); -// -// //Then -// for (AcademiesByNameResult academiesByNameResult : academiesByNameResults.academiesByNameResults()) { -// assertThat(academiesByNameResult.academyName()).contains(ACADEMY_NAME_FOR_SEARCH); -// } -// } + @BeforeEach + void setUp() { + + Member member = MemberFixture.member(); + savedMember = memberRepository.save(member); + + Academy academyAboutSungnam = AcademyFixture.academySungnam(); + academyAboutSungnam.changeEducationFee(100000L); + savedAcademyAboutSungnam = academyRepository.save(academyAboutSungnam); + + Lesson lessonAboutSungnam = AcademyFixture.lessonForSunganm(savedAcademyAboutSungnam); + savedALessonAboutSungnam = lessonRepository.save(lessonAboutSungnam); + + savedReviewCountAboutSungnam = reviewCountRepository.save( + AcademyFixture.reviewCountDefault(savedAcademyAboutSungnam)); + } + + @Test + @DisplayName("학원 ID로 학원 정보를 조회할 때 학원 정보, 수업 정보, 리뷰를 확인할 수 있다.") + void getAcademy_academyId_reviewsAndLessons() { + //When + AcademyGetResult academyGetResult = academyService.getAcademy(savedAcademyAboutSungnam.getId(), savedMember.getId()); + + //Then + assertThat(academyGetResult.academyName()).isEqualTo(savedAcademyAboutSungnam.getAcademyName()); + assertThat(academyGetResult.contact()).isEqualTo(savedAcademyAboutSungnam.getContact()); + assertThat(academyGetResult.fullAddress()).isEqualTo(savedAcademyAboutSungnam.getFullAddress()); + assertThat(academyGetResult.shuttleAvailability()).isEqualTo(savedAcademyAboutSungnam.getShuttleAvailability().toString()); + assertThat(academyGetResult.expectedFee()).isEqualTo(savedAcademyAboutSungnam.getMaxEducationFee()); + assertThat(academyGetResult.updatedDate()).isEqualTo(savedAcademyAboutSungnam.getUpdatedDate().toString()); + assertThat(academyGetResult.areaOfExpertise()).isEqualTo(savedAcademyAboutSungnam.getAreaOfExpertise()); + assertThat(academyGetResult.lessonGetResults().lessonGetResults()).contains( + LessonGetResult.from(savedALessonAboutSungnam)); + assertThat(academyGetResult.reviewPercentGetResult()).isEqualTo( + ReviewPercentGetResult.from(savedReviewCountAboutSungnam)); + } + + @Test + @DisplayName("사용자의 중심 위치가 주어졌을 때 반경 거리 이내의 학원 목록이 조회된다.") + void findAcademiesByLocation_academiesWithinDistance_equalsSize() { + //Given + lessonRepository.deleteAll(); + reviewCountRepository.deleteAll(); + academyRepository.deleteAll(); + + List academies = AcademyFixture.randomAcademiesWithinDistance(LATITUDE, LONGITUDE); + for (Academy academy : academies) { + Academy savedAcademy = academyRepository.save(academy); + lessonRepository.save(AcademyFixture.lessonForSunganm(savedAcademy)); + reviewCountRepository.save(AcademyFixture.reviewCountDefault(savedAcademy)); + } + + //When + AcademiesByLocationResults academiesByLocations = academyService.findAcademiesByLocation( + AcademyFixture.academiesByLocationParam(LATITUDE, LONGITUDE), + savedMember.getId()); + + //Then + assertThat(academiesByLocations.academiesByLocationResults().size()).isEqualTo(academies.size()); + } + + @Test + @DisplayName("학원 이름(ACADEMY_NAME_FOR_SEARCH)으로 검색하면 자동완성 기능으로 관련 학원들을 보여준다.") + void findAcademiesByName_academyName_relatedAcademies() { + //Given + List academies = AcademyFixture.academies(); + for (Academy academy : academies) { + Academy savedAcademy = academyRepository.save(academy); + lessonRepository.save(AcademyFixture.lessonForSunganm(savedAcademy)); + reviewCountRepository.save(AcademyFixture.reviewCountDefault(savedAcademy)); + } + + //When + AcademiesByNameResults academiesByNameResults = academyService.findAcademiesByName( + AcademiesByNameParam.of(ACADEMY_NAME_FOR_SEARCH, 0) + ); + + //Then + for (AcademiesByNameResult academiesByNameResult : academiesByNameResults.academiesByNameResults()) { + assertThat(academiesByNameResult.academyName()).contains(ACADEMY_NAME_FOR_SEARCH); + } + } + + + @Test + @DisplayName("중심 위치 반경 이내에 있는 학원 중에서 교육비가 최소와 최대 사이에 있고 선택한 학원 분류 분야에 해당하는 학원들을 반환한다.") + void filterAcademy_BetweenEducationFeeAndLocationAndInExpertise() { + //Given + lessonRepository.deleteAll(); + reviewCountRepository.deleteAll(); + academyRepository.deleteAll(); + + List academies = AcademyFixture.randomAcademiesWithinDistance(LATITUDE, LONGITUDE); + Long minFee = 10000L; + Long maxFee = 1000000L; + + for (Academy academy : academies) { + Academy savedAcademy = academyRepository.save(academy); + savedAcademy.changeEducationFee(generateRandomAmount(minFee, maxFee)); + + lessonRepository.save(AcademyFixture.lessonForSunganm(savedAcademy)); + reviewCountRepository.save(AcademyFixture.reviewCountDefault(savedAcademy)); + } + AcademyFilterParam academyFilterParam = AcademyFixture.academyFilterParam(LATITUDE, LONGITUDE, minFee, maxFee); + + //When + AcademyFilterResults academyFilterResults = academyService.filterAcademies(academyFilterParam, savedMember.getId()); + + //Then + for (AcademyFilterResult academyFilterResult : academyFilterResults.academyFilterResults()) { + Academy filtedAcademy = academyRepository.getById(academyFilterResult.academyId()); + + assertThat(filtedAcademy.getMaxEducationFee()). + isGreaterThanOrEqualTo(minFee) + .isLessThanOrEqualTo(maxFee); + assertThat(academyFilterParam.areaOfExpertises()).containsExactlyInAnyOrder(academyFilterResult.areaOfExpertise()); + } + } + + private long generateRandomAmount(long min, long max) { + if (min >= max) { + throw new IllegalArgumentException("Min value must be less than max value"); + } + + Random random = new Random(); + return min + random.nextInt((int) (max - min + 1)); + } } diff --git a/src/test/java/org/guzzing/studayserver/testutil/fixture/AcademyFixture.java b/src/test/java/org/guzzing/studayserver/testutil/fixture/AcademyFixture.java deleted file mode 100644 index 8d75a669..00000000 --- a/src/test/java/org/guzzing/studayserver/testutil/fixture/AcademyFixture.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.guzzing.studayserver.testutil.fixture; - -import java.util.List; -import org.guzzing.studayserver.domain.academy.model.Academy; -import org.guzzing.studayserver.domain.academy.model.Lesson; -import org.guzzing.studayserver.domain.academy.model.ReviewCount; -import org.guzzing.studayserver.domain.academy.model.vo.Address; -import org.guzzing.studayserver.domain.academy.model.vo.Location; -import org.guzzing.studayserver.domain.academy.model.vo.academyinfo.AcademyInfo; -import org.guzzing.studayserver.domain.academy.model.vo.academyinfo.ShuttleAvailability; - -public class AcademyFixture { - - public static List academyInfos() { - return List.of( - AcademyInfo.of("유원우 코딩학원", "000-0000-0000", ShuttleAvailability.AVAILABLE.name(), "예능(대)"), - AcademyInfo.of("박세영 코딩학원", "000-0000-0000", ShuttleAvailability.AVAILABLE.name(), "예능(대)"), - AcademyInfo.of("김별 코딩학원", "000-0000-0000", ShuttleAvailability.AVAILABLE.name(), "예능(대)"), - AcademyInfo.of("김희석보스 코딩학원", "000-0000-0000", ShuttleAvailability.AVAILABLE.name(), "예능(대)") - ); - } - - public static Academy academySuwon() { - return Academy.of(AcademyFixture.academyInfos().get(0), Address.of("경기도 분당구 수원시 망포동"), Location.of(35, 127)); - } - - public static Academy academySungnam() { - return Academy.of(AcademyFixture.academyInfos().get(1), Address.of("경기도 분당구 성남시 망포동"), Location.of(35, 127)); - } - - public static Lesson lessonForSuwon(Academy academy) { - return Lesson.of(academy, "자바와 객체지향", "자바와 객체지향으로 떠나자", "20", "1개월", "100000"); - } - - public static Lesson lessonForSunganm(Academy academy) { - return Lesson.of(academy, "DB에 대해서", "인덱스란 뭘까", "20", "1개월", "100000"); - } - - public static ReviewCount reviewCountDefault(Academy academy) { - return ReviewCount.makeDefaultReviewCount(academy); - } - -} diff --git a/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/AcademyFixture.java b/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/AcademyFixture.java index 54d19743..f3ecf65f 100644 --- a/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/AcademyFixture.java +++ b/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/AcademyFixture.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; + import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.academy.model.Lesson; import org.guzzing.studayserver.domain.academy.model.ReviewCount; @@ -10,6 +11,7 @@ import org.guzzing.studayserver.domain.academy.model.vo.academyinfo.AcademyInfo; import org.guzzing.studayserver.domain.academy.model.vo.academyinfo.ShuttleAvailability; import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByLocationParam; +import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterParam; import org.locationtech.jts.geom.Point; public class AcademyFixture { @@ -70,4 +72,8 @@ public static AcademiesByLocationParam academiesByLocationParam(double latitude, return AcademiesByLocationParam.of(latitude, longitude); } + public static AcademyFilterParam academyFilterParam(Double latitude, Double longitude, Long desiredMinAmount, Long desiredMaxAmount) { + return new AcademyFilterParam(latitude, longitude, List.of("예능(대)"), desiredMinAmount, desiredMaxAmount); + } + } diff --git a/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/RandomLocationGenerator.java b/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/RandomLocationGenerator.java index 525a9977..5010696a 100644 --- a/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/RandomLocationGenerator.java +++ b/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/RandomLocationGenerator.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; + import org.guzzing.studayserver.domain.academy.model.vo.Location; import org.guzzing.studayserver.domain.academy.util.GeometryUtil; @@ -41,4 +42,5 @@ public static List generateRandomLocations(Location centerLocation, in return randomLocations; } + } diff --git a/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java b/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java new file mode 100644 index 00000000..e03d7d3c --- /dev/null +++ b/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java @@ -0,0 +1,13 @@ +package org.guzzing.studayserver.testutil.fixture.member; + +import org.guzzing.studayserver.domain.child.model.NickName; +import org.guzzing.studayserver.domain.member.model.Member; +import org.guzzing.studayserver.domain.member.model.vo.MemberProvider; +import org.guzzing.studayserver.domain.member.model.vo.RoleType; + +public class MemberFixture { + public static Member member() { + return Member.of(new NickName("나는왕이다"), "12345678", MemberProvider.KAKAO, RoleType.USER); + } + +}