Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -9,6 +9,7 @@
import com.kuit.findyou.domain.report.dto.response.WitnessReportDetailResponseDTO;
import com.kuit.findyou.domain.report.model.ReportTag;
import com.kuit.findyou.domain.report.service.facade.ReportServiceFacade;
import com.kuit.findyou.domain.report.service.retrieve.MissingReportRetrieveWithS3Service;
import com.kuit.findyou.domain.report.service.retrieve.ProtectingReportRetrieveWithS3Service;
import com.kuit.findyou.global.common.annotation.CustomExceptionDescription;
import com.kuit.findyou.global.common.response.BaseResponse;
Expand Down Expand Up @@ -40,6 +41,7 @@ public class ReportController {

private final ReportServiceFacade reportServiceFacade;
private final ProtectingReportRetrieveWithS3Service protectingReportRetrieveWithS3Service;
private final MissingReportRetrieveWithS3Service missingReportRetrieveWithS3Service;

@Operation(summary = "보호글 상세 조회 API", description = "보호글의 정보를 상세 조회하기 위한 API")
@GetMapping("/protecting-reports/{reportId}")
Expand Down Expand Up @@ -133,5 +135,23 @@ public ResponseEntity<?> getRandomProtectingReportsWithS3(
return ResponseEntity.ok(BaseResponse.ok(details));
}

@Operation(
summary = "실종글 S3 이미지 포함 랜덤 조회 API", description = "랜덤으로 실종글을 선택하여 원본 이미지를 S3에 업로드 후, S3 URL 포함 실종글을 리스트로 반환합니다."
)
@GetMapping("/missing-reports/random-s3")
@CustomExceptionDescription(DEFAULT)
public ResponseEntity<?> getRandomMissingReportsWithS3(
@RequestParam(name = "count", defaultValue = "1")
@Min(1) @Max(10) int count
) {
List<MissingReportDetailResponseDTO> details =
missingReportRetrieveWithS3Service.getRandomMissingReportsWithS3(count);

if (details.isEmpty()) {
return ResponseEntity.noContent().build();
}
return ResponseEntity.ok(BaseResponse.ok(details));
}

}

Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.kuit.findyou.domain.report.repository;

import com.kuit.findyou.domain.report.model.MissingReport;
import com.kuit.findyou.domain.report.model.ProtectingReport;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

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


Expand All @@ -14,4 +15,6 @@ public interface MissingReportRepository extends JpaRepository<MissingReport, Lo

@EntityGraph(attributePaths = {"reportImages"})
Optional<MissingReport> findWithImagesById(Long id);

List<MissingReport> findByDate(LocalDate date);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.List;

import static com.kuit.findyou.global.common.response.status.BaseExceptionResponseStatus.MISSING_REPORT_NOT_FOUND;

Expand Down Expand Up @@ -39,6 +39,25 @@ public MissingReportDetailResponseDTO getDetail(MissingReport report, boolean in
interest
);
}
public MissingReportDetailResponseDTO toDetailDto(MissingReport report, List<String> imageUrls, boolean interest) {
return new MissingReportDetailResponseDTO(
imageUrls,
ReportFormatUtil.safeValue(report.getBreed()),
report.getTag().getValue(),
ReportFormatUtil.safeValue(report.getAge()),
ReportFormatUtil.safeSex(report.getSex()),
ReportFormatUtil.safeDate(report.getDate()),
ReportFormatUtil.safeValue(report.getRfid()),
ReportFormatUtil.safeValue(report.getSignificant()),
ReportFormatUtil.safeValue(report.getLandmark()),
ReportFormatUtil.safeValue(report.getAddress()),
ReportFormatUtil.formatCoordinate(report.getLatitude()),
ReportFormatUtil.formatCoordinate(report.getLongitude()),
ReportFormatUtil.safeValue(report.getReporterName()),
ReportFormatUtil.safeValue(report.getReporterTel()),
interest
);
}

@Override
public MissingReport getReport(Long reportId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.kuit.findyou.domain.report.service.retrieve;

import com.kuit.findyou.domain.report.dto.response.MissingReportDetailResponseDTO;

import java.util.List;

public interface MissingReportRetrieveWithS3Service {
List<MissingReportDetailResponseDTO> getRandomMissingReportsWithS3(int count);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.kuit.findyou.domain.report.service.retrieve;

import com.kuit.findyou.domain.image.model.ReportImage;
import com.kuit.findyou.domain.report.dto.response.MissingReportDetailResponseDTO;
import com.kuit.findyou.domain.report.model.MissingReport;
import com.kuit.findyou.domain.report.repository.MissingReportRepository;
import com.kuit.findyou.domain.report.service.detail.strategy.MissingReportDetailStrategy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@RequiredArgsConstructor
@Service
@Slf4j
public class MissingReportRetrieveWithS3ServiceImpl implements MissingReportRetrieveWithS3Service{
private final MissingReportRepository missingReportRepository;
private final MissingReportDetailStrategy missingReportDetailStrategy;

@Override
@Transactional(readOnly = true)
public List<MissingReportDetailResponseDTO> getRandomMissingReportsWithS3(int count) {
LocalDate yesterday = LocalDate.now().minusDays(1);

List<MissingReport> allReports = missingReportRepository.findByDate(yesterday);

if (allReports.isEmpty()) {
// 204 no content
return Collections.emptyList();
}

Collections.shuffle(allReports);

int limit = Math.max(1, count);
List<MissingReport> selectedReports = allReports.stream().limit(limit).toList();

List<MissingReportDetailResponseDTO> result = new ArrayList<>();

for (MissingReport report : selectedReports) {

List<String> imageUrls = report.getReportImages().stream()
.map(ReportImage::getImageUrl)
.filter(url -> url != null && !url.isBlank())
.distinct()
.toList();

Comment on lines +45 to +51
Copy link
Collaborator

Choose a reason for hiding this comment

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

예전에 작성해주신 신고글 저장 로직을 보면 이미지 URL 중복을 제거하시긴 하던데, 여기서도 중복 제거를 수행하네요. 의도하신건가요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

음 저장 시에 중복제거를 수행하긴 하지만 조회 단에서도 방어적으로 한번 더 검증하는 것이 좋겠다 싶어서 넣긴 했어요. 물론 저장 시에만 제거해도 웬만한 경우에는 DB에 중복이 안 들어갈 거긴 합니다만, 버그나 기타 상황을 생각하고 중복제거를 수행했습니다!

MissingReportDetailResponseDTO dto =
missingReportDetailStrategy.toDetailDto(report, imageUrls,false);
result.add(dto);
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
.requestMatchers(HttpMethod.POST, "/api/v2/users").permitAll()
.requestMatchers(HttpMethod.POST, "/api/v2/users/check/duplicate-nickname").permitAll()
.requestMatchers(HttpMethod.GET, "/api/v2/reports/protecting-reports/random-s3").permitAll()
.requestMatchers(HttpMethod.GET, "/api/v2/reports/missing-reports/random-s3").permitAll()
.anyRequest().authenticated());

// 토큰 검증 필터 추가
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.kuit.findyou.domain.report.controller;

import com.kuit.findyou.domain.image.repository.ReportImageRepository;
import com.kuit.findyou.domain.report.dto.request.CreateMissingReportRequest;
import com.kuit.findyou.domain.report.dto.request.CreateWitnessReportRequest;
import com.kuit.findyou.domain.report.dto.request.ReportViewType;
import com.kuit.findyou.domain.report.model.MissingReport;
import com.kuit.findyou.domain.report.model.ProtectingReport;
import com.kuit.findyou.domain.report.repository.MissingReportRepository;
import com.kuit.findyou.domain.report.repository.ProtectingReportRepository;
import com.kuit.findyou.domain.user.model.User;
import com.kuit.findyou.global.common.util.DatabaseCleaner;
Expand All @@ -24,6 +25,7 @@
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDate;
Expand Down Expand Up @@ -52,7 +54,7 @@ class ReportControllerTest {
private ProtectingReportRepository protectingReportRepository;

@Autowired
private ReportImageRepository reportImageRepository;
private MissingReportRepository missingReportRepository;


@LocalServerPort
Expand Down Expand Up @@ -584,7 +586,7 @@ void getRandomProtectingReportsWithS3_success() {
.body("success", equalTo(true))
.body("code", equalTo(200))
.body("data.size()", equalTo(1))
.body("data[0].imageUrls[0]", equalTo("https://cdn.findyou.store/random1.jpg"))
.body( "data[0].imageUrls[0]", equalTo("https://cdn.findyou.store/random1.jpg"))
.body("data[0].breed", equalTo("믹스견"))
.body("data[0].tag", equalTo("보호중"))
.body("data[0].careName", equalTo("광진보호소"));
Expand All @@ -607,4 +609,52 @@ void getRandomProtectingReportsWithS3_noContent() {
.log().all()
.statusCode(204);
}
@Test
@DisplayName("실종글 랜덤 조회 -> S3 URL 포함 응답")
void getRandomMissingReportsWithS3_success() {
// given
User user = testInitializer.createTestUser();
MissingReport report =
testInitializer.createTestMissingReportWithImage(user);

ReflectionTestUtils.setField(report, "date", LocalDate.now().minusDays(1));

missingReportRepository.saveAndFlush(report);

// when & then
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.param("count", 1)
.when()
.get("/api/v2/reports/missing-reports/random-s3")
.then()
.log().all()
.statusCode(200)
.body("success", equalTo(true))
.body("code", equalTo(200))
.body("data.size()", equalTo(1))
.body("data[0].imageUrls[0]", equalTo("https://img.com/missing.png"))
.body("data[0].breed", equalTo("포메라니안"))
.body("data[0].tag", equalTo("실종신고"));
}

@Test
@DisplayName("실종글이 없을 경우 -> 204 No Content 응답 (Body 없음)")
void getRandomMissingReportsWithS3_noContent() {
// given
// DB에 아무것도 저장하지 않음 (빈 상태)

// when & then
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.param("count", 1)
.when()
.get("/api/v2/reports/missing-reports/random-s3")
.then()
.log().all()
.statusCode(204);
}

}
Loading