Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9fade18
feat: exception,ocrClient,ocrConfig,reviewController 수정
1224kang Jan 16, 2026
136b736
feat: DTO 정리
1224kang Jan 16, 2026
89c0a53
feat: 재êµìƒ장소 상세 조회, 제휴 요청ê¹
1224kang Jan 16, 2026
f2ee0f5
feat: OCR 리뷰 isVerified=true로 변경해서 저장하도록 수정
1224kang Jan 16, 2026
593809e
feat: 리뷰 작성 로직 설명 추가 및 제휴여부 판단 할 수 있는 필드 추가
1224kang Jan 16, 2026
6c420bd
fix: coderabbit 1차 PR 수정
1224kang Jan 16, 2026
dde4856
refactor: 리소스 파일 ocr 설정 추가
1winhyun Jan 16, 2026
4292348
fix: PR 2차 수정
1224kang Jan 16, 2026
d7fe45b
Merge branch 'feat/#86' of https://github.com/our-campUS/our-campUS-B…
1224kang Jan 16, 2026
aea391f
refactor: 리소스 파일 ocr 사진 최대 크기 수정
1winhyun Jan 16, 2026
9feaf72
refactor: OcrConfig RestTemplate 사용에서 RestClient 사용으로 수정
1winhyun Jan 16, 2026
66037b4
refactor: OCR 인증 SavedPlaceInfo가 아닌 placeId로 가져오도록 수정
1winhyun Jan 16, 2026
7a9f98f
refactor: OCR 인증 반환값에 paymentDate 추가
1winhyun Jan 16, 2026
8feb4ea
refactor: 컨벤션 개행 처리
1winhyun Jan 16, 2026
1c885fa
refactor: 리뷰 작성 example 변경
1224kang Jan 16, 2026
44fd559
refactor: 제휴 장소 리뷰와 제휴 없는 장소 리뷰 작성에 대한 api 분리
1winhyun Jan 16, 2026
6d65bad
refactor: PermitUrlConfig에 url 발급 추가
1winhyun Jan 16, 2026
d31d05e
refactor: getPartnershipPlaces size 파라미터 적용
1winhyun Jan 16, 2026
9627414
refactor: 개행 처리 및 중복 메서드 분리
1winhyun Jan 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@ Optional<StudentCouncil> findByIdWithDetailsAndManagerApprovedIsTrueAndDeletedAt
boolean existsByEmailAndDeletedAtIsNotNull(String email);

boolean existsByLoginIdAndManagerApprovedIsTrueAndDeletedAtIsNull(String loginId);

Optional<StudentCouncil> findByMajor_MajorIdAndDeletedAtIsNull(Long majorId);

Optional<StudentCouncil> findByCollege_CollegeIdAndDeletedAtIsNull(Long collegeId);

Optional<StudentCouncil> findBySchool_SchoolIdAndDeletedAtIsNull(Long schoolId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.campus.campus.domain.councilpost.domain.entity.PostCategory;
import com.campus.campus.domain.councilpost.domain.entity.StudentCouncilPost;
import com.campus.campus.domain.councilpost.domain.entity.ThumbnailIcon;
import com.campus.campus.domain.place.domain.entity.Place;

public interface StudentCouncilPostRepository extends JpaRepository<StudentCouncilPost, Long> {

Expand Down Expand Up @@ -314,6 +315,34 @@ List<StudentCouncilPost> findTop3RecommendedPartnershipPlaces(
Pageable pageable
);

@Query("""
SELECT p
FROM StudentCouncilPost p
JOIN p.writer w
LEFT JOIN w.major m
LEFT JOIN w.college c
LEFT JOIN w.school s
WHERE p.place.placeId = :placeId
AND p.startDateTime <= :paymentDate
AND p.endDateTime >= :paymentDate
AND w.deletedAt IS NULL
AND (
(w.councilType =:majorType AND m.majorId = :majorId)
OR (w.councilType =:collegeType AND c.collegeId = :collegeId)
OR (w.councilType =:schoolType AND s.schoolId = :schoolId)
)
""")
Optional<StudentCouncilPost> findValidPartnershipForUserScope(
@Param("placeId") Long placeId,
@Param("paymentDate") LocalDateTime paymentDate,
@Param("majorId") Long majorId,
@Param("collegeId") Long collegeId,
@Param("schoolId") Long schoolId,
@Param("majorType") CouncilType majorType,
@Param("collegeType") CouncilType collegeType,
@Param("schoolType") CouncilType schoolType
);

@EntityGraph(attributePaths = {"writer", "writer.school", "writer.college", "writer.major", "place"})
@Query("""
SELECT p FROM StudentCouncilPost p
Expand Down Expand Up @@ -383,4 +412,30 @@ List<StudentCouncilPost> findTodayEvent(
@Param("endOfDay") LocalDateTime endOfDay,
Pageable pageable
);

@Query("""
SELECT p
FROM StudentCouncilPost p
JOIN p.writer w
WHERE p.place = :place
AND p.startDateTime <= :now
AND p.endDateTime >= :now
AND w.deletedAt IS NULL
AND (
(w.councilType = :majorType AND w.major.majorId = :majorId)
OR (w.councilType = :collegeType AND w.college.collegeId = :collegeId)
OR (w.councilType = :schoolType AND w.school.schoolId = :schoolId)
)
ORDER BY p.endDateTime DESC
""")
Optional<StudentCouncilPost> findActiveByPlaceAndUserScope(
@Param("place") Place place,
@Param("now") LocalDateTime now,
@Param("majorType") CouncilType majorType,
@Param("majorId") Long majorId,
@Param("collegeType") CouncilType collegeType,
@Param("collegeId") Long collegeId,
@Param("schoolType") CouncilType schoolType,
@Param("schoolId") Long schoolId
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.campus.campus.domain.place.application.dto.response;

import java.util.List;

import com.campus.campus.domain.review.application.dto.response.SimpleReviewResponse;

public record PlaceDetailResponse(
boolean isPartnership,
Long placeId,
String placeKey,
String name,
String category,
String address,
Double latitude,
Double longitude,
boolean isLiked,
double star,
double distance,

//PlaceImg 이미지 받아오기
List<String> imgUrls,
List<SimpleReviewResponse> reviews,
int reviewSize
) implements PlaceDetailView {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.campus.campus.domain.place.application.dto.response;

public interface PlaceDetailView {

boolean isPartnership();

Long placeId();

String placeKey();

String name();

String category();

String address();

Double latitude();

Double longitude();

boolean isLiked();

double star();

double distance();
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
package com.campus.campus.domain.place.application.dto.response.partnership;

import java.time.LocalDate;
import java.util.List;

public record PartnershipResponse(
Long placeId,
String placeKey,
String name,
String category,
String address,
Double latitude,
Double longitude,
String tag, //(ex.) 총학생회, 사회과학대학, IT공학과
boolean isLiked,
Double star, //리뷰 평점
String partnerTitle, //제휴 제목
double distance, //거리(m)
LocalDate endDate, //제휴 끝나는 시점

//StudentCouncilPost 이미지 받아오기
List<String> imgUrls
) {
}
package com.campus.campus.domain.place.application.dto.response.partnership;

import java.time.LocalDate;
import java.util.List;

import com.campus.campus.domain.place.application.dto.response.PlaceDetailView;
import com.campus.campus.domain.review.application.dto.response.SimpleReviewResponse;

public record PartnershipDetailResponse(
boolean isPartnership,
Long placeId,
String placeKey,
String name,
String category,
String address,
Double latitude,
Double longitude,
String tag, //(ex.) 총학생회, 사회과학대학, IT공학과
boolean isLiked,
double star, //리뷰 평점
String partnerTitle, //제휴 제목
double distance, //거리(m)
LocalDate endDate, //제휴 끝나는 시점

//StudentCouncilPost 이미지 받아오기
List<String> imgUrls,
List<SimpleReviewResponse> reviews,
int reviewSize
) implements PlaceDetailView {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.campus.campus.domain.place.application.exception;

import com.campus.campus.global.common.exception.ApplicationException;

public class AlreadySuggestedPartnershipException extends ApplicationException {
public AlreadySuggestedPartnershipException() {
super(ErrorCode.ALREADY_PARTNERSHIP_SUGGESTED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ public enum ErrorCode implements ErrorCodeInterface {
SHA256_NOT_SUPPORTED(2603, HttpStatus.INTERNAL_SERVER_ERROR, "SHA-256이 지원되지 않습니다."),
NAVER_API_ERROR(2604, HttpStatus.INTERNAL_SERVER_ERROR, "네이버 api 호출에 실패하였습니다."),
PLACE_CREATION_ERROR(2605, HttpStatus.INTERNAL_SERVER_ERROR, "Place 생성에 오류가 발생하였습니다."),
GEOCODER_ERROR(2606, HttpStatus.INTERNAL_SERVER_ERROR, "좌표 -> 주소 변환 과정에서 오류가 발생하였습니다.");
GEOCODER_ERROR(2606, HttpStatus.INTERNAL_SERVER_ERROR, "좌표 -> 주소 변환 과정에서 오류가 발생하였습니다."),
ALREADY_PARTNERSHIP_SUGGESTED(2607, HttpStatus.CONFLICT, "이미 제휴 신청 완료된 장소입니다.");

private final int code;
private final HttpStatus status;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
package com.campus.campus.domain.place.application.mapper;

import java.time.LocalDate;
import java.util.List;

import org.springframework.stereotype.Component;

import com.campus.campus.domain.council.domain.entity.CouncilType;
import com.campus.campus.domain.councilpost.domain.entity.StudentCouncilPost;
import com.campus.campus.domain.place.application.dto.response.PartnershipPinResponse;
import com.campus.campus.domain.place.application.dto.response.LikeResponse;
import com.campus.campus.domain.place.application.dto.response.SearchPartnershipInfoResponse;
import com.campus.campus.domain.place.application.dto.response.SearchPlaceInfoResponse;
import com.campus.campus.domain.place.application.dto.response.PartnershipPinResponse;
import com.campus.campus.domain.place.application.dto.response.PlaceDetailResponse;
import com.campus.campus.domain.place.application.dto.response.RecommendNearByPlaceResponse;
import com.campus.campus.domain.place.application.dto.response.RecommendPartnershipPlaceResponse;
import com.campus.campus.domain.place.application.dto.response.RecommendPlaceByTimeResponse;
import com.campus.campus.domain.place.application.dto.response.SavedPlaceInfo;
import com.campus.campus.domain.place.application.dto.response.SearchPartnershipInfoResponse;
import com.campus.campus.domain.place.application.dto.response.SearchPlaceInfoResponse;
import com.campus.campus.domain.place.application.dto.response.naver.NaverSearchResponse;
import com.campus.campus.domain.place.application.dto.response.partnership.PartnershipResponse;
import com.campus.campus.domain.place.application.dto.response.partnership.PartnershipDetailResponse;
import com.campus.campus.domain.place.domain.entity.Coordinate;
import com.campus.campus.domain.place.domain.entity.LikedPlace;
import com.campus.campus.domain.place.domain.entity.Place;
import com.campus.campus.domain.place.domain.entity.PlaceImages;
import com.campus.campus.domain.review.application.dto.response.ReviewPartnerResponse;
import com.campus.campus.domain.review.application.dto.response.SimpleReviewResponse;
import com.campus.campus.domain.user.domain.entity.User;

@Component
Expand Down Expand Up @@ -71,9 +75,11 @@ public PartnershipPinResponse toPartnershipPinResponse(StudentCouncilPost post,
);
}

public PartnershipResponse toPartnershipResponse(User user, StudentCouncilPost post, Place place, boolean isLiked,
List<String> imgUrls, double distance) {
return new PartnershipResponse(
public PartnershipDetailResponse toPartnershipResponse(User user, StudentCouncilPost post, Place place,
boolean isLiked,
List<String> imgUrls, double distance, Double averageStar, List<SimpleReviewResponse> reviews, Integer size) {
return new PartnershipDetailResponse(
true,
place.getPlaceId(),
place.getPlaceKey(),
place.getPlaceName(),
Expand All @@ -83,11 +89,47 @@ public PartnershipResponse toPartnershipResponse(User user, StudentCouncilPost p
place.getCoordinate().longitude(),
resolveTag(post, user),
isLiked,
5.0, //리뷰 구현 이후 수정 예정
averageStar,
post.getTitle(),
distance,
post.getEndDateTime().toLocalDate(),
imgUrls
imgUrls,
reviews,
size
);
}

public PlaceDetailResponse toPlaceDetailResponse(Place place, boolean isLiked,
List<String> imgUrls, double distance, Double averageStar, List<SimpleReviewResponse> reviews, Integer size) {
return new PlaceDetailResponse(
false,
place.getPlaceId(),
place.getPlaceKey(),
place.getPlaceName(),
place.getPlaceCategory(),
place.getAddress(),
place.getCoordinate().latitude(),
place.getCoordinate().longitude(),
isLiked,
averageStar,
distance,
imgUrls,
reviews,
size
);
}

public ReviewPartnerResponse toReviewPartnerResponse(StudentCouncilPost post, Place place, double averageStar,
String tag, boolean isLiked, LocalDate paymentDate) {
return new ReviewPartnerResponse(
place.getPlaceName(),
place.getPlaceCategory(),
post.getWriter().getCouncilName(),
averageStar, //리뷰 별점
post.getTitle(),
tag,
isLiked,
paymentDate
);
Comment on lines +122 to 133
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find PlaceMapper file and understand the context
find . -type f -name "PlaceMapper.java" | head -20

Repository: our-campUS/our-campUS-BE

Length of output: 150


🏁 Script executed:

# Search for calls to toReviewPartnerResponse method
rg "toReviewPartnerResponse" -A 5 -B 2

Repository: our-campUS/our-campUS-BE

Length of output: 2017


🏁 Script executed:

# Find ReviewService file to check how tag parameter is passed
find . -type f -name "ReviewService.java" | head -20

Repository: our-campUS/our-campUS-BE

Length of output: 154


🏁 Script executed:

# Read ReviewService.java to understand the full context of the call
cat -n ./src/main/java/com/campus/campus/domain/review/application/service/ReviewService.java | head -100

Repository: our-campUS/our-campUS-BE

Length of output: 5811


🏁 Script executed:

# Search for resolveTag method
rg "resolveTag" -B 5 -A 10

Repository: our-campUS/our-campUS-BE

Length of output: 3468


🏁 Script executed:

# Get more context around the toReviewPartnerResponse call
rg "toReviewPartnerResponse" -B 10 -A 5

Repository: our-campUS/our-campUS-BE

Length of output: 3867


tag 파라미터가 councilName으로 전달되어 council 필드와 중복 발생

ReviewService에서 tagpost.getWriter().getCouncilName()을 넘기고 있어, 현재 toReviewPartnerResponse 메서드 내에서 council 필드도 동일하게 post.getWriter().getCouncilName()을 사용하므로 두 필드가 동일한 값을 갖습니다. resolveTag 메서드가 학교/단과대/학과명을 올바르게 반환하도록 설계되었으므로, ReviewService의 호출부에서 tag 파라미터로 resolveTag 로직을 적용하거나 메서드 시그니처를 수정하여 의도에 맞는 태그 값을 전달하세요.

🤖 Prompt for AI Agents
In
`@src/main/java/com/campus/campus/domain/place/application/mapper/PlaceMapper.java`
around lines 122 - 133, The tag parameter is being passed as
post.getWriter().getCouncilName(), causing duplicate values with the council
field in toReviewPartnerResponse; update the call site in ReviewService to pass
the resolved tag (use resolveTag(...) that returns school/college/department)
instead of post.getWriter().getCouncilName(), or alternatively change the
toReviewPartnerResponse signature to accept a StudentCouncilPost and call
resolveTag inside that method; locate the call that constructs the
ReviewPartnerResponse in ReviewService and replace the tag argument with
resolveTag(...) (or move resolveTag logic into toReviewPartnerResponse) so
council stays councilName and tag contains the resolved
school/college/department value.

}

Expand Down
Loading