diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/api/PostManagementApi.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/api/PostManagementApi.java index bb538dd6..f3f99abe 100644 --- a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/api/PostManagementApi.java +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/api/PostManagementApi.java @@ -5,6 +5,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; import org.springframework.web.bind.annotation.RequestParam; import synk.meeteam.domain.recruitment.recruitment_post.dto.response.SimpleRecruitmentPostDto; import synk.meeteam.domain.user.user.entity.User; @@ -21,6 +23,8 @@ public interface PostManagementApi { @Operation(summary = "북마크한 구인글 조회") @SecurityRequirement(name = "Authorization") PageNationDto getBookmarkPost(@AuthUser User user, + @RequestParam(value = "size", required = false, defaultValue = "24") @Valid @Min(1) int size, + @RequestParam(value = "page", required = false, defaultValue = "1") @Valid @Min(1) int page, @RequestParam(value = "is-closed", required = false) Boolean isClosed); @ApiResponses( @@ -31,6 +35,8 @@ PageNationDto getBookmarkPost(@AuthUser User user, @Operation(summary = "내가 신청한 구인글 조회") @SecurityRequirement(name = "Authorization") PageNationDto getAppliedPost(@AuthUser User user, + @RequestParam(value = "size", required = false, defaultValue = "24") @Valid @Min(1) int size, + @RequestParam(value = "page", required = false, defaultValue = "1") @Valid @Min(1) int page, @RequestParam(value = "is-closed", required = false) Boolean isClosed); @ApiResponses( @@ -41,5 +47,7 @@ PageNationDto getAppliedPost(@AuthUser User user, @Operation(summary = "내가 작성한 구인글 조회") @SecurityRequirement(name = "Authorization") PageNationDto getMyPost(@AuthUser User user, + @RequestParam(value = "size", required = false, defaultValue = "24") @Valid @Min(1) int size, + @RequestParam(value = "page", required = false, defaultValue = "1") @Valid @Min(1) int page, @RequestParam(value = "is-closed", required = false) Boolean isClosed); } diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/api/PostManagementController.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/api/PostManagementController.java index dfb62a41..495ea35c 100644 --- a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/api/PostManagementController.java +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/api/PostManagementController.java @@ -1,14 +1,15 @@ package synk.meeteam.domain.recruitment.recruitment_post.api; -import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import synk.meeteam.domain.recruitment.recruitment_post.dto.response.SimpleRecruitmentPostDto; +import synk.meeteam.domain.recruitment.recruitment_post.service.RecruitmentPostService; import synk.meeteam.domain.user.user.entity.User; -import synk.meeteam.global.dto.PageInfo; import synk.meeteam.global.dto.PageNationDto; import synk.meeteam.security.AuthUser; @@ -17,60 +18,32 @@ @RequestMapping("/management") public class PostManagementController implements PostManagementApi { + private final RecruitmentPostService recruitmentPostService; + @GetMapping("/bookmark") @Override public PageNationDto getBookmarkPost(@AuthUser User user, + @RequestParam(value = "size", required = false, defaultValue = "24") @Valid @Min(1) int size, + @RequestParam(value = "page", required = false, defaultValue = "1") @Valid @Min(1) int page, @RequestParam(value = "is-closed", required = false) Boolean isClosed) { - return new PageNationDto( - List.of(new SimpleRecruitmentPostDto( - 1L, - "같이할사람 구합니다.", - "프로젝트", - "goder", - "https://img.png", - "2021-12-15", - "교외", - true - )), - new PageInfo(1, 24, 1L, 1) - ); + return recruitmentPostService.getBookmarkPost(size, page, user, isClosed); } @GetMapping("/applied") @Override public PageNationDto getAppliedPost(@AuthUser User user, + @RequestParam(value = "size", required = false, defaultValue = "24") @Valid @Min(1) int size, + @RequestParam(value = "page", required = false, defaultValue = "1") @Valid @Min(1) int page, @RequestParam(value = "is-closed", required = false) Boolean isClosed) { - return new PageNationDto( - List.of(new SimpleRecruitmentPostDto( - 1L, - "같이할사람 구합니다.", - "프로젝트", - "goder", - "https://img.png", - "2021-12-15", - "교외", - true - )), - new PageInfo(1, 24, 1L, 1) - ); + return recruitmentPostService.getAppliedPost(size, page, user, isClosed); } @GetMapping("/myPost") @Override public PageNationDto getMyPost(@AuthUser User user, + @RequestParam(value = "size", required = false, defaultValue = "24") @Valid @Min(1) int size, + @RequestParam(value = "page", required = false, defaultValue = "1") @Valid @Min(1) int page, @RequestParam(value = "is-closed", required = false) Boolean isClosed) { - return new PageNationDto( - List.of(new SimpleRecruitmentPostDto( - 1L, - "같이할사람 구합니다.", - "프로젝트", - "goder", - "https://img.png", - "2021-12-15", - "교외", - true - )), - new PageInfo(1, 24, 1L, 1) - ); + return recruitmentPostService.getMyPost(size, page, user, isClosed); } } diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/dto/SimpleRecruitmentPostMapper.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/dto/SimpleRecruitmentPostMapper.java index ab469333..467bc42a 100644 --- a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/dto/SimpleRecruitmentPostMapper.java +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/dto/SimpleRecruitmentPostMapper.java @@ -9,5 +9,8 @@ public interface SimpleRecruitmentPostMapper { @Mapping(target = "category", expression = "java(recruitmentPostVo.getCategory().getName())") @Mapping(target = "scope", expression = "java(recruitmentPostVo.getScope().getName())") - SimpleRecruitmentPostDto toSimpleRecruitmentPostDto(RecruitmentPostVo recruitmentPostVo); + @Mapping(target = "writerProfileImg", source = "writerProfileImg") + @Mapping(target = "writerId", source = "writerId") + SimpleRecruitmentPostDto toSimpleRecruitmentPostDto(RecruitmentPostVo recruitmentPostVo, String writerId, + String writerProfileImg); } diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/dto/response/SimpleRecruitmentPostDto.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/dto/response/SimpleRecruitmentPostDto.java index f54d0d36..aa8494f3 100644 --- a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/dto/response/SimpleRecruitmentPostDto.java +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/dto/response/SimpleRecruitmentPostDto.java @@ -9,6 +9,8 @@ public record SimpleRecruitmentPostDto( String title, @Schema(description = "유형", example = "프로젝트") String category, + @Schema(description = "작성자 id", example = "sdfkljwncxmv") + String writerId, @Schema(description = "작성자 닉네임", example = "song123") String writerNickname, @Schema(description = "작성자 사진", example = "url 형태") @@ -18,6 +20,8 @@ public record SimpleRecruitmentPostDto( @Schema(description = "범위", example = "교내") String scope, @Schema(description = "북마크 여부", example = "true") - Boolean isBookmarked + Boolean isBookmarked, + @Schema(description = "마감 여부", example = "true") + Boolean isClosed ) { } diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentManagementRepository.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentManagementRepository.java new file mode 100644 index 00000000..db61eaac --- /dev/null +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentManagementRepository.java @@ -0,0 +1,15 @@ +package synk.meeteam.domain.recruitment.recruitment_post.repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import synk.meeteam.domain.recruitment.recruitment_post.repository.vo.RecruitmentPostVo; +import synk.meeteam.domain.user.user.entity.User; + +public interface RecruitmentManagementRepository { + Page findMyBookmarkPost(Pageable pageable, User user, Boolean isClosed); + + Page findMyAppliedPost(Pageable pageable, User user, Boolean isClosed); + + Page findMyPost(Pageable pageable, User user, Boolean isClosed); + +} diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentManagementRepositoryImpl.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentManagementRepositoryImpl.java new file mode 100644 index 00000000..c32e1acc --- /dev/null +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentManagementRepositoryImpl.java @@ -0,0 +1,184 @@ +package synk.meeteam.domain.recruitment.recruitment_post.repository; + +import static synk.meeteam.domain.recruitment.bookmark.entity.QBookmark.bookmark; +import static synk.meeteam.domain.recruitment.recruitment_applicant.entity.QRecruitmentApplicant.recruitmentApplicant; +import static synk.meeteam.domain.recruitment.recruitment_post.entity.QRecruitmentPost.recruitmentPost; +import static synk.meeteam.domain.recruitment.recruitment_post.repository.expression.ExpressionUtils.isClosedEq; + +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.impl.JPAQuery; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; +import org.springframework.stereotype.Repository; +import synk.meeteam.domain.recruitment.recruitment_post.repository.vo.QRecruitmentPostVo; +import synk.meeteam.domain.recruitment.recruitment_post.repository.vo.RecruitmentPostVo; +import synk.meeteam.domain.user.user.entity.QUser; +import synk.meeteam.domain.user.user.entity.User; + +@Repository +@RequiredArgsConstructor +public class RecruitmentManagementRepositoryImpl implements RecruitmentManagementRepository { + private final JPAQueryFactory queryFactory; + + @Override + public Page findMyBookmarkPost(Pageable pageable, User user, Boolean isClosed) { + List contents = getBookmarkPostVos(pageable, user, isClosed); + JPAQuery countQuery = getBookmarkCount(user, isClosed); + return PageableExecutionUtils.getPage(contents, pageable, countQuery::fetchOne); + } + + @Override + public Page findMyAppliedPost(Pageable pageable, User user, Boolean isClosed) { + List contents = getAppliedPostVos(pageable, user, isClosed); + JPAQuery countQuery = getAppliedCount(user, isClosed); + return PageableExecutionUtils.getPage(contents, pageable, countQuery::fetchOne); + } + + @Override + public Page findMyPost(Pageable pageable, User user, Boolean isClosed) { + List contents = getMyPostVos(pageable, user, isClosed); + JPAQuery countQuery = getMyPostCount(user, isClosed); + return PageableExecutionUtils.getPage(contents, pageable, countQuery::fetchOne); + } + + private List getBookmarkPostVos(Pageable pageable, User userDomain, Boolean isClosed) { + QUser writer = new QUser("writer"); + + JPAQuery query = queryFactory.select( + new QRecruitmentPostVo( + recruitmentPost.id, + recruitmentPost.title, + recruitmentPost.category, + recruitmentPost.scope, + writer.id, + writer.nickname, + writer.profileImgFileName, + recruitmentPost.deadline, + Expressions.asBoolean(true), + recruitmentPost.createdAt, + recruitmentPost.isClosed + ) + ) + .distinct() + .from(recruitmentPost) + .leftJoin(writer).on(recruitmentPost.createdBy.eq(writer.id)) + .leftJoin(bookmark).on(recruitmentPost.id.eq(bookmark.recruitmentPost.id)) + .where( + isClosedEq(isClosed), + bookmark.user.id.eq(userDomain.getId()) + ); + + return query.orderBy(recruitmentPost.createdAt.desc(), recruitmentPost.id.desc()) + .offset(pageable.getOffset()) //페이지 번호 + .limit(pageable.getPageSize()) //페이지 사이즈 + .fetch(); + } + + private List getAppliedPostVos(Pageable pageable, User userDomain, Boolean isClosed) { + QUser writer = new QUser("writer"); + + JPAQuery query = queryFactory.select( + new QRecruitmentPostVo( + recruitmentPost.id, + recruitmentPost.title, + recruitmentPost.category, + recruitmentPost.scope, + writer.id, + writer.nickname, + writer.profileImgFileName, + recruitmentPost.deadline, + Expressions.asBoolean(true), + recruitmentPost.createdAt, + recruitmentPost.isClosed + ) + ) + .distinct() + .from(recruitmentPost) + .leftJoin(writer).on(recruitmentPost.createdBy.eq(writer.id)) + .leftJoin(recruitmentApplicant).on(recruitmentPost.id.eq(recruitmentApplicant.recruitmentPost.id)) + .where( + isClosedEq(isClosed), + recruitmentApplicant.applicant.id.eq(userDomain.getId()) + ); + + return query.orderBy(recruitmentPost.createdAt.desc(), recruitmentPost.id.desc()) + .offset(pageable.getOffset()) //페이지 번호 + .limit(pageable.getPageSize()) //페이지 사이즈 + .fetch(); + } + + private List getMyPostVos(Pageable pageable, User userDomain, Boolean isClosed) { + QUser writer = new QUser("writer"); + + JPAQuery query = queryFactory.select( + new QRecruitmentPostVo( + recruitmentPost.id, + recruitmentPost.title, + recruitmentPost.category, + recruitmentPost.scope, + writer.id, + writer.nickname, + writer.profileImgFileName, + recruitmentPost.deadline, + Expressions.asBoolean(true), + recruitmentPost.createdAt, + recruitmentPost.isClosed + ) + ) + .distinct() + .from(recruitmentPost) + .leftJoin(writer).on(recruitmentPost.createdBy.eq(writer.id)) + .where( + isClosedEq(isClosed), + writer.id.eq(userDomain.getId()) + ); + + return query.orderBy(recruitmentPost.createdAt.desc(), recruitmentPost.id.desc()) + .offset(pageable.getOffset()) //페이지 번호 + .limit(pageable.getPageSize()) //페이지 사이즈 + .fetch(); + } + + private JPAQuery getBookmarkCount(User userDomain, Boolean isClosed) { + QUser writer = new QUser("writer"); + + return queryFactory.select(recruitmentPost.countDistinct()) + .from(recruitmentPost) + .leftJoin(writer).on(recruitmentPost.createdBy.eq(writer.id)) + .leftJoin(bookmark).on(recruitmentPost.id.eq(bookmark.recruitmentPost.id)) + .where( + isClosedEq(isClosed), + bookmark.user.id.eq(userDomain.getId()) + ); + } + + private JPAQuery getAppliedCount(User userDomain, Boolean isClosed) { + QUser writer = new QUser("writer"); + + return queryFactory.select(recruitmentPost.countDistinct()) + .from(recruitmentPost) + .leftJoin(writer).on(recruitmentPost.createdBy.eq(writer.id)) + .leftJoin(recruitmentApplicant).on(recruitmentPost.id.eq(recruitmentApplicant.recruitmentPost.id)) + .where( + isClosedEq(isClosed), + recruitmentApplicant.applicant.id.eq(userDomain.getId()) + ); + } + + private JPAQuery getMyPostCount(User userDomain, Boolean isClosed) { + QUser writer = new QUser("writer"); + + return queryFactory.select(recruitmentPost.countDistinct()) + .from(recruitmentPost) + .leftJoin(writer).on(recruitmentPost.createdBy.eq(writer.id)) + .where( + isClosedEq(isClosed), + writer.id.eq(userDomain.getId()) + ); + } + +} diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentPostRepository.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentPostRepository.java index 73c0ade9..ad9bdd6a 100644 --- a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentPostRepository.java +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentPostRepository.java @@ -7,7 +7,7 @@ import synk.meeteam.domain.recruitment.recruitment_post.exception.RecruitmentPostException; public interface RecruitmentPostRepository extends JpaRepository, - RecruitmentPostSearchRepository { + RecruitmentPostSearchRepository, RecruitmentManagementRepository { default RecruitmentPost findByIdOrElseThrow(Long postId) { return findById(postId).orElseThrow(() -> new RecruitmentPostException(NOT_FOUND_POST)); diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentPostSearchRepositoryImpl.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentPostSearchRepositoryImpl.java index 5c6feaa1..7b5d26f1 100644 --- a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentPostSearchRepositoryImpl.java +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/RecruitmentPostSearchRepositoryImpl.java @@ -1,20 +1,21 @@ package synk.meeteam.domain.recruitment.recruitment_post.repository; -import static com.querydsl.jpa.JPAExpressions.selectOne; import static synk.meeteam.domain.common.course.entity.QCourse.course; import static synk.meeteam.domain.common.course.entity.QProfessor.professor; import static synk.meeteam.domain.common.field.entity.QField.field; import static synk.meeteam.domain.common.role.entity.QRole.role; import static synk.meeteam.domain.common.skill.entity.QSkill.skill; import static synk.meeteam.domain.common.tag.entity.QTag.tag; -import static synk.meeteam.domain.recruitment.bookmark.entity.QBookmark.bookmark; import static synk.meeteam.domain.recruitment.recruitment_post.entity.QRecruitmentPost.recruitmentPost; +import static synk.meeteam.domain.recruitment.recruitment_post.repository.expression.ExpressionUtils.categoryEq; +import static synk.meeteam.domain.recruitment.recruitment_post.repository.expression.ExpressionUtils.isBookmark; +import static synk.meeteam.domain.recruitment.recruitment_post.repository.expression.ExpressionUtils.scopeEq; +import static synk.meeteam.domain.recruitment.recruitment_post.repository.expression.ExpressionUtils.titleStartWith; +import static synk.meeteam.domain.recruitment.recruitment_post.repository.expression.ExpressionUtils.writerUniversityEq; import static synk.meeteam.domain.recruitment.recruitment_role.entity.QRecruitmentRole.recruitmentRole; import static synk.meeteam.domain.recruitment.recruitment_role_skill.entity.QRecruitmentRoleSkill.recruitmentRoleSkill; import static synk.meeteam.domain.recruitment.recruitment_tag.entity.QRecruitmentTag.recruitmentTag; -import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.core.types.dsl.Expressions; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; @@ -29,7 +30,6 @@ import synk.meeteam.domain.recruitment.recruitment_post.repository.vo.RecruitmentPostVo; import synk.meeteam.domain.user.user.entity.QUser; import synk.meeteam.domain.user.user.entity.User; -import synk.meeteam.global.entity.Category; import synk.meeteam.global.entity.Scope; @Repository @@ -57,12 +57,14 @@ private List getPostVos(Pageable pageable, SearchCondition co recruitmentPost.id, recruitmentPost.title, recruitmentPost.category, + recruitmentPost.scope, + writer.id, writer.nickname, writer.profileImgFileName, recruitmentPost.deadline, - recruitmentPost.scope, isBookmark(userDomain), - recruitmentPost.createdAt + recruitmentPost.createdAt, + recruitmentPost.isClosed ) ) .distinct() @@ -82,7 +84,7 @@ private List getPostVos(Pageable pageable, SearchCondition co query = jpaUtils.joinWithCourseAndProfessor(query, condition, userDomain); } - return query.orderBy(recruitmentPost.createdAt.desc()) + return query.orderBy(recruitmentPost.createdAt.desc(), recruitmentPost.id.desc()) .offset(pageable.getOffset()) //페이지 번호 .limit(pageable.getPageSize()) //페이지 사이즈 .fetch(); @@ -111,45 +113,6 @@ private JPAQuery getCount(SearchCondition condition, String keyword, User } - //BooleanExpression - private BooleanExpression isBookmark(User userDomain) { - //로그인 안된 경우 - if (userDomain == null) { - return isFalse(); - } - - return selectOne() - .from(bookmark) - .where( - bookmark.user.id.eq(userDomain.getId()), - bookmark.recruitmentPost.id.eq(recruitmentPost.id)) - .exists(); - } - - private BooleanExpression writerUniversityEq(QUser writer, User userDomain, Scope scope) { - return scope != Scope.ON_CAMPUS ? null : writer.university.eq(userDomain.getUniversity()); - } - - private BooleanExpression categoryEq(Category category) { - return category == null ? null : recruitmentPost.category.eq(category); - } - - private BooleanExpression scopeEq(Scope scope) { - if (scope == null) { - return null; - } else { - return recruitmentPost.scope.eq(scope); - } - } - - private BooleanExpression titleStartWith(String keyword) { - return (keyword == null || keyword.isEmpty()) ? null : recruitmentPost.title.startsWith(keyword); - } - - private BooleanExpression isFalse() { - return Expressions.asBoolean(false); - } - static class jpaUtils { public static JPAQuery joinWithFieldAndTagAndRoleAndSkill(JPAQuery query, SearchCondition condition) { //분야 diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/expression/ExpressionUtils.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/expression/ExpressionUtils.java new file mode 100644 index 00000000..8f1aa7ab --- /dev/null +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/expression/ExpressionUtils.java @@ -0,0 +1,57 @@ +package synk.meeteam.domain.recruitment.recruitment_post.repository.expression; + +import static com.querydsl.jpa.JPAExpressions.selectOne; +import static synk.meeteam.domain.recruitment.bookmark.entity.QBookmark.bookmark; +import static synk.meeteam.domain.recruitment.recruitment_post.entity.QRecruitmentPost.recruitmentPost; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.Expressions; +import synk.meeteam.domain.user.user.entity.QUser; +import synk.meeteam.domain.user.user.entity.User; +import synk.meeteam.global.entity.Category; +import synk.meeteam.global.entity.Scope; + +public class ExpressionUtils { + //BooleanExpression + public static BooleanExpression isBookmark(User userDomain) { + //로그인 안된 경우 + if (userDomain == null) { + return isFalse(); + } + + return selectOne() + .from(bookmark) + .where( + bookmark.user.id.eq(userDomain.getId()), + bookmark.recruitmentPost.id.eq(recruitmentPost.id)) + .exists(); + } + + public static BooleanExpression isClosedEq(Boolean isClosed) { + return isClosed == null ? null : recruitmentPost.isClosed.eq(isClosed); + } + + public static BooleanExpression writerUniversityEq(QUser writer, User userDomain, Scope scope) { + return scope != Scope.ON_CAMPUS ? null : writer.university.eq(userDomain.getUniversity()); + } + + public static BooleanExpression categoryEq(Category category) { + return category == null ? null : recruitmentPost.category.eq(category); + } + + public static BooleanExpression scopeEq(Scope scope) { + if (scope == null) { + return null; + } else { + return recruitmentPost.scope.eq(scope); + } + } + + public static BooleanExpression titleStartWith(String keyword) { + return (keyword == null || keyword.isEmpty()) ? null : recruitmentPost.title.startsWith(keyword); + } + + private static BooleanExpression isFalse() { + return Expressions.asBoolean(false); + } +} diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/vo/RecruitmentPostVo.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/vo/RecruitmentPostVo.java index 4ca6e5fc..c565afa4 100644 --- a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/vo/RecruitmentPostVo.java +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/repository/vo/RecruitmentPostVo.java @@ -14,24 +14,30 @@ public class RecruitmentPostVo { private String title; private Category category; private Scope scope; + private Long writerId; private String writerNickname; private String writerProfileImg; private LocalDate deadline; private Boolean isBookmarked; private LocalDateTime createdAt; + private Boolean isClosed; @Builder @QueryProjection - public RecruitmentPostVo(Long id, String title, Category category, String writerNickname, String writerProfileImg, - LocalDate deadline, Scope scope, Boolean isBookmarked, LocalDateTime createdAt) { + public RecruitmentPostVo(Long id, String title, Category category, Scope scope, Long writerId, + String writerNickname, + String writerProfileImg, LocalDate deadline, Boolean isBookmarked, LocalDateTime createdAt, + Boolean isClosed) { this.id = id; this.title = title; this.category = category; + this.scope = scope; + this.writerId = writerId; this.writerNickname = writerNickname; this.writerProfileImg = writerProfileImg; this.deadline = deadline; - this.scope = scope; this.isBookmarked = isBookmarked; this.createdAt = createdAt; + this.isClosed = isClosed; } } diff --git a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/service/RecruitmentPostService.java b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/service/RecruitmentPostService.java index 28e4a63a..e74cd3ee 100644 --- a/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/service/RecruitmentPostService.java +++ b/src/main/java/synk/meeteam/domain/recruitment/recruitment_post/service/RecruitmentPostService.java @@ -15,7 +15,11 @@ import synk.meeteam.domain.recruitment.recruitment_post.repository.vo.RecruitmentPostVo; import synk.meeteam.domain.user.user.entity.User; import synk.meeteam.global.dto.PageInfo; +import synk.meeteam.global.dto.PageNationDto; import synk.meeteam.global.entity.Scope; +import synk.meeteam.global.util.Encryption; +import synk.meeteam.infra.s3.S3FileName; +import synk.meeteam.infra.s3.service.S3Service; @Service @RequiredArgsConstructor @@ -23,6 +27,7 @@ public class RecruitmentPostService { private final RecruitmentPostRepository recruitmentPostRepository; private final SimpleRecruitmentPostMapper simpleRecruitmentPostMapper; + private final S3Service s3Service; @Transactional public RecruitmentPost writeRecruitmentPost(RecruitmentPost recruitmentPost) { @@ -92,7 +97,11 @@ public PaginationSearchPostResponseDto searchWithPageRecruitmentPost(int size, i .findBySearchConditionAndKeyword(PageRequest.of(page - 1, size), condition, keyword, user); PageInfo pageInfo = new PageInfo(page, size, postVos.getTotalElements(), postVos.getTotalPages()); List contents = postVos.stream() - .map(simpleRecruitmentPostMapper::toSimpleRecruitmentPostDto).toList(); + .map((postVo) -> { + String writerEncryptedId = Encryption.encryptLong(postVo.getWriterId()); + String imageUrl = s3Service.createPreSignedGetUrl(S3FileName.USER, postVo.getWriterProfileImg()); + return simpleRecruitmentPostMapper.toSimpleRecruitmentPostDto(postVo, writerEncryptedId, imageUrl); + }).toList(); return new PaginationSearchPostResponseDto(contents, pageInfo); } @@ -112,4 +121,46 @@ public void incrementResponseCount(Long postId, Long userId, long responseCount) RecruitmentPost recruitmentPost = recruitmentPostRepository.findByIdOrElseThrow(postId); recruitmentPost.incrementResponseCount(userId, responseCount); } + + @Transactional + public PageNationDto getBookmarkPost(int size, int page, User user, Boolean isClosed) { + Page postVos = recruitmentPostRepository.findMyBookmarkPost(PageRequest.of(page - 1, size), + user, isClosed); + PageInfo pageInfo = new PageInfo(page, size, postVos.getTotalElements(), postVos.getTotalPages()); + List contents = postVos.stream() + .map((postVo) -> { + String writerEncryptedId = Encryption.encryptLong(postVo.getWriterId()); + String imageUrl = s3Service.createPreSignedGetUrl(S3FileName.USER, postVo.getWriterProfileImg()); + return simpleRecruitmentPostMapper.toSimpleRecruitmentPostDto(postVo, writerEncryptedId, imageUrl); + }).toList(); + return new PageNationDto<>(contents, pageInfo); + } + + @Transactional + public PageNationDto getAppliedPost(int size, int page, User user, Boolean isClosed) { + Page postVos = recruitmentPostRepository.findMyAppliedPost(PageRequest.of(page - 1, size), + user, isClosed); + PageInfo pageInfo = new PageInfo(page, size, postVos.getTotalElements(), postVos.getTotalPages()); + List contents = postVos.stream() + .map((postVo) -> { + String writerEncryptedId = Encryption.encryptLong(postVo.getWriterId()); + String imageUrl = s3Service.createPreSignedGetUrl(S3FileName.USER, postVo.getWriterProfileImg()); + return simpleRecruitmentPostMapper.toSimpleRecruitmentPostDto(postVo, writerEncryptedId, imageUrl); + }).toList(); + return new PageNationDto<>(contents, pageInfo); + } + + @Transactional + public PageNationDto getMyPost(int size, int page, User user, Boolean isClosed) { + Page postVos = recruitmentPostRepository.findMyPost(PageRequest.of(page - 1, size), + user, isClosed); + PageInfo pageInfo = new PageInfo(page, size, postVos.getTotalElements(), postVos.getTotalPages()); + List contents = postVos.stream() + .map((postVo) -> { + String writerEncryptedId = Encryption.encryptLong(postVo.getWriterId()); + String imageUrl = s3Service.createPreSignedGetUrl(S3FileName.USER, postVo.getWriterProfileImg()); + return simpleRecruitmentPostMapper.toSimpleRecruitmentPostDto(postVo, writerEncryptedId, imageUrl); + }).toList(); + return new PageNationDto<>(contents, pageInfo); + } } diff --git a/src/test/java/synk/meeteam/domain/recruitment/recruitment_post/RecruitmentPostFixture.java b/src/test/java/synk/meeteam/domain/recruitment/recruitment_post/RecruitmentPostFixture.java index b76483b6..a12276ef 100644 --- a/src/test/java/synk/meeteam/domain/recruitment/recruitment_post/RecruitmentPostFixture.java +++ b/src/test/java/synk/meeteam/domain/recruitment/recruitment_post/RecruitmentPostFixture.java @@ -52,8 +52,10 @@ public static RecruitmentPost createRecruitmentPost_bookmark(Long bookmarkCount) public static PaginationSearchPostResponseDto createPageSearchPostResponseDto() { List simpleRecruitmentPostDtos = List.of( - new SimpleRecruitmentPostDto(1L, "제목", "프로젝트", "작성자", "이미지", "2022-03-03", "교외", true), - new SimpleRecruitmentPostDto(2L, "제목2", "스터디", "작성자", "이미지", "2022-03-03", "교내", false) + new SimpleRecruitmentPostDto(1L, "제목", "프로젝트", "dfjksdewnknv", "작성자", "dfjksdewnknv.png", "2022-03-03", + "교외", true, false), + new SimpleRecruitmentPostDto(2L, "제목2", "스터디", "sdfjkldfwel", "작성자", "dfjksdewnknv.png", "2022-03-03", + "교내", false, false) ); return new PaginationSearchPostResponseDto(simpleRecruitmentPostDtos, new PageInfo(1, 24, 3L, 1)); }