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
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dmu.dasom.api.domain.applicant.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;

import java.time.LocalDateTime;

@AllArgsConstructor
@SuperBuilder
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Schema(name = "ApplicantDetailsResponseDto", description = "지원자 상세 응답 DTO")
public class ApplicantDetailsResponseDto extends ApplicantResponseDto {

@Schema(description = "연락처", example = "010-1234-5678")
private String contact;

@Schema(description = "이메일", example = "[email protected]")
private String email;

@Schema(description = "학년", example = "3")
private int grade;

@Schema(description = "지원 동기", example = "동아리 활동을 통해 새로운 경험을 쌓고 싶어서 지원합니다.")
private String reasonForApply;

@Schema(description = "희망 활동", example = "프로젝트")
private String activityWish;

@Schema(description = "개인정보 처리방침 동의 여부", example = "true")
private Boolean isPrivacyPolicyAgreed;

@Schema(description = "지원일시", example = "2021-10-01T00:00:00")
private LocalDateTime createdAt;

@Schema(description = "수정일시", example = "2021-10-01T00:00:00")
private LocalDateTime updatedAt;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dmu.dasom.api.domain.applicant.dto;

import dmu.dasom.api.domain.applicant.enums.ApplicantStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;

@AllArgsConstructor
@SuperBuilder
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Schema(name = "ApplicantResponseDto", description = "지원자 응답 DTO")
public class ApplicantResponseDto {

@Schema(description = "id", example = "1")
private Long id;

@Schema(description = "이름", example = "홍길동")
private String name;

@Schema(description = "학번", example = "20210000")
private String studentNo;

@Schema(description = "상태", example = "PENDING")
private ApplicantStatus status;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dmu.dasom.api.domain.applicant.dto;

import dmu.dasom.api.domain.applicant.enums.ApplicantStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

@Getter
@Schema(name = "ApplicantStatusUpdateRequestDto", description = "지원자 상태 변경 요청 DTO")
public class ApplicantStatusUpdateRequestDto {

@Schema(description = "상태", example = "DOCUMENT_PASSED")
private ApplicantStatus status;

}
32 changes: 32 additions & 0 deletions src/main/java/dmu/dasom/api/domain/applicant/entity/Applicant.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dmu.dasom.api.domain.applicant.entity;

import dmu.dasom.api.domain.applicant.dto.ApplicantDetailsResponseDto;
import dmu.dasom.api.domain.applicant.dto.ApplicantResponseDto;
import dmu.dasom.api.domain.applicant.enums.ApplicantStatus;
import jakarta.persistence.*;
import jakarta.validation.constraints.*;
Expand All @@ -26,6 +28,10 @@ public class Applicant {
@Id
private Long id;

@Column(name = "name", nullable = false, length = 16)
@Size(max = 16)
private String name;

@Column(name = "student_no", nullable = false, length = 8)
@Pattern(regexp = "^[0-9]{8}$")
@Size(min = 8, max = 8)
Expand Down Expand Up @@ -73,4 +79,30 @@ public void updateStatus(final ApplicantStatus status) {
this.status = status;
}

public ApplicantResponseDto toApplicantResponse() {
return ApplicantResponseDto.builder()
.id(this.id)
.name(this.name)
.studentNo(this.studentNo)
.status(this.status)
.build();
}

public ApplicantDetailsResponseDto toApplicantDetailsResponse() {
return ApplicantDetailsResponseDto.builder()
.id(this.id)
.name(this.name)
.studentNo(this.studentNo)
.contact(this.contact)
.email(this.email)
.grade(this.grade)
.reasonForApply(this.reasonForApply)
.activityWish(this.activityWish)
.isPrivacyPolicyAgreed(this.isPrivacyPolicyAgreed)
.status(this.status)
.createdAt(this.createdAt)
.updatedAt(this.updatedAt)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package dmu.dasom.api.domain.applicant.repository;

import dmu.dasom.api.domain.applicant.entity.Applicant;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface ApplicantRepository extends JpaRepository<Applicant, Long> {

@Query("SELECT a FROM Applicant a ORDER BY a.id DESC")
Page<Applicant> findAllWithPageRequest(final Pageable pageable);

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package dmu.dasom.api.domain.applicant.service;

import dmu.dasom.api.domain.applicant.dto.ApplicantCreateRequestDto;
import dmu.dasom.api.domain.applicant.dto.ApplicantDetailsResponseDto;
import dmu.dasom.api.domain.applicant.dto.ApplicantResponseDto;
import dmu.dasom.api.domain.applicant.dto.ApplicantStatusUpdateRequestDto;
import dmu.dasom.api.global.dto.PageResponse;

public interface ApplicantService {

void apply(final ApplicantCreateRequestDto request);

PageResponse<ApplicantResponseDto> getApplicants(final int page);

ApplicantDetailsResponseDto getApplicant(final Long id);

ApplicantDetailsResponseDto updateApplicantStatus(final Long id, final ApplicantStatusUpdateRequestDto request);

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
package dmu.dasom.api.domain.applicant.service;

import dmu.dasom.api.domain.applicant.dto.ApplicantCreateRequestDto;
import dmu.dasom.api.domain.applicant.dto.ApplicantDetailsResponseDto;
import dmu.dasom.api.domain.applicant.dto.ApplicantResponseDto;
import dmu.dasom.api.domain.applicant.dto.ApplicantStatusUpdateRequestDto;
import dmu.dasom.api.domain.applicant.entity.Applicant;
import dmu.dasom.api.domain.applicant.repository.ApplicantRepository;
import dmu.dasom.api.domain.common.exception.CustomException;
import dmu.dasom.api.domain.common.exception.ErrorCode;
import dmu.dasom.api.global.dto.PageResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class ApplicantServiceImpl implements ApplicantService {

private final static int DEFAULT_PAGE_SIZE = 20;

private final ApplicantRepository applicantRepository;

// 지원자 저장
Expand All @@ -17,4 +28,37 @@ public void apply(final ApplicantCreateRequestDto request) {
applicantRepository.save(request.toEntity());
}

// 지원자 조회
@Override
public PageResponse<ApplicantResponseDto> getApplicants(final int page) {
final Page<Applicant> applicants = applicantRepository.findAllWithPageRequest(PageRequest.of(page, DEFAULT_PAGE_SIZE));

// 조회 조건에 따라 결과가 없을 수 있음
if (applicants.isEmpty())
throw new CustomException(ErrorCode.EMPTY_RESULT);

return PageResponse.from(applicants.map(Applicant::toApplicantResponse));
}

// 지원자 상세 조회
@Override
public ApplicantDetailsResponseDto getApplicant(final Long id) {
return findById(id).toApplicantDetailsResponse();
}

// 지원자 상태 변경
@Override
public ApplicantDetailsResponseDto updateApplicantStatus(final Long id, final ApplicantStatusUpdateRequestDto request) {
final Applicant applicant = findById(id);
applicant.updateStatus(request.getStatus());

return applicant.toApplicantDetailsResponse();
}

// Repository에서 ID로 지원자 조회
private Applicant findById(final Long id) {
return applicantRepository.findById(id)
.orElseThrow(() -> new CustomException(ErrorCode.EMPTY_RESULT));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public enum ErrorCode {
TOKEN_NOT_VALID(400, "C008", "토큰이 올바르지 않습니다."),
INTERNAL_SERVER_ERROR(500, "C009", "서버에 문제가 발생하였습니다."),
NOT_FOUND(404, "C010", "해당 리소스를 찾을 수 없습니다."),
WRITE_FAIL(400, "C011", "데이터를 쓰는데 실패하였습니다.")
WRITE_FAIL(400, "C011", "데이터를 쓰는데 실패하였습니다."),
EMPTY_RESULT(400, "C012", "조회 결과가 없습니다.")
;

private final int status;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dmu.dasom.api.domain.recruit.controller;

import dmu.dasom.api.domain.applicant.dto.ApplicantCreateRequestDto;
import dmu.dasom.api.domain.applicant.service.ApplicantService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/recruit")
@RequiredArgsConstructor
public class RecruitController {

private final ApplicantService applicantService;

// 지원하기
@Operation(summary = "부원 지원하기")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "지원 성공")
})
@PostMapping("/apply")
public ResponseEntity<Void> apply(@Valid @RequestBody final ApplicantCreateRequestDto request) {
applicantService.apply(request);
return ResponseEntity.ok().build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package dmu.dasom.api.global.admin.controller;

import dmu.dasom.api.domain.applicant.dto.ApplicantDetailsResponseDto;
import dmu.dasom.api.domain.applicant.dto.ApplicantResponseDto;
import dmu.dasom.api.domain.applicant.dto.ApplicantStatusUpdateRequestDto;
import dmu.dasom.api.domain.applicant.service.ApplicantService;
import dmu.dasom.api.global.dto.PageResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.ErrorResponse;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/admin")
@RequiredArgsConstructor
public class AdminController {

private final ApplicantService applicantService;

// 지원자 조회
@Operation(summary = "지원자 전체 조회")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "지원자 조회 성공"),
@ApiResponse(responseCode = "400", description = "잘못된 요청",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(
name = "조회 결과 없음",
value = "{ \"code\": \"C012\", \"message\": \"조회 결과가 없습니다.\" }"
)
}
)
)
})
@GetMapping("/applicants")
public ResponseEntity<PageResponse<ApplicantResponseDto>> getApplicants(
@RequestParam(value = "page", defaultValue = "0") @Min(0) final int page
) {
return ResponseEntity.ok(applicantService.getApplicants(page));
}

// 지원자 상세 조회
@Operation(summary = "지원자 상세 조회")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "지원자 상세 조회 성공"),
@ApiResponse(responseCode = "400", description = "잘못된 요청",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(
name = "조회 결과 없음",
value = "{ \"code\": \"C012\", \"message\": \"조회 결과가 없습니다.\" }"
)
}
)
)
})
@GetMapping("/applicants/{id}")
public ResponseEntity<ApplicantDetailsResponseDto> getApplicant(@PathVariable("id") @Min(0) final Long id) {
return ResponseEntity.ok(applicantService.getApplicant(id));
}

// 지원자 상태 변경
@Operation(summary = "지원자 상태 변경")
@PatchMapping("/applicants/{id}/status")
public ResponseEntity<ApplicantDetailsResponseDto> updateApplicantStatus(@PathVariable("id") @Min(0) final Long id,
@Valid @RequestBody final ApplicantStatusUpdateRequestDto request) {
return ResponseEntity.ok(applicantService.updateApplicantStatus(id, request));
}

}
Loading