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
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ def jacocoExcludePatterns = [
'**/auth/**',
'**/domain/*',
'**/domains/*',
'**/fixture/*'
'**/fixture/*',
'**/*Factory*'
]

def jacocoExcludePatternsForVerify = [
Expand All @@ -130,7 +131,8 @@ def jacocoExcludePatternsForVerify = [
'*.auth.*',
'*.domain.*',
'*.domains.*',
'*.fixture.*'
'*.fixture.*',
'*.*Factory*'
]

jacocoTestReport {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.somemore.center.repository;

import com.somemore.center.domain.Center;
import com.somemore.center.repository.mapper.CenterOverviewInfo;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

Expand All @@ -14,5 +16,6 @@ default boolean doesNotExistById(UUID id) {
return !existsById(id);
}
Optional<Center> findCenterById(UUID id);
List<CenterOverviewInfo> findCenterOverviewsByIds(List<UUID> ids);
void deleteAllInBatch();
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package com.somemore.center.repository;

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.somemore.center.domain.Center;
import com.somemore.center.domain.QCenter;
import com.somemore.center.repository.mapper.CenterOverviewInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

@RequiredArgsConstructor
@Repository
public class CenterRepositoryImpl implements CenterRepository {

private final JPAQueryFactory queryFactory;
private final CenterJpaRepository centerJpaRepository;

@Override
Expand All @@ -28,6 +34,23 @@ public Optional<Center> findCenterById(UUID id) {
return centerJpaRepository.findCenterById(id);
}

@Override
public List<CenterOverviewInfo> findCenterOverviewsByIds(List<UUID> ids) {
QCenter center = QCenter.center;

return queryFactory
.select(Projections.constructor(
CenterOverviewInfo.class,
center.id,
center.name,
center.imgUrl
))
.from(center)
.where(center.id.in(ids)
.and(center.deleted.eq(false)))
.fetch();
}

@Override
public void deleteAllInBatch() {
centerJpaRepository.deleteAllInBatch();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.somemore.center.repository.mapper;


import java.util.UUID;

public record CenterOverviewInfo(
UUID centerId,
String centerName,
String imgUrl
) {

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.somemore.center.service.query;

import com.somemore.center.domain.Center;
import com.somemore.center.repository.mapper.CenterOverviewInfo;
import com.somemore.center.dto.response.CenterProfileResponseDto;
import com.somemore.center.dto.response.PreferItemResponseDto;
import com.somemore.center.repository.CenterRepository;
Expand Down Expand Up @@ -33,6 +34,11 @@ public CenterProfileResponseDto getCenterProfileByCenterId(UUID centerId) {
return CenterProfileResponseDto.of(center, preferItemDtos);
}

@Override
public List<CenterOverviewInfo> getCenterOverviewsByIds(List<UUID> centerIds) {
return centerRepository.findCenterOverviewsByIds(centerIds);
}

@Override
public void validateCenterExists(UUID id) {
if (centerRepository.doesNotExistById(id)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.somemore.center.usecase.query;

import com.somemore.center.repository.mapper.CenterOverviewInfo;
import com.somemore.center.dto.response.CenterProfileResponseDto;

import java.util.List;
import java.util.UUID;

public interface CenterQueryUseCase {

CenterProfileResponseDto getCenterProfileByCenterId(UUID centerId);
List<CenterOverviewInfo> getCenterOverviewsByIds(List<UUID> centerIds);
void validateCenterExists(UUID centerId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.somemore.interestcenter.controller;

import com.somemore.global.common.response.ApiResponse;
import com.somemore.interestcenter.dto.response.InterestCentersResponseDto;
import com.somemore.interestcenter.usecase.InterestCenterQueryUseCase;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.UUID;

@RequiredArgsConstructor
@RestController
@Tag(name = "Interest Center Query API", description = "관심 기관의 조회 API를 제공합니다")
public class InterestCenterQueryApiController {

private final InterestCenterQueryUseCase interestCenterQueryUseCase;

@Operation(summary = "관심기관 목록 조회 API")
@GetMapping("/api/interest-centers")
public ApiResponse<List<InterestCentersResponseDto>> getInterestCenters(@AuthenticationPrincipal String volunteerId) {

Copy link
Collaborator

Choose a reason for hiding this comment

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

명세상으로 페이징 처리 해야할 것 같아요

Copy link
Collaborator

Choose a reason for hiding this comment

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

List<InterestCentersResponseDto> responseDtos = interestCenterQueryUseCase.getInterestCenters(UUID.fromString(volunteerId));

return ApiResponse.ok(200, responseDtos, "관심기관 조회 성공");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.somemore.interestcenter.dto.response;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.somemore.center.repository.mapper.CenterOverviewInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import java.util.UUID;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@Builder
public record InterestCentersResponseDto(
@Schema(description = "관심기관의 ID", example = "123e4567-e89b-12d3-a456-426614174000")
UUID centerId,
@Schema(description = "관심기관의 이름", example = "서울 도서관")
String centerName,
@Schema(description = "관심기관의 프로필 이미지 링크", example = "~~/image.jpeg")
String imgUrl
) {
public static InterestCentersResponseDto of(CenterOverviewInfo responseDto) {
return InterestCentersResponseDto.builder()
.centerId(responseDto.centerId())
.centerName(responseDto.centerName())
.imgUrl(responseDto.imgUrl())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public record RegisterInterestCenterResponseDto(
@Schema(description = "봉사자 ID", example = "123e4567-e89b-12d3-a456-426614174000")
UUID volunteerId,

@Schema(description = "센터 ID", example = "123e4567-e89b-12d3-a456-426614174000")
@Schema(description = "기관 ID", example = "123e4567-e89b-12d3-a456-426614174000")
UUID centerId
) {
public static RegisterInterestCenterResponseDto from(InterestCenter interestCenter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import com.somemore.interestcenter.domain.InterestCenter;
import com.somemore.interestcenter.dto.response.RegisterInterestCenterResponseDto;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

public interface InterestCenterRepository {
InterestCenter save(InterestCenter interestCenter);
Optional<InterestCenter> findById(Long id);
Optional<RegisterInterestCenterResponseDto> findInterestCenterResponseById(Long id);
List<UUID> findInterestCenterIdsByVolunteerId(UUID volunteerId);
boolean existsByVolunteerIdAndCenterId(UUID volunteerId, UUID centerId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

Expand Down Expand Up @@ -61,6 +62,20 @@ public Optional<RegisterInterestCenterResponseDto> findInterestCenterResponseByI
return Optional.ofNullable(result);
}

@Override
public List<UUID> findInterestCenterIdsByVolunteerId(UUID volunteerId) {
QInterestCenter interestCenter = QInterestCenter.interestCenter;

return queryFactory
.select(interestCenter.centerId)
.from(interestCenter)
.where(
interestCenter.volunteerId.eq(volunteerId)
.and(interestCenter.deleted.eq(false))
)
.fetch();
}

@Override
public boolean existsByVolunteerIdAndCenterId(UUID volunteerId, UUID centerId) {
QInterestCenter interestCenter = QInterestCenter.interestCenter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.somemore.interestcenter.service;

import com.somemore.center.repository.mapper.CenterOverviewInfo;
import com.somemore.center.usecase.query.CenterQueryUseCase;
import com.somemore.interestcenter.dto.response.InterestCentersResponseDto;
import com.somemore.interestcenter.repository.InterestCenterRepository;
import com.somemore.interestcenter.usecase.InterestCenterQueryUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

@RequiredArgsConstructor
@Service
public class InterestCenterQueryService implements InterestCenterQueryUseCase {

private final CenterQueryUseCase centerQueryUseCase;
private final InterestCenterRepository interestCenterRepository;

@Override
public List<InterestCentersResponseDto> getInterestCenters(UUID volunteerId) {

List<UUID> interestCenterIds = interestCenterRepository.findInterestCenterIdsByVolunteerId(volunteerId);
if (interestCenterIds.isEmpty()) {
return List.of();
}

List<CenterOverviewInfo> centerOverviews = centerQueryUseCase.getCenterOverviewsByIds(interestCenterIds);
return centerOverviews.stream()
.map(InterestCentersResponseDto::of)
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.somemore.interestcenter.usecase;

import com.somemore.interestcenter.dto.response.InterestCentersResponseDto;

import java.util.List;
import java.util.UUID;

public interface InterestCenterQueryUseCase {
List<InterestCentersResponseDto> getInterestCenters(UUID volunteerId);
}
26 changes: 26 additions & 0 deletions src/test/java/com/somemore/CustomSecurityContextFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.somemore;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.test.context.support.WithSecurityContextFactory;

import java.util.Collections;

public class CustomSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> {
@Override
public SecurityContext createSecurityContext(WithMockCustomUser annotation) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
Copy link
Collaborator

Choose a reason for hiding this comment

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

아 저는 이게 문제였을까요...


Authentication auth = new UsernamePasswordAuthenticationToken(
annotation.username(),
"password",
Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))
);

context.setAuthentication(auth);
return context;
}
}
12 changes: 12 additions & 0 deletions src/test/java/com/somemore/WithMockCustomUser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.somemore;

import org.springframework.security.test.context.support.WithSecurityContext;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = CustomSecurityContextFactory.class)
public @interface WithMockCustomUser {
String username() default "123e4567-e89b-12d3-a456-426614174000";
}
Comment on lines +8 to +12
Copy link
Collaborator

Choose a reason for hiding this comment

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

어노테이션에 능숙하시네요. 저는 처음보는 문법이 많은 것 같습니다.

Loading