-
Notifications
You must be signed in to change notification settings - Fork 0
feat(application): Application REST API 구성 #24 #62
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
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
254e6e6
feat(application): Application REST API 구성 #24
wlyoon921 f42cf76
fix(application): 인증 사용자 기반 요청 처리 보완 #24
wlyoon921 83c8550
test(application): 요청 처리 테스트 보강 #24
wlyoon921 0f672fa
fix(application): 원서 기준 요청 처리 보완 #24
wlyoon921 dfbe8a1
fix(application): gateway 사용자 헤더 기반 요청 처리 #24
wlyoon921 85d0d3a
test(application): 성적 요청 매핑 검증 추가 #24
wlyoon921 fb2cc7b
feat(application): Application JPA 저장소 구성 #24
wlyoon921 827d5d8
fix(application): 유저 기준 조회 저장소 추가 #24
wlyoon921 52cc424
fix(application): 지원자 영속 모델 갱신 안정성 보완 #24
wlyoon921 93abcda
fix(application): 필수 학기 성적 검증 보완 #24
wlyoon921 1ff25c1
feat(application): Application 테스트 및 실행 설정 정리 #24
wlyoon921 5b4266b
fix(application): 지원 일정 설정 및 테스트 fixture 정리 #24
wlyoon921 2ae1f19
chore(application): usecase bean 등록 구성 추가 #24
wlyoon921 7f4c4bd
fix(application): 유스케이스 테스트 및 성적 계산 안정성 보완 #24
wlyoon921 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
210 changes: 210 additions & 0 deletions
210
...pter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/ApplicationController.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,210 @@ | ||
| package hs.kr.entrydsm.application.adapterin.web | ||
|
|
||
| import hs.kr.entrydsm.application.adapterin.web.config.LandingScheduleProperties | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.common.ApiResponse | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.common.toResponse | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.UpdateFamilyRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.UpdateIntroductionRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.UpdateMiddleSchoolRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.UpdatePersonalRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.UpdateStudyPlanRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.UpdateTypeRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.response.CreateApplicantResponse | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.response.LandingResponse | ||
| import hs.kr.entrydsm.application.application.port.`in`.ApplicationPort | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.CreateApplicantCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.SubmitApplicationCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.UpdateFamilyCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.UpdateIntroductionCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.UpdateMiddleSchoolCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.UpdatePersonalCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.UpdateStudyPlanCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.UpdateTypeCommand | ||
| import hs.kr.entrydsm.application.domain.enum.GuardianRelation | ||
| import hs.kr.entrydsm.application.domain.enum.SpecialAdmissionType | ||
| import java.time.LocalDate | ||
| import java.time.YearMonth | ||
| import org.springframework.http.HttpStatus | ||
| import org.springframework.web.bind.annotation.GetMapping | ||
| import org.springframework.web.bind.annotation.PatchMapping | ||
| import org.springframework.web.bind.annotation.PathVariable | ||
| import org.springframework.web.bind.annotation.PostMapping | ||
| import org.springframework.web.bind.annotation.RequestBody | ||
| import org.springframework.web.bind.annotation.RequestHeader | ||
| import org.springframework.web.bind.annotation.RequestMapping | ||
| import org.springframework.web.bind.annotation.ResponseStatus | ||
| import org.springframework.web.bind.annotation.RestController | ||
|
|
||
| @RestController | ||
| @RequestMapping("/api/application/v11/applicants") | ||
| class ApplicationController( | ||
| private val applicationPort: ApplicationPort, | ||
| private val landingScheduleProperties: LandingScheduleProperties, | ||
| ) { | ||
| @GetMapping("/landing") | ||
| fun getLanding( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| ): ApiResponse<LandingResponse> { | ||
| val result = applicationPort.getLanding(userId) | ||
| return ApiResponse(data = result.toResponse(landingScheduleProperties)) | ||
| } | ||
|
|
||
| @PostMapping | ||
| @ResponseStatus(HttpStatus.CREATED) | ||
| fun createApplicant( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| ): ApiResponse<CreateApplicantResponse> { | ||
| val result = applicationPort.createApplicant( | ||
| CreateApplicantCommand( | ||
| userId = userId, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = result.toResponse()) | ||
| } | ||
|
|
||
| @PatchMapping("/{id}/type") | ||
| fun updateType( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @PathVariable id: Long, | ||
| @RequestBody request: UpdateTypeRequest, | ||
| ): ApiResponse<Unit> { | ||
| applicationPort.updateType( | ||
| UpdateTypeCommand( | ||
| userId = userId, | ||
| applicantId = id, | ||
| admissionType = request.admissionType, | ||
| region = request.region, | ||
| graduationType = request.graduationType, | ||
| graduationDate = request.graduationDate?.let(YearMonth::parse), | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PatchMapping("/{id}/personal") | ||
| fun updatePersonal( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @PathVariable id: Long, | ||
| @RequestBody request: UpdatePersonalRequest, | ||
| ): ApiResponse<Unit> { | ||
| applicationPort.updatePersonal( | ||
| UpdatePersonalCommand( | ||
| userId = userId, | ||
| applicantId = id, | ||
| photoFileId = request.photoFileId, | ||
| name = request.name, | ||
| phoneNumber = request.phoneNumber, | ||
| gender = request.gender, | ||
| birthdate = parseDate(request.birthdate), | ||
| specialAdmissionType = request.specialAdmissionType ?: SpecialAdmissionType.NONE, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PatchMapping("/{id}/family") | ||
| fun updateFamily( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @PathVariable id: Long, | ||
| @RequestBody request: UpdateFamilyRequest, | ||
| ): ApiResponse<Unit> { | ||
| applicationPort.updateFamily( | ||
| UpdateFamilyCommand( | ||
| userId = userId, | ||
| applicantId = id, | ||
| guardianName = request.guardianName, | ||
| guardianPhoneNumber = request.guardianPhoneNumber, | ||
| guardianGender = request.guardianGender, | ||
| guardianRelation = request.guardianRelation.toGuardianRelation(), | ||
| zipCode = request.address.zipCode, | ||
| addressBase = request.address.addressBase, | ||
| addressDetail = request.address.addressDetail, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PatchMapping("/{id}/middle-school") | ||
| fun updateMiddleSchool( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @PathVariable id: Long, | ||
| @RequestBody request: UpdateMiddleSchoolRequest, | ||
| ): ApiResponse<Unit> { | ||
| applicationPort.updateMiddleSchool( | ||
| UpdateMiddleSchoolCommand( | ||
| userId = userId, | ||
| applicantId = id, | ||
| schoolName = request.schoolName, | ||
| studentNumber = request.studentNumber, | ||
| schoolPhone = request.schoolPhone, | ||
| teacherName = request.teacherName, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PatchMapping("/{id}/self-introduction") | ||
| fun updateIntroduction( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @PathVariable id: Long, | ||
| @RequestBody request: UpdateIntroductionRequest, | ||
| ): ApiResponse<Unit> { | ||
| applicationPort.updateIntroduction( | ||
| UpdateIntroductionCommand( | ||
| userId = userId, | ||
| applicantId = id, | ||
| introduction = request.introduction, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PatchMapping("/{id}/study-plan") | ||
| fun updateStudyPlan( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @PathVariable id: Long, | ||
| @RequestBody request: UpdateStudyPlanRequest, | ||
| ): ApiResponse<Unit> { | ||
| applicationPort.updateStudyPlan( | ||
| UpdateStudyPlanCommand( | ||
| userId = userId, | ||
| applicantId = id, | ||
| studyPlan = request.studyPlan, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PatchMapping | ||
| fun submit( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| ): ApiResponse<Unit> { | ||
| applicationPort.submit( | ||
| SubmitApplicationCommand( | ||
| userId = userId, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
wlyoon921 marked this conversation as resolved.
|
||
|
|
||
| private fun parseDate(value: String): LocalDate { | ||
| return if (value.length == 7) { | ||
| YearMonth.parse(value).atDay(1) | ||
| } else { | ||
| LocalDate.parse(value) | ||
| } | ||
| } | ||
|
|
||
| private fun String.toGuardianRelation(): GuardianRelation { | ||
| return when (uppercase()) { | ||
| "FATHER", "FATHER_RELATION" -> GuardianRelation.FATHER | ||
| "MOTHER", "MOTHER_RELATION" -> GuardianRelation.MOTHER | ||
| "OTHER" -> GuardianRelation.OTHER | ||
| else -> throw IllegalArgumentException("guardianRelation must be FATHER, MOTHER, or OTHER") | ||
| } | ||
| } | ||
|
|
||
| private companion object { | ||
| const val USER_ID_HEADER = "user-id" | ||
| } | ||
| } | ||
140 changes: 140 additions & 0 deletions
140
...apter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/EvaluationController.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| package hs.kr.entrydsm.application.adapterin.web | ||
|
|
||
| import hs.kr.entrydsm.application.adapterin.web.dto.common.ApiResponse | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.common.toResponse | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.SaveAcademicRecordRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.SaveCertificatesRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.SaveGedScoresRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.request.SaveSubjectGradesRequest | ||
| import hs.kr.entrydsm.application.adapterin.web.dto.response.AcademicRecordResponse | ||
| import hs.kr.entrydsm.application.application.port.`in`.EvaluationPort | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.CalculateEvaluationCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.SaveAcademicRecordCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.SaveCertificatesCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.SaveGedScoresCommand | ||
| import hs.kr.entrydsm.application.application.port.`in`.command.SaveSubjectGradesCommand | ||
| import hs.kr.entrydsm.application.domain.enum.SchoolSemester | ||
| import hs.kr.entrydsm.application.domain.model.GedScores | ||
| import org.springframework.web.bind.annotation.PostMapping | ||
| import org.springframework.web.bind.annotation.RequestBody | ||
| import org.springframework.web.bind.annotation.RequestHeader | ||
| import org.springframework.web.bind.annotation.RequestMapping | ||
| import org.springframework.web.bind.annotation.RestController | ||
|
|
||
| @RestController | ||
| @RequestMapping("/api/evaluation/v11/evaluations") | ||
| class EvaluationController( | ||
| private val evaluationPort: EvaluationPort, | ||
| ) { | ||
| @PostMapping("/grades/expected") | ||
| fun saveExpectedGrades( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @RequestBody request: SaveSubjectGradesRequest, | ||
| ): ApiResponse<Unit> { | ||
| saveSubjectGrades(userId, request) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PostMapping("/grades/graduated") | ||
| fun saveGraduatedGrades( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @RequestBody request: SaveSubjectGradesRequest, | ||
| ): ApiResponse<Unit> { | ||
| saveSubjectGrades(userId, request) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PostMapping("/ged-scores") | ||
| fun saveGedScores( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @RequestBody request: SaveGedScoresRequest, | ||
| ): ApiResponse<Unit> { | ||
| evaluationPort.saveGedScores( | ||
| SaveGedScoresCommand( | ||
| userId = userId, | ||
| gedScores = GedScores( | ||
| koreanScore = request.koreanScore, | ||
| mathScore = request.mathScore, | ||
| englishScore = request.englishScore, | ||
| scienceScore = request.scienceScore, | ||
| societyScore = request.societyScore, | ||
| technologyScore = request.technologyScore, | ||
| historyScore = request.historyScore, | ||
| ), | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PostMapping("/academic-records") | ||
| fun saveAcademicRecords( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @RequestBody request: SaveAcademicRecordRequest, | ||
| ): ApiResponse<AcademicRecordResponse> { | ||
| val result = evaluationPort.saveAcademicRecord( | ||
| SaveAcademicRecordCommand( | ||
| userId = userId, | ||
| absentCount = request.absentCount, | ||
| earlyLeaveCount = request.earlyLeaveCount, | ||
| lateCount = request.lateCount, | ||
| classAbsenceCount = request.classAbsenceCount, | ||
| volunteerTime = request.volunteerTime, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = result.toResponse()) | ||
| } | ||
|
|
||
| @PostMapping("/certificates") | ||
| fun saveCertificates( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| @RequestBody request: SaveCertificatesRequest, | ||
| ): ApiResponse<Unit> { | ||
| evaluationPort.saveCertificates( | ||
| SaveCertificatesCommand( | ||
| userId = userId, | ||
| isDsmAlgorithmAwarded = request.isDsmAlgorithmAwarded, | ||
| isProgrammingCertified = request.isProgrammingCertified, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| @PostMapping("/result") | ||
| fun getResult( | ||
| @RequestHeader(USER_ID_HEADER, required = false) userId: Long? = null, | ||
| ): ApiResponse<Unit> { | ||
| evaluationPort.calculateResult( | ||
| CalculateEvaluationCommand( | ||
| userId = userId, | ||
| ), | ||
| ) | ||
| return ApiResponse(data = null) | ||
| } | ||
|
|
||
| private fun saveSubjectGrades( | ||
| userId: Long?, | ||
| request: SaveSubjectGradesRequest, | ||
| ) { | ||
| evaluationPort.saveSubjectGrades( | ||
| SaveSubjectGradesCommand( | ||
| userId = userId, | ||
| schoolSemester = request.schoolSemester.toSchoolSemester(), | ||
| subjectGrades = request.subjects.toDomain(), | ||
| ), | ||
| ) | ||
| } | ||
|
|
||
| private companion object { | ||
| const val USER_ID_HEADER = "user-id" | ||
| } | ||
| } | ||
|
|
||
| private fun String.toSchoolSemester(): SchoolSemester { | ||
| return when (this) { | ||
| "2-1" -> SchoolSemester.SECOND_GRADE_FIRST_SEMESTER | ||
| "2-2" -> SchoolSemester.SECOND_GRADE_SECOND_SEMESTER | ||
| "3-1" -> SchoolSemester.THIRD_GRADE_FIRST_SEMESTER | ||
| "3-2" -> SchoolSemester.THIRD_GRADE_SECOND_SEMESTER | ||
| else -> throw IllegalArgumentException("schoolSemester must be one of 2-1, 2-2, 3-1, 3-2") | ||
| } | ||
| } |
17 changes: 17 additions & 0 deletions
17
.../main/kotlin/hs/kr/entrydsm/application/adapterin/web/config/LandingScheduleProperties.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package hs.kr.entrydsm.application.adapterin.web.config | ||
|
|
||
| import java.time.LocalDateTime | ||
| import org.springframework.beans.factory.annotation.Value | ||
| import org.springframework.stereotype.Component | ||
|
|
||
| @Component | ||
| class LandingScheduleProperties( | ||
| @Value("\${entrydsm.application.schedule.application-start-at}") | ||
| val applicationStartAt: LocalDateTime, | ||
|
|
||
| @Value("\${entrydsm.application.schedule.application-end-at}") | ||
| val applicationEndAt: LocalDateTime, | ||
|
|
||
| @Value("\${entrydsm.application.schedule.result-announced-at}") | ||
| val resultAnnouncedAt: LocalDateTime, | ||
| ) |
7 changes: 7 additions & 0 deletions
7
...ter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ApiResponse.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package hs.kr.entrydsm.application.adapterin.web.dto.common | ||
|
|
||
| data class ApiResponse<T>( | ||
| val success: Boolean = true, | ||
| val data: T?, | ||
| val error: ErrorDetail? = null, | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.