Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GETP-177 feat: 지원한 프로젝트 목록 조회 기능 구현 #117

Merged
merged 6 commits into from
Aug 19, 2024
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
@@ -0,0 +1,11 @@
package es.princip.getp.domain.project.query.dao;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import es.princip.getp.domain.project.query.dto.AppliedProjectCardResponse;

public interface AppliedProjectDao {

Page<AppliedProjectCardResponse> findPagedMyAppliedProjects(Pageable pageable, Long memberId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package es.princip.getp.domain.project.query.dao;

import com.querydsl.jpa.impl.JPAQuery;
import es.princip.getp.domain.project.command.domain.Project;
import es.princip.getp.domain.project.query.dto.AppliedProjectCardResponse;
import es.princip.getp.infra.support.QueryDslSupport;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

import static es.princip.getp.domain.people.command.domain.QPeople.people;
import static es.princip.getp.domain.project.command.domain.QProject.project;
import static es.princip.getp.domain.project.command.domain.QProjectApplication.projectApplication;
import static es.princip.getp.domain.project.query.dao.ProjectDaoUtil.toProjectIds;

@Repository
@RequiredArgsConstructor
public class AppliedProjectQueryDslDao extends QueryDslSupport implements AppliedProjectDao{

private final ProjectApplicationDao projectApplicationDao;

@Override
public Page<AppliedProjectCardResponse> findPagedMyAppliedProjects(
final Pageable pageable,
final Long memberId
) {
final List<Project> projects = getAppliedProjects(pageable, memberId);
final Long[] projectIds = toProjectIds(projects);
final Map<Long, Long> projectApplicationCounts = projectApplicationDao.countByProjectIds(projectIds);
final List<AppliedProjectCardResponse> content = assembleAppliedProjectCardResponse(projects, projectApplicationCounts);

return applyPagination(
pageable,
content,
countQuery -> getAppliedProjectsCountQuery(memberId)
);
}

private List<Project> getAppliedProjects(
final Pageable pageable,
final Long memberId
) {
return queryFactory.selectFrom(project)
.join(projectApplication).on(projectApplication.projectId.eq(project.projectId))
.join(people).on(people.peopleId.eq(projectApplication.applicantId))
.where(people.memberId.eq(memberId))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
}

private JPAQuery<Long> getAppliedProjectsCountQuery(final Long memberId) {
return queryFactory.select(project.count())
.from(project)
.join(projectApplication).on(projectApplication.projectId.eq(project.projectId))
.join(people).on(people.peopleId.eq(projectApplication.applicantId))
.where(people.memberId.eq(memberId));
}

private List<AppliedProjectCardResponse> assembleAppliedProjectCardResponse(
final List<Project> projects,
final Map<Long, Long> projectApplicationCounts
) {
return projects.stream()
.map(project -> AppliedProjectCardResponse.of(
project,
projectApplicationCounts.get(project.getProjectId())
))
.toList();
}
}
scv1702 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package es.princip.getp.domain.project.query.dao;

import es.princip.getp.infra.support.QueryDslSupport;
import lombok.RequiredArgsConstructor;

import org.springframework.stereotype.Repository;

import java.util.Map;
Expand All @@ -10,6 +12,7 @@
import static es.princip.getp.domain.project.command.domain.QProjectApplication.projectApplication;

@Repository
@RequiredArgsConstructor
public class ProjectApplicationQueryDslDao extends QueryDslSupport implements ProjectApplicationDao {

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package es.princip.getp.domain.project.query.dto;

import es.princip.getp.domain.common.domain.Duration;
import es.princip.getp.domain.common.dto.HashtagsResponse;
import es.princip.getp.domain.project.command.domain.Project;
import es.princip.getp.domain.project.command.domain.ProjectStatus;

public record AppliedProjectCardResponse(
Long projectId,
String title,
Long payment,
Long applicantsCount,
Long estimatedDays,
Duration applicationDuration,
HashtagsResponse hashtags,
String description,
ProjectStatus status
) {

public static AppliedProjectCardResponse of(final Project project, final Long applicantsCount) {
return new AppliedProjectCardResponse(
project.getProjectId(),
project.getTitle(),
project.getPayment(),
applicantsCount,
project.getEstimatedDuration().days(),
project.getApplicationDuration(),
HashtagsResponse.from(project.getHashtags()),
project.getDescription(),
project.getStatus()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package es.princip.getp.domain.project.query.presentation;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import es.princip.getp.domain.project.query.dao.AppliedProjectDao;
import es.princip.getp.domain.project.query.dto.AppliedProjectCardResponse;
import es.princip.getp.infra.dto.response.ApiResponse;
import es.princip.getp.infra.dto.response.ApiResponse.ApiSuccessResult;
import es.princip.getp.infra.dto.response.PageResponse;
import es.princip.getp.infra.security.details.PrincipalDetails;
import lombok.RequiredArgsConstructor;

import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;

@RestController
@RequestMapping("/people")
@RequiredArgsConstructor
public class AppliedProjectQueryController {

private final AppliedProjectDao appliedProjectDao;

@GetMapping("/me/projects")
@PreAuthorize("hasRole('PEOPLE') and isAuthenticated()")
public ResponseEntity<ApiSuccessResult<PageResponse<AppliedProjectCardResponse>>> getMyAppliedProjects(
@PageableDefault(sort = "projectId", direction = Sort.Direction.DESC) final Pageable pageable,
@AuthenticationPrincipal final PrincipalDetails principalDetails
) {
final Long memberId = principalDetails.getMember().getMemberId();
final Page<AppliedProjectCardResponse> page = appliedProjectDao.findPagedMyAppliedProjects(pageable, memberId);
final PageResponse<AppliedProjectCardResponse> response = PageResponse.from(page);
return ApiResponse.success(HttpStatus.OK, response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package es.princip.getp.domain.common.description;


import org.springframework.restdocs.request.ParameterDescriptor;

import static es.princip.getp.infra.util.ParameterDescriptorHelper.getDescriptor;

public class PaginationDescription {

public static ParameterDescriptor[] description(final int page, final int size, final String sort) {
return new ParameterDescriptor[] {
getDescriptor("page", "페이지 번호", "default", String.valueOf(page)),
getDescriptor("size", "페이지 크기", "default", String.valueOf(size)),
getDescriptor("sort", "정렬 방식", "default", sort)
};
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package es.princip.getp.domain.people.query.presentation;

import es.princip.getp.domain.common.description.PaginationDescription;
import es.princip.getp.domain.people.command.domain.PeopleType;
import es.princip.getp.domain.people.query.dao.PeopleDao;
import es.princip.getp.domain.people.query.dto.people.CardPeopleResponse;
Expand Down Expand Up @@ -64,8 +65,8 @@ private ResultActions perform() throws Exception {

@Test
public void getCardPeoplePage() throws Exception {
Pageable pageable = PageRequest.of(page, size, sort);
List<CardPeopleResponse> content = List.of(
final Pageable pageable = PageRequest.of(page, size, sort);
final List<CardPeopleResponse> content = List.of(
new CardPeopleResponse(
1L,
NICKNAME,
Expand All @@ -80,21 +81,14 @@ public void getCardPeoplePage() throws Exception {
)
)
);
Page<CardPeopleResponse> page = new PageImpl<>(content, pageable, content.size());
final Page<CardPeopleResponse> page = new PageImpl<>(content, pageable, content.size());
given(peopleDao.findCardPeoplePage(any(Pageable.class))).willReturn(page);

perform()
.andExpect(status().isOk())
.andDo(
restDocs.document(
queryParameters(
parameterWithName("page").description("페이지 번호")
.optional().attributes(key("default").value("0")),
parameterWithName("size").description("페이지 크기")
.optional().attributes(key("default").value("10")),
parameterWithName("sort").description("정렬 방식")
.optional().attributes(key("default").value("peopleId,desc"))
),
queryParameters(PaginationDescription.description(this.page, size, "peopleId,desc")),
responseFields(
getDescriptor("content[].peopleId", "피플 ID"),
getDescriptor("content[].peopleType", "피플 유형")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package es.princip.getp.domain.project.query.dao;

import es.princip.getp.domain.people.query.infra.PeopleDataLoader;
import es.princip.getp.domain.project.query.dto.AppliedProjectCardResponse;
import es.princip.getp.domain.project.query.infra.ProjectApplicationDataLoader;
import es.princip.getp.domain.project.query.infra.ProjectDataLoader;
import es.princip.getp.infra.DataLoader;
import es.princip.getp.infra.support.DaoTest;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

public class AppliedProjectDaoTest extends DaoTest {

private static final int TEST_SIZE = 20;
private static final int PAGE_SIZE = 10;

@PersistenceContext
private EntityManager entityManager;

@Autowired
private AppliedProjectDao appliedProjectDao;

private List<DataLoader> dataLoaders;

@BeforeEach
void setUp() {
dataLoaders = List.of(
new PeopleDataLoader(entityManager),
new ProjectDataLoader(entityManager),
new ProjectApplicationDataLoader(entityManager)
);
dataLoaders.forEach(dataLoader -> dataLoader.load(TEST_SIZE));
}

@AfterEach
void teardown() {
dataLoaders.forEach(DataLoader::teardown);
}

@Nested
class 지원한_프로젝트_목록_조회 {

final Pageable pageable = PageRequest.of(0, PAGE_SIZE);

@Test
void 프로젝트_목록_조회() {
final Page<AppliedProjectCardResponse> response = appliedProjectDao.findPagedMyAppliedProjects(
pageable,
1L
);

assertThat(response.getContent()).allSatisfy(content -> {
assertThat(content).usingRecursiveComparison().isNotNull();
});
assertThat(response.getNumberOfElements()).isGreaterThan(0);
}
}
}
Loading