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

[FEAT] 사용자가 생성한 프로젝트, 프로젝트 리스트 조회 API 개발 #183

Merged
merged 7 commits into from
Feb 28, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDetailAPIRes;
import io.oeid.mogakgo.domain.project.presentation.dto.req.ProjectCreateReq;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectIdRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectInfoAPIRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.projectJoinRequestRes;
import io.oeid.mogakgo.exception.dto.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
Expand Down Expand Up @@ -179,4 +180,53 @@ ResponseEntity<CursorPaginationResult<projectJoinRequestRes>> getJoinRequest(
content = @Content(schema = @Schema(implementation = ProjectDensityRankRes.class))),
})
ResponseEntity<ProjectDensityRankRes> getDensityRankProjects();

@Operation(summary = "사용자가 생성한 프로젝트 리스트 조회", description = "회원이 자신이 만든 프로젝트 리스트를 조회할 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "프로젝트 리스트 조회 성공"),
@ApiResponse(responseCode = "403", description = "본인의 프로젝트 카드만 조회 할 수 있음.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "E030101", value = SwaggerProjectErrorExamples.PROJECT_JOIN_REQUEST_FORBIDDEN_OPERATION))),
@ApiResponse(responseCode = "404", description = "요청한 데이터가 존재하지 않음",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND)
))
})
@Parameters({
@Parameter(name = "cursorId", description = "기준이 되는 커서 ID", example = "1"),
@Parameter(name = "pageSize", description = "요청할 데이터 크기", example = "5", required = true),
@Parameter(name = "sortOrder", description = "정렬 방향", example = "ASC"),
})
ResponseEntity<CursorPaginationResult<ProjectInfoAPIRes>> getProjectsByCreator(
@Parameter(hidden = true) Long userId,
@Parameter(description = "프로젝트를 생성한 사용자 ID", required = true) Long creatorId,
@Parameter(hidden = true) CursorPaginationInfoReq pageable
);

@Operation(summary = "사용자가 생성한 프로젝트 상세 정보 조회", description = "회원이 자신이 생성한 프로젝트의 상세 정보를 조회할 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "프로젝트 조회 성공"),
@ApiResponse(responseCode = "403", description = "본인의 프로젝트 카드만 조회 할 수 있음.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "E030101", value = SwaggerProjectErrorExamples.PROJECT_JOIN_REQUEST_FORBIDDEN_OPERATION))),
@ApiResponse(responseCode = "404", description = "요청한 데이터가 존재하지 않음",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E030301", value = SwaggerProjectErrorExamples.PROJECT_NOT_FOUND),
@ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND)
}))
})
ResponseEntity<ProjectDetailAPIRes> getById(
@Parameter(hidden = true) Long userId,
@Parameter(description = "조회하려는 프로젝트 ID", required = true) Long projectId,
@Parameter(description = "프로젝트 생성자 ID", required = true) Long id
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.oeid.mogakgo.domain.project.presentation.dto.req.ProjectCreateReq;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDensityRankRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDetailAPIRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectInfoAPIRes;
import io.oeid.mogakgo.domain.project_join_req.exception.ProjectJoinRequestException;
import io.oeid.mogakgo.domain.project_join_req.infrastructure.ProjectJoinRequestJpaRepository;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.projectJoinRequestRes;
Expand Down Expand Up @@ -150,6 +151,23 @@ public CursorPaginationResult<ProjectDetailAPIRes> getRandomOrderedProjectsByReg
return projects;
}

public CursorPaginationResult<ProjectInfoAPIRes> getByCreatorId(
Long userId, Long creatorId, CursorPaginationInfoReq pageable
) {
User user = getUser(userId);
validateProjectCardCreator(user, creatorId);

return projectJpaRepository.findByCreatorIdWithPagination(creatorId, pageable);
}

public ProjectDetailAPIRes getByProjectId(Long userId, Long id, Long projectId) {
User user = getUser(userId);

validateProjectCardCreator(user, id);

return ProjectDetailAPIRes.from(getProject(projectId));
}

public ProjectDensityRankRes getDensityRankProjects() {
List<Region> regionRankList = projectJpaRepository.getDensityRankProjectsByRegion(DENSITY_RANK_LIMIT);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.oeid.mogakgo.domain.geo.domain.enums.Region;
import io.oeid.mogakgo.domain.project.domain.entity.enums.ProjectStatus;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDetailAPIRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectInfoAPIRes;
import java.util.List;

public interface ProjectRepositoryCustom {
Expand All @@ -13,5 +14,9 @@ CursorPaginationResult<ProjectDetailAPIRes> findByConditionWithPagination(
Long userId, Region region, ProjectStatus projectStatus, CursorPaginationInfoReq pageable
);

CursorPaginationResult<ProjectInfoAPIRes> findByCreatorIdWithPagination(
Long userId, CursorPaginationInfoReq pageable
);

List<Region> getDensityRankProjectsByRegion(int limit);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.oeid.mogakgo.domain.project.domain.entity.enums.ProjectStatus;
import io.oeid.mogakgo.domain.project.presentation.dto.res.MeetingInfoResponse;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDetailAPIRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectInfoAPIRes;
import io.oeid.mogakgo.domain.user.domain.UserDevelopLanguageTag;
import io.oeid.mogakgo.domain.user.domain.UserWantedJobTag;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserPublicApiResponse;
Expand Down Expand Up @@ -80,6 +81,37 @@ public CursorPaginationResult<ProjectDetailAPIRes> findByConditionWithPagination
);
}

@Override
public CursorPaginationResult<ProjectInfoAPIRes> findByCreatorIdWithPagination(
Long userId, CursorPaginationInfoReq pageable
) {
List<Project> entities = jpaQueryFactory.selectFrom(project)
.innerJoin(project.creator, user)
.on(project.creator.id.eq(user.id))
.where(
userIdEq(userId),
deletedAtEq()
)
.orderBy(project.id.desc())
.limit(pageable.getPageSize() + 1)
.fetch();

List<ProjectInfoAPIRes> result = entities.stream().map(
project -> new ProjectInfoAPIRes(
project.getId(),
project.getProjectStatus(),
project.getCreator().getAvatarUrl(),
project.getMeetingInfo().getMeetDetail(),
project.getMeetingInfo().getMeetStartTime(),
project.getMeetingInfo().getMeetEndTime()
)
).toList();

return CursorPaginationResult.fromDataWithExtraItemForNextCheck(
result, pageable.getPageSize()
);
}

@Override
public List<Region> getDensityRankProjectsByRegion(int limit) {
return jpaQueryFactory.select(project.creatorInfo.region)
Expand Down Expand Up @@ -112,4 +144,8 @@ private BooleanExpression createdAtEq(LocalDate today) {
.and(project.createdAt.month().eq(today.getMonthValue()))
.and(project.createdAt.dayOfMonth().eq(today.getDayOfMonth()));
}

private BooleanExpression deletedAtEq() {
return project.deletedAt.isNull();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDensityRankRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDetailAPIRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectIdRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectInfoAPIRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.projectJoinRequestRes;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -78,4 +79,20 @@ public ResponseEntity<ProjectDensityRankRes> getDensityRankProjects() {
return ResponseEntity.ok().body(projectService.getDensityRankProjects());
}

@GetMapping("/list/{creatorId}")
public ResponseEntity<CursorPaginationResult<ProjectInfoAPIRes>> getProjectsByCreator(
@UserId Long userId, @PathVariable Long creatorId,
@Valid @ModelAttribute CursorPaginationInfoReq pageable
) {
return ResponseEntity.ok()
.body(projectService.getByCreatorId(userId, creatorId, pageable));
}

@GetMapping("{projectId}/{id}")
public ResponseEntity<ProjectDetailAPIRes> getById(
@UserId Long userId, @PathVariable Long projectId, @PathVariable Long id
) {
return ResponseEntity.ok().body(projectService.getByProjectId(userId, id, projectId));
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package io.oeid.mogakgo.domain.project.presentation.dto.res;

import io.oeid.mogakgo.domain.project.domain.entity.Project;
import io.oeid.mogakgo.domain.project.domain.entity.ProjectTag;
import io.oeid.mogakgo.domain.project.domain.entity.enums.ProjectStatus;
import io.oeid.mogakgo.domain.user.domain.UserDevelopLanguageTag;
import io.oeid.mogakgo.domain.user.domain.UserWantedJobTag;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserPublicApiResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
Expand Down Expand Up @@ -46,4 +50,31 @@ public static ProjectDetailAPIRes of(Long projectId, UserPublicApiResponse creat
meetingInfo
);
}

public static ProjectDetailAPIRes from(Project project) {
return ProjectDetailAPIRes.of(project.getId(),
new UserPublicApiResponse(
project.getCreator().getId(),
project.getCreator().getUsername(),
project.getCreator().getGithubId(),
project.getCreator().getAvatarUrl(),
project.getCreator().getGithubUrl(),
project.getCreator().getBio(),
project.getCreator().getJandiRate(),
project.getCreator().getAchievement() != null ? project.getCreator()
.getAchievement().getTitle() : null,
project.getCreator().getUserDevelopLanguageTags().stream().map(
UserDevelopLanguageTag::getDevelopLanguage).map(String::valueOf).toList(),
project.getCreator().getUserWantedJobTags().stream().map(
UserWantedJobTag::getWantedJob).map(String::valueOf).toList()
),
project.getProjectStatus(),
project.getProjectTags().stream().map(ProjectTag::getContent).toList(),
new MeetingInfoResponse(
project.getMeetingInfo().getMeetStartTime(),
project.getMeetingInfo().getMeetEndTime(),
project.getMeetingInfo().getMeetDetail()
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.oeid.mogakgo.domain.project.presentation.dto.res;

import io.oeid.mogakgo.domain.project.domain.entity.enums.ProjectStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Schema(description = "사용자가 생성한 프로젝트 리스트 조회 응답 DTO")
@Getter
@AllArgsConstructor
public class ProjectInfoAPIRes {

@Schema(description = "생성한 프로젝트 ID", example = "11", implementation = Long.class)
@NotNull
private final Long projectId;

@Schema(description = "프로젝트 상태")
@NotNull
private final ProjectStatus projectStatus;

@Schema(description = "프로젝트 생성자 Url")
@NotNull
private final String creatorAvatorUrl;

@Schema(description = "프로젝트 위치 상세")
@NotNull
private final String projectLocationDetail;

@Schema(description = "프로젝트 시작 시간")
@NotNull
private final LocalDateTime projectStartTime;

@Schema(description = "프로젝트 종료 시간")
@NotNull
private final LocalDateTime projectEndTime;
}
Loading