Skip to content

Commit

Permalink
Merge pull request #60 from sukjuhong/feature/sukjuhong/resume-announ…
Browse files Browse the repository at this point in the history
…cement

feature: 이력서 공고 기능 구현
  • Loading branch information
mclub4 authored May 19, 2024
2 parents 1b486d7 + 2e83923 commit b75cac5
Show file tree
Hide file tree
Showing 38 changed files with 495 additions and 247 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.eumserver.domain.team.announcement.domain;
package com.example.eumserver.domain.announcement.filter.domain;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.eumserver.domain.team.announcement.domain;
package com.example.eumserver.domain.announcement.filter.domain;

/**
* 모집 공고의 모집 유형을 나타낸 Enum Class 입니다.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.example.eumserver.domain.announcement.resume.controller;

import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementFilter;
import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementRequest;
import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementResponse;
import com.example.eumserver.domain.announcement.resume.service.ResumeAnnouncementService;
import com.example.eumserver.global.dto.ApiResult;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/resume-announcement")
@RequiredArgsConstructor
public class ResumeAnnouncementController {

private final ResumeAnnouncementService resumeAnnouncementService;

@PostMapping("")
@ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<ApiResult<?>> createResumeAnnouncement(
@RequestBody ResumeAnnouncementRequest request) {
resumeAnnouncementService.publishResume(request);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(new ApiResult<>("이력서 공고 생성"));
}

@DeleteMapping("/{resumeAnnouncementId}")
public ResponseEntity<ApiResult<?>> deleteResumeAnnouncement(
@PathVariable Long resumeAnnouncementId) {
resumeAnnouncementService.unpublishResume(resumeAnnouncementId);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(new ApiResult<>("이력서 공고 생성"));
}

@GetMapping("")
public ResponseEntity<ApiResult<Page<ResumeAnnouncementResponse>>> getResumeAnnouncements(
@RequestBody ResumeAnnouncementFilter filter,
@RequestParam(name = "page", defaultValue = "0") int page
) {
Page<ResumeAnnouncementResponse> resumeAnnouncementResponses = resumeAnnouncementService.getResumeAnnouncements(filter, page);
return ResponseEntity.ok(new ApiResult<>("이력서 공고 필터링 및 페이징 조회 성공", resumeAnnouncementResponses));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.example.eumserver.domain.announcement.resume.domain;

import com.example.eumserver.domain.announcement.filter.domain.OccupationClassification;
import com.example.eumserver.domain.resume.entity.Resume;
import com.example.eumserver.global.dto.TimeStamp;
import jakarta.persistence.*;
import lombok.*;

import java.util.List;

@Entity
@Table(name = "resume_announcements")
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class ResumeAnnouncement {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "resume_announcement_id")
private Long id;

@Column(nullable = false)
private String introduction;

@ElementCollection(targetClass = OccupationClassification.class)
@Enumerated(EnumType.STRING)
private List<OccupationClassification> occupationClassifications;

@Setter
@OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
@JoinColumn(name = "resume_id")
private Resume resume;

@Embedded
private TimeStamp timeStamp;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.eumserver.domain.announcement.resume.dto;

import com.example.eumserver.domain.announcement.filter.domain.OccupationClassification;

import java.util.List;

public record ResumeAnnouncementFilter(
List<OccupationClassification> occupationClassifications
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.eumserver.domain.announcement.resume.dto;

public record ResumeAnnouncementRequest(
Long resumeId,
String introduction
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.eumserver.domain.announcement.resume.dto;

import com.example.eumserver.domain.announcement.filter.domain.OccupationClassification;

import java.util.List;

public record ResumeAnnouncementResponse(
Long id,
Long resumeId,
String introduction,
List<OccupationClassification> occupationClassifications
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.eumserver.domain.announcement.resume.mapper;

import com.example.eumserver.domain.announcement.resume.domain.ResumeAnnouncement;
import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementRequest;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface ResumeAnnouncementMapper {

ResumeAnnouncementMapper INSTANCE = Mappers.getMapper(ResumeAnnouncementMapper.class);

@Mapping(target = "id", ignore = true)
@Mapping(target = "resume", ignore = true)
ResumeAnnouncement requestToEntity(ResumeAnnouncementRequest resumeAnnouncementRequest);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.eumserver.domain.announcement.resume.repository;

import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementFilter;
import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface ResumeAnnouncementCustomRepository {

Page<ResumeAnnouncementResponse> findResumeAnnouncementsWithFilteredAndPagination(ResumeAnnouncementFilter filter, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.example.eumserver.domain.announcement.resume.repository;

import com.example.eumserver.domain.announcement.filter.domain.OccupationClassification;
import com.example.eumserver.domain.announcement.resume.domain.QResumeAnnouncement;
import com.example.eumserver.domain.announcement.resume.domain.ResumeAnnouncement;
import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementFilter;
import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementResponse;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
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 java.util.List;

@Repository
@RequiredArgsConstructor
public class ResumeAnnouncementCustomRepositoryImpl implements ResumeAnnouncementCustomRepository {

private final JPAQueryFactory queryFactory;

@Override
public Page<ResumeAnnouncementResponse> findResumeAnnouncementsWithFilteredAndPagination(ResumeAnnouncementFilter filter, Pageable pageable) {

QResumeAnnouncement resumeAnnouncement = QResumeAnnouncement.resumeAnnouncement;
BooleanExpression predicate = resumeAnnouncement.isNotNull();

List<OccupationClassification> occupationClassifications = filter.occupationClassifications();
if (occupationClassifications != null && !occupationClassifications.isEmpty()) {
predicate = predicate.and(resumeAnnouncement.occupationClassifications.any().in(occupationClassifications));
}

List<ResumeAnnouncement> announcements = queryFactory
.select(resumeAnnouncement)
.where(predicate)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();

List<ResumeAnnouncementResponse> resumeAnnouncementResponses = announcements.stream()
.map(announcement ->
new ResumeAnnouncementResponse(
announcement.getId(),
announcement.getResume().getId(),
announcement.getIntroduction(),
announcement.getOccupationClassifications())).toList();

JPAQuery<Long> count = queryFactory
.select(resumeAnnouncement.count())
.from(resumeAnnouncement)
.where(predicate);

return PageableExecutionUtils.getPage(resumeAnnouncementResponses, pageable, count::fetchOne);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.example.eumserver.domain.announcement.resume.repository;

import com.example.eumserver.domain.announcement.resume.domain.ResumeAnnouncement;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ResumeAnnouncementRepository extends JpaRepository<ResumeAnnouncement, Long>, ResumeAnnouncementCustomRepository { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.example.eumserver.domain.announcement.resume.service;

import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementFilter;
import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementResponse;
import com.example.eumserver.domain.announcement.resume.mapper.ResumeAnnouncementMapper;
import com.example.eumserver.domain.announcement.resume.repository.ResumeAnnouncementRepository;
import com.example.eumserver.domain.resume.ResumeRepository;
import com.example.eumserver.domain.announcement.resume.domain.ResumeAnnouncement;
import com.example.eumserver.domain.announcement.resume.dto.ResumeAnnouncementRequest;
import com.example.eumserver.domain.resume.entity.Resume;
import com.example.eumserver.global.error.exception.CustomException;
import com.example.eumserver.global.error.exception.ErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ResumeAnnouncementService {

private final ResumeRepository resumeRepository;
private final ResumeAnnouncementRepository resumeAnnouncementRepository;

public void publishResume(ResumeAnnouncementRequest resumeAnnouncementRequest) {
Resume resume = resumeRepository.findById(resumeAnnouncementRequest.resumeId())
.orElseThrow(() -> new CustomException(ErrorCode.RESUME_NOT_FOUND));

ResumeAnnouncement resumeAnnouncement = ResumeAnnouncementMapper.INSTANCE
.requestToEntity(resumeAnnouncementRequest);
resumeAnnouncement.setResume(resume);
resumeAnnouncementRepository.save(resumeAnnouncement);
}

public void unpublishResume(Long resumeAnnouncementId) {
ResumeAnnouncement resumeAnnouncement = resumeAnnouncementRepository.findById(resumeAnnouncementId)
.orElseThrow(() -> new CustomException(ErrorCode.RESUME_ANNOUNCEMENT_NOT_FOUND));
resumeAnnouncementRepository.delete(resumeAnnouncement);
}

public Page<ResumeAnnouncementResponse> getResumeAnnouncements(ResumeAnnouncementFilter filter, int page) {
List<Sort.Order> sorts = new ArrayList<>();
sorts.add(Sort.Order.desc("date_created"));
Pageable pageable = PageRequest.of(page, 12, Sort.by(sorts));
return resumeRepository.findResumeAnnouncementsWithFilteredAndPagination(filter, pageable);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.example.eumserver.domain.team.announcement.controller;
package com.example.eumserver.domain.announcement.team.controller;

import com.example.eumserver.domain.team.announcement.domain.Announcement;
import com.example.eumserver.domain.team.announcement.dto.AnnouncementFilter;
import com.example.eumserver.domain.team.announcement.dto.AnnouncementRequest;
import com.example.eumserver.domain.team.announcement.dto.AnnouncementResponse;
import com.example.eumserver.domain.team.announcement.dto.AnnouncementUpdateRequest;
import com.example.eumserver.domain.team.announcement.mapper.AnnouncementMapper;
import com.example.eumserver.domain.team.announcement.service.AnnouncementService;
import com.example.eumserver.domain.announcement.team.domain.TeamAnnouncement;
import com.example.eumserver.domain.announcement.team.dto.TeamAnnouncementFilter;
import com.example.eumserver.domain.announcement.team.dto.TeamAnnouncementRequest;
import com.example.eumserver.domain.announcement.team.dto.TeamAnnouncementResponse;
import com.example.eumserver.domain.announcement.team.dto.TeamAnnouncementUpdateRequest;
import com.example.eumserver.domain.announcement.team.mapper.TeamAnnouncementMapper;
import com.example.eumserver.domain.announcement.team.service.TeamAnnouncementService;
import com.example.eumserver.global.dto.ApiResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -19,46 +19,46 @@
@RestController
@RequestMapping("/api/team/{teamId}/announcement")
@RequiredArgsConstructor
public class AnnouncementController {
public class TeamAnnouncementController {

private final AnnouncementService announcementService;
private final TeamAnnouncementService announcementService;

@PostMapping("")
@ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<ApiResult<AnnouncementResponse>> createAnnouncement(
public ResponseEntity<ApiResult<TeamAnnouncementResponse>> createAnnouncement(
@PathVariable(name = "teamId") Long teamId,
@RequestBody AnnouncementRequest announcementRequest
@RequestBody TeamAnnouncementRequest announcementRequest
) {
log.debug("announcement request: {}", announcementRequest);
AnnouncementResponse announcementResponse = announcementService.createAnnouncement(teamId, announcementRequest);
TeamAnnouncementResponse announcementResponse = announcementService.createAnnouncement(teamId, announcementRequest);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(new ApiResult<>("팀 공고 생성 성공", announcementResponse));
}

@GetMapping("")
public ResponseEntity<ApiResult<Page<AnnouncementResponse>>> getAnnouncements(
public ResponseEntity<ApiResult<Page<TeamAnnouncementResponse>>> getAnnouncements(
@PathVariable(name = "teamId") Long teamId,
@RequestParam(name = "page", defaultValue = "0") Integer page,
@RequestBody AnnouncementFilter announcementFilter
@RequestBody TeamAnnouncementFilter announcementFilter
) {
Page<AnnouncementResponse> filteredAnnouncementsWithPaging = announcementService.getFilteredAnnouncementsWithPaging(teamId, page, announcementFilter);
Page<TeamAnnouncementResponse> filteredAnnouncementsWithPaging = announcementService.getFilteredAnnouncementsWithPaging(teamId, page, announcementFilter);
return ResponseEntity
.ok(new ApiResult<>("팀 공고 필터링 및 페이징 조회 성공", filteredAnnouncementsWithPaging));
}

@GetMapping("/{announcementId}")
public ResponseEntity<ApiResult<AnnouncementResponse>> getAnnouncement(@PathVariable(name = "announcementId") Long announcementId) {
Announcement announcement = announcementService.findAnnouncementById(announcementId);
AnnouncementResponse announcementResponse = AnnouncementMapper.INSTANCE.entityToResponse(announcement);
public ResponseEntity<ApiResult<TeamAnnouncementResponse>> getAnnouncement(@PathVariable(name = "announcementId") Long announcementId) {
TeamAnnouncement announcement = announcementService.findAnnouncementById(announcementId);
TeamAnnouncementResponse announcementResponse = TeamAnnouncementMapper.INSTANCE.entityToResponse(announcement);
return ResponseEntity
.ok(new ApiResult<>("팀 공고 조회 성공", announcementResponse));
}

@PutMapping("/{announcementId}")
public ResponseEntity<ApiResult<?>> updateAnnouncement(
@PathVariable(name = "announcementId") Long announcementId,
@RequestBody AnnouncementUpdateRequest announcementUpdateRequest
@RequestBody TeamAnnouncementUpdateRequest announcementUpdateRequest
) {
announcementService.updateAnnouncement(announcementId, announcementUpdateRequest);
return ResponseEntity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.example.eumserver.domain.team.announcement.domain;
package com.example.eumserver.domain.announcement.team.domain;

import com.example.eumserver.domain.announcement.filter.domain.OccupationClassification;
import com.example.eumserver.domain.announcement.team.dto.TeamAnnouncementUpdateRequest;
import com.example.eumserver.domain.team.Team;
import com.example.eumserver.domain.team.announcement.dto.AnnouncementUpdateRequest;
import com.example.eumserver.global.dto.TimeStamp;
import jakarta.persistence.*;
import lombok.*;
Expand All @@ -15,7 +16,7 @@
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Announcement {
public class TeamAnnouncement {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down Expand Up @@ -59,7 +60,7 @@ public boolean isPublished() {
return this.publishedDate != null;
}

public void updateAnnouncement(AnnouncementUpdateRequest announcementUpdateRequest) {
public void updateAnnouncement(TeamAnnouncementUpdateRequest announcementUpdateRequest) {
this.title = announcementUpdateRequest.title();
this.description = announcementUpdateRequest.description();
this.vacancies = announcementUpdateRequest.vacancies();
Expand Down
Loading

0 comments on commit b75cac5

Please sign in to comment.