diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/CreateVolunteerRequest.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/CreateVolunteerRequest.kt new file mode 100644 index 000000000..14891ae4e --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/CreateVolunteerRequest.kt @@ -0,0 +1,11 @@ +package team.aliens.dms.domain.volunteer.dto.request + +data class CreateVolunteerRequest( + val name: String, + val content: String, + val availableSex: String, + val availableGrade: String, + val score: Int, + val optionalScore: Int, + val maxApplicants: Int +) diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/UpdateVolunteerRequest.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/UpdateVolunteerRequest.kt new file mode 100644 index 000000000..44b0c499a --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/UpdateVolunteerRequest.kt @@ -0,0 +1,14 @@ +package team.aliens.dms.domain.volunteer.dto.request + +import java.util.UUID + +data class UpdateVolunteerRequest( + val name: String, + val content: String, + val availableSex: String, + val availableGrade: String, + val score: Int, + val optionalScore: Int, + val maxApplicants: Int, + val volunteerId: UUID +) diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/response/ApplyVolunteerResponse.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/response/ApplyVolunteerResponse.kt new file mode 100644 index 000000000..2bfbf16e3 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/response/ApplyVolunteerResponse.kt @@ -0,0 +1,7 @@ +package team.aliens.dms.domain.volunteer.dto.response + +import java.util.UUID + +data class ApplyVolunteerResponse( + val volunteerApplicationId: UUID +) diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/response/VolunteerResponse.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/response/VolunteerResponse.kt new file mode 100644 index 000000000..368cdf5ac --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/response/VolunteerResponse.kt @@ -0,0 +1,134 @@ +package team.aliens.dms.domain.volunteer.dto.response + +import team.aliens.dms.domain.student.model.Sex +import team.aliens.dms.domain.volunteer.model.GradeCondition +import team.aliens.dms.domain.volunteer.model.Volunteer +import team.aliens.dms.domain.volunteer.model.VolunteerApplication +import team.aliens.dms.domain.volunteer.spi.vo.CurrentVolunteerApplicantVO +import team.aliens.dms.domain.volunteer.spi.vo.VolunteerApplicantVO +import java.util.UUID + +data class QueryMyVolunteerApplicationResponse( + val volunteerApplications: List +) { + companion object { + fun of( + applicationsWithVolunteers: List> + ): QueryMyVolunteerApplicationResponse { + return QueryMyVolunteerApplicationResponse( + volunteerApplications = applicationsWithVolunteers.map { (application, volunteer) -> + VolunteerApplicationResponse.of(application, volunteer) + } + ) + } + } +} + +data class VolunteerApplicationResponse( + val id: UUID, + val volunteerId: UUID, + val approved: Boolean, + val name: String, +) { + companion object { + fun of(volunteerApplication: VolunteerApplication, volunteer: Volunteer): VolunteerApplicationResponse { + return VolunteerApplicationResponse( + id = volunteerApplication.id, + volunteerId = volunteerApplication.volunteerId, + approved = volunteerApplication.approved, + name = volunteer.name + ) + } + } +} + +data class VolunteerResponse( + val id: UUID, + val name: String, + val content: String, + val score: Int, + val optionalScore: Int, + val maxApplicants: Int, + val availableSex: Sex, + val availableGrade: GradeCondition +) { + companion object { + fun of(volunteer: Volunteer): VolunteerResponse { + return VolunteerResponse( + id = volunteer.id, + name = volunteer.name, + content = volunteer.content, + score = volunteer.score, + optionalScore = volunteer.optionalScore, + maxApplicants = volunteer.maxApplicants, + availableSex = volunteer.availableSex, + availableGrade = volunteer.availableGrade + ) + } + } +} + +data class VolunteersResponse( + val volunteers: List +) + +data class VolunteerApplicantResponse( + val id: UUID, + val gcd: String, + val name: String, +) { + companion object { + fun of(applicants: VolunteerApplicantVO) = VolunteerApplicantResponse( + id = applicants.id, + gcd = applicants.gcn, + name = applicants.name + ) + } +} + +data class VolunteerApplicantsResponse( + val applicants: List +) + +data class CurrentVolunteerApplicantResponse( + val volunteerName: String, + val applicants: List +) { + companion object { + fun of(currentVolunteerApplicant: CurrentVolunteerApplicantVO) = CurrentVolunteerApplicantResponse( + volunteerName = currentVolunteerApplicant.volunteerName, + applicants = currentVolunteerApplicant.applicants + .map { VolunteerApplicantResponse.of(it) } + ) + } +} + +data class CurrentVolunteerApplicantsResponse( + val volunteers: List +) + +data class AvailableVolunteerResponse( + val id: UUID, + val name: String, + val content: String, + val score: Int, + val optionalScore: Int, + val maxApplicants: Int +) { + companion object { + fun of(volunteer: Volunteer): AvailableVolunteerResponse { + return AvailableVolunteerResponse( + id = volunteer.id, + name = volunteer.name, + content = volunteer.content, + score = volunteer.score, + optionalScore = volunteer.optionalScore, + maxApplicants = volunteer.maxApplicants + ) + } + } +} + +data class AvailableVolunteersResponse( + val volunteers: List +) diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/exception/VolunteerErrorCode.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/exception/VolunteerErrorCode.kt new file mode 100644 index 000000000..dff32d25f --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/exception/VolunteerErrorCode.kt @@ -0,0 +1,22 @@ +package team.aliens.dms.domain.volunteer.exception + +import team.aliens.dms.common.error.ErrorProperty +import team.aliens.dms.common.error.ErrorStatus + +enum class VolunteerErrorCode( + private val status: Int, + private val message: String, + private val sequence: Int +) : ErrorProperty { + + VOLUNTEER_APPLICATION_NOT_FOUND(ErrorStatus.NOT_FOUND, "Volunteer Application Not Found", 1), + VOLUNTEER_NOT_FOUND(ErrorStatus.NOT_FOUND, "Volunteer Not Found", 2), + + VOLUNTEER_APPLICATION_ALREADY_ASSIGNED(ErrorStatus.CONFLICT, "Volunteer Application Already Assigned", 1), + VOLUNTEER_APPLICATION_NOT_ASSIGNED(ErrorStatus.CONFLICT, "Volunteer Application Not Assigned", 2) + ; + + override fun status(): Int = status + override fun message(): String = message + override fun code(): String = "Volunteer-$status-$sequence" +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/exception/VolunteerExceptions.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/exception/VolunteerExceptions.kt new file mode 100644 index 000000000..9d887a3c9 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/exception/VolunteerExceptions.kt @@ -0,0 +1,19 @@ +package team.aliens.dms.domain.volunteer.exception + +import team.aliens.dms.common.error.DmsException + +object VolunteerApplicationNotFoundException : DmsException( + VolunteerErrorCode.VOLUNTEER_APPLICATION_NOT_FOUND +) + +object VolunteerApplicationAlreadyAssigned : DmsException( + VolunteerErrorCode.VOLUNTEER_APPLICATION_ALREADY_ASSIGNED +) + +object VolunteerApplicationNotAssigned : DmsException( + VolunteerErrorCode.VOLUNTEER_APPLICATION_NOT_ASSIGNED +) + +object VolunteerNotFoundException : DmsException( + VolunteerErrorCode.VOLUNTEER_NOT_FOUND +) diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/GradeCondition.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/GradeCondition.kt index c2fc3d13a..d9ae7559c 100644 --- a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/GradeCondition.kt +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/GradeCondition.kt @@ -1,11 +1,13 @@ package team.aliens.dms.domain.volunteer.model -enum class GradeCondition { - ALL, - FIRST, - SECOND, - THIRD, - FIRSTANDSECOND, - SECONDANDTHIRD, - FIRSTANDTHIRD +enum class GradeCondition( + val grades: Set +) { + ALL(setOf(1, 2, 3)), + FIRST(setOf(1)), + SECOND(setOf(2)), + THIRD(setOf(3)), + FIRST_SECOND(setOf(1, 2)), + SECOND_THIRD(setOf(2, 3)), + FIRST_THIRD(setOf(1, 3)) } diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/Volunteer.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/Volunteer.kt index 7971f8918..971502a37 100644 --- a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/Volunteer.kt +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/Volunteer.kt @@ -20,9 +20,9 @@ data class Volunteer( val maxApplicants: Int, - val sexCondition: Sex, + val availableSex: Sex, - val gradeCondition: GradeCondition, + val availableGrade: GradeCondition, override val schoolId: UUID ) : SchoolIdDomain diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/VolunteerApplication.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/VolunteerApplication.kt index a006496d4..6510a920a 100644 --- a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/VolunteerApplication.kt +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/model/VolunteerApplication.kt @@ -1,6 +1,8 @@ package team.aliens.dms.domain.volunteer.model import team.aliens.dms.common.annotation.Aggregate +import team.aliens.dms.domain.volunteer.exception.VolunteerApplicationAlreadyAssigned +import team.aliens.dms.domain.volunteer.exception.VolunteerApplicationNotAssigned import java.util.UUID @Aggregate @@ -12,6 +14,17 @@ data class VolunteerApplication( val volunteerId: UUID, - val approved: Boolean + val approved: Boolean, +) { + fun checkIsNotApproved() { + if (approved) { + throw VolunteerApplicationAlreadyAssigned + } + } -) + fun checkIsApproved() { + if (!approved) { + throw VolunteerApplicationNotAssigned + } + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/CommandVolunteerService.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/CommandVolunteerService.kt new file mode 100644 index 000000000..6f4f046e7 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/CommandVolunteerService.kt @@ -0,0 +1,15 @@ +package team.aliens.dms.domain.volunteer.service + +import team.aliens.dms.domain.volunteer.model.Volunteer +import team.aliens.dms.domain.volunteer.model.VolunteerApplication + +interface CommandVolunteerService { + + fun saveVolunteerApplication(volunteerApplication: VolunteerApplication): VolunteerApplication + + fun deleteVolunteerApplication(volunteerApplication: VolunteerApplication) + + fun saveVolunteer(volunteer: Volunteer): Volunteer + + fun deleteVolunteer(volunteer: Volunteer) +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/CommandVolunteerServiceImpl.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/CommandVolunteerServiceImpl.kt new file mode 100644 index 000000000..c234649fe --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/CommandVolunteerServiceImpl.kt @@ -0,0 +1,28 @@ +package team.aliens.dms.domain.volunteer.service + +import team.aliens.dms.common.annotation.Service +import team.aliens.dms.domain.volunteer.model.Volunteer +import team.aliens.dms.domain.volunteer.model.VolunteerApplication +import team.aliens.dms.domain.volunteer.spi.CommandVolunteerApplicationPort +import team.aliens.dms.domain.volunteer.spi.CommandVolunteerPort + +@Service +class CommandVolunteerServiceImpl( + private val commandVolunteerApplicationPort: CommandVolunteerApplicationPort, + private val commandVolunteerPort: CommandVolunteerPort +) : CommandVolunteerService { + + override fun saveVolunteerApplication(volunteerApplication: VolunteerApplication): VolunteerApplication = + commandVolunteerApplicationPort.saveVolunteerApplication(volunteerApplication) + + override fun deleteVolunteerApplication(volunteerApplication: VolunteerApplication) { + commandVolunteerApplicationPort.deleteVolunteerApplication(volunteerApplication) + } + + override fun saveVolunteer(volunteer: Volunteer): Volunteer = + commandVolunteerPort.saveVolunteer(volunteer) + + override fun deleteVolunteer(volunteer: Volunteer) { + commandVolunteerPort.deleteVolunteer(volunteer) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/GetVolunteerService.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/GetVolunteerService.kt new file mode 100644 index 000000000..453c5b4d5 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/GetVolunteerService.kt @@ -0,0 +1,26 @@ +package team.aliens.dms.domain.volunteer.service + +import team.aliens.dms.domain.volunteer.model.Volunteer +import team.aliens.dms.domain.volunteer.model.VolunteerApplication +import team.aliens.dms.domain.volunteer.spi.vo.CurrentVolunteerApplicantVO +import team.aliens.dms.domain.volunteer.spi.vo.VolunteerApplicantVO +import java.util.UUID + +interface GetVolunteerService { + + fun getVolunteerApplicationById(volunteerApplicationId: UUID): VolunteerApplication + + fun getVolunteerById(volunteerId: UUID): Volunteer + + fun getVolunteerByStudentId(studentId: UUID): List + + fun getAllVolunteersBySchoolId(schoolId: UUID): List + + fun getAllApplicantsByVolunteerId(volunteerId: UUID): List + + fun getAllApplicantsBySchoolIdGroupByVolunteer(schoolId: UUID): List + + fun getAllVolunteers(): List + + fun getVolunteerApplicationsWithVolunteersByStudentId(studentId: UUID): List> +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/GetVolunteerServiceImpl.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/GetVolunteerServiceImpl.kt new file mode 100644 index 000000000..cb1c6208a --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/GetVolunteerServiceImpl.kt @@ -0,0 +1,46 @@ +package team.aliens.dms.domain.volunteer.service + +import team.aliens.dms.common.annotation.Service +import team.aliens.dms.domain.volunteer.exception.VolunteerApplicationNotFoundException +import team.aliens.dms.domain.volunteer.exception.VolunteerNotFoundException +import team.aliens.dms.domain.volunteer.model.Volunteer +import team.aliens.dms.domain.volunteer.model.VolunteerApplication +import team.aliens.dms.domain.volunteer.spi.QueryVolunteerApplicationPort +import team.aliens.dms.domain.volunteer.spi.QueryVolunteerPort +import team.aliens.dms.domain.volunteer.spi.vo.CurrentVolunteerApplicantVO +import team.aliens.dms.domain.volunteer.spi.vo.VolunteerApplicantVO +import java.util.UUID + +@Service +class GetVolunteerServiceImpl( + private val queryVolunteerApplicationPort: QueryVolunteerApplicationPort, + private val queryVolunteerPort: QueryVolunteerPort, +) : GetVolunteerService { + + override fun getVolunteerApplicationById(volunteerApplicationId: UUID): VolunteerApplication = + queryVolunteerApplicationPort.queryVolunteerApplicationById(volunteerApplicationId) + ?: throw VolunteerApplicationNotFoundException + + override fun getVolunteerById(volunteerId: UUID): Volunteer = + queryVolunteerPort.queryVolunteerById(volunteerId) + ?: throw VolunteerNotFoundException + + override fun getVolunteerByStudentId(studentId: UUID): List = + queryVolunteerPort.queryVolunteerByStudentId(studentId) + + override fun getAllVolunteersBySchoolId(schoolId: UUID): List = + queryVolunteerPort.queryAllVolunteersBySchoolId(schoolId) + + override fun getAllApplicantsByVolunteerId(volunteerId: UUID): List = + queryVolunteerApplicationPort.queryAllApplicantsByVolunteerId(volunteerId) + + override fun getAllApplicantsBySchoolIdGroupByVolunteer(schoolId: UUID): List = + queryVolunteerApplicationPort.queryAllApplicantsBySchoolIdGroupByVolunteer(schoolId) + + override fun getAllVolunteers(): List = + queryVolunteerPort.queryAllVolunteers() + + override fun getVolunteerApplicationsWithVolunteersByStudentId(studentId: UUID): List> { + return queryVolunteerApplicationPort.getVolunteerApplicationsWithVolunteersByStudentId(studentId) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/VolunteerService.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/VolunteerService.kt new file mode 100644 index 000000000..6cac32837 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/service/VolunteerService.kt @@ -0,0 +1,10 @@ +package team.aliens.dms.domain.volunteer.service + +import team.aliens.dms.common.annotation.Service + +@Service +class VolunteerService( + commandVolunteerService: CommandVolunteerService, + getVolunteerService: GetVolunteerService +) : CommandVolunteerService by commandVolunteerService, + GetVolunteerService by getVolunteerService diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/CommandVolunteerApplicationPort.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/CommandVolunteerApplicationPort.kt new file mode 100644 index 000000000..5fb7f0fd0 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/CommandVolunteerApplicationPort.kt @@ -0,0 +1,10 @@ +package team.aliens.dms.domain.volunteer.spi + +import team.aliens.dms.domain.volunteer.model.VolunteerApplication + +interface CommandVolunteerApplicationPort { + + fun saveVolunteerApplication(volunteerApplication: VolunteerApplication): VolunteerApplication + + fun deleteVolunteerApplication(volunteerApplication: VolunteerApplication) +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/CommandVolunteerPort.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/CommandVolunteerPort.kt new file mode 100644 index 000000000..c119f383d --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/CommandVolunteerPort.kt @@ -0,0 +1,10 @@ +package team.aliens.dms.domain.volunteer.spi + +import team.aliens.dms.domain.volunteer.model.Volunteer + +interface CommandVolunteerPort { + + fun saveVolunteer(volunteer: Volunteer): Volunteer + + fun deleteVolunteer(volunteer: Volunteer) +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/QueryVolunteerApplicationPort.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/QueryVolunteerApplicationPort.kt new file mode 100644 index 000000000..203ecf66e --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/QueryVolunteerApplicationPort.kt @@ -0,0 +1,18 @@ +package team.aliens.dms.domain.volunteer.spi + +import team.aliens.dms.domain.volunteer.model.Volunteer +import team.aliens.dms.domain.volunteer.model.VolunteerApplication +import team.aliens.dms.domain.volunteer.spi.vo.CurrentVolunteerApplicantVO +import team.aliens.dms.domain.volunteer.spi.vo.VolunteerApplicantVO +import java.util.UUID + +interface QueryVolunteerApplicationPort { + + fun queryVolunteerApplicationById(volunteerApplicationId: UUID): VolunteerApplication? + + fun queryAllApplicantsByVolunteerId(volunteerId: UUID): List + + fun queryAllApplicantsBySchoolIdGroupByVolunteer(schoolId: UUID): List + + fun getVolunteerApplicationsWithVolunteersByStudentId(studentId: UUID): List> +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/QueryVolunteerPort.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/QueryVolunteerPort.kt new file mode 100644 index 000000000..b8d5be861 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/QueryVolunteerPort.kt @@ -0,0 +1,15 @@ +package team.aliens.dms.domain.volunteer.spi + +import team.aliens.dms.domain.volunteer.model.Volunteer +import java.util.UUID + +interface QueryVolunteerPort { + + fun queryVolunteerById(volunteerId: UUID): Volunteer? + + fun queryVolunteerByStudentId(studentId: UUID): List + + fun queryAllVolunteersBySchoolId(schoolId: UUID): List + + fun queryAllVolunteers(): List +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/VolunteerApplicationPort.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/VolunteerApplicationPort.kt new file mode 100644 index 000000000..4222f3509 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/VolunteerApplicationPort.kt @@ -0,0 +1,5 @@ +package team.aliens.dms.domain.volunteer.spi + +interface VolunteerApplicationPort : + CommandVolunteerApplicationPort, + QueryVolunteerApplicationPort diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/VolunteerPort.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/VolunteerPort.kt new file mode 100644 index 000000000..8a2711c32 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/VolunteerPort.kt @@ -0,0 +1,5 @@ +package team.aliens.dms.domain.volunteer.spi + +interface VolunteerPort : + QueryVolunteerPort, + CommandVolunteerPort diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/vo/CurrentVolunteerApplicantVO.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/vo/CurrentVolunteerApplicantVO.kt new file mode 100644 index 000000000..58be08900 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/vo/CurrentVolunteerApplicantVO.kt @@ -0,0 +1,6 @@ +package team.aliens.dms.domain.volunteer.spi.vo + +open class CurrentVolunteerApplicantVO( + val volunteerName: String, + val applicants: List +) diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/vo/VolunteerApplicantVO.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/vo/VolunteerApplicantVO.kt new file mode 100644 index 000000000..f9e208f3c --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/spi/vo/VolunteerApplicantVO.kt @@ -0,0 +1,14 @@ +package team.aliens.dms.domain.volunteer.spi.vo + +import team.aliens.dms.domain.student.model.Student +import java.util.UUID + +open class VolunteerApplicantVO( + val id: UUID, + val grade: Int, + val classRoom: Int, + val number: Int, + val name: String +) { + val gcn = Student.processGcn(grade, classRoom, number) +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ApplyVolunteerUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ApplyVolunteerUseCase.kt new file mode 100644 index 000000000..3791d5c62 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ApplyVolunteerUseCase.kt @@ -0,0 +1,29 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.UseCase +import team.aliens.dms.domain.student.service.StudentService +import team.aliens.dms.domain.volunteer.dto.response.ApplyVolunteerResponse +import team.aliens.dms.domain.volunteer.model.VolunteerApplication +import team.aliens.dms.domain.volunteer.service.VolunteerService +import java.util.UUID + +@UseCase +class ApplyVolunteerUseCase( + private val volunteerService: VolunteerService, + private val studentService: StudentService, +) { + + fun execute(volunteerId: UUID): ApplyVolunteerResponse { + val student = studentService.getCurrentStudent() + + val volunteer = volunteerService.saveVolunteerApplication( + VolunteerApplication( + studentId = student.id, + volunteerId = volunteerId, + approved = false + ) + ) + + return ApplyVolunteerResponse(volunteer.id) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ApproveVolunteerApplicationUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ApproveVolunteerApplicationUseCase.kt new file mode 100644 index 000000000..34aaf6be4 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ApproveVolunteerApplicationUseCase.kt @@ -0,0 +1,24 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.UseCase +import team.aliens.dms.domain.volunteer.service.VolunteerService +import java.util.UUID + +@UseCase +class ApproveVolunteerApplicationUseCase( + private val volunteerService: VolunteerService +) { + + fun execute(volunteerApplicationId: UUID) { + + val currentVolunteerApplication = volunteerService.getVolunteerApplicationById(volunteerApplicationId) + + currentVolunteerApplication.checkIsNotApproved() + + volunteerService.saveVolunteerApplication( + currentVolunteerApplication.copy( + approved = true + ) + ) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/CreateVolunteerUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/CreateVolunteerUseCase.kt new file mode 100644 index 000000000..bad40681e --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/CreateVolunteerUseCase.kt @@ -0,0 +1,33 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.UseCase +import team.aliens.dms.common.service.security.SecurityService +import team.aliens.dms.domain.student.model.Sex +import team.aliens.dms.domain.volunteer.dto.request.CreateVolunteerRequest +import team.aliens.dms.domain.volunteer.model.GradeCondition +import team.aliens.dms.domain.volunteer.model.Volunteer +import team.aliens.dms.domain.volunteer.service.VolunteerService + +@UseCase +class CreateVolunteerUseCase( + private val securityService: SecurityService, + private val volunteerService: VolunteerService +) { + + fun execute(createVolunteerRequest: CreateVolunteerRequest) { + val schoolId = securityService.getCurrentSchoolId() + + val volunteer = Volunteer( + name = createVolunteerRequest.name, + content = createVolunteerRequest.content, + availableSex = Sex.valueOf(createVolunteerRequest.availableSex), + availableGrade = GradeCondition.valueOf(createVolunteerRequest.availableGrade), + score = createVolunteerRequest.score, + optionalScore = createVolunteerRequest.optionalScore, + maxApplicants = createVolunteerRequest.maxApplicants, + schoolId = schoolId + ) + + volunteerService.saveVolunteer(volunteer) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/DeleteVolunteerUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/DeleteVolunteerUseCase.kt new file mode 100644 index 000000000..253425295 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/DeleteVolunteerUseCase.kt @@ -0,0 +1,18 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.UseCase +import team.aliens.dms.domain.volunteer.service.VolunteerService +import java.util.UUID + +@UseCase +class DeleteVolunteerUseCase( + private val volunteerService: VolunteerService +) { + + fun execute(volunteerId: UUID) { + + val currentVolunteer = volunteerService.getVolunteerById(volunteerId) + + volunteerService.deleteVolunteer(currentVolunteer) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ExcludeVolunteerApplicationUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ExcludeVolunteerApplicationUseCase.kt new file mode 100644 index 000000000..e909bed84 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ExcludeVolunteerApplicationUseCase.kt @@ -0,0 +1,19 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.UseCase +import team.aliens.dms.domain.volunteer.service.VolunteerService +import java.util.UUID + +@UseCase +class ExcludeVolunteerApplicationUseCase( + private val volunteerService: VolunteerService +) { + + fun execute(volunteerApplicationId: UUID) { + val currentVolunteerApplication = volunteerService.getVolunteerApplicationById(volunteerApplicationId) + + currentVolunteerApplication.checkIsApproved() + + volunteerService.deleteVolunteerApplication(currentVolunteerApplication) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ManagerGetAllVolunteersUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ManagerGetAllVolunteersUseCase.kt new file mode 100644 index 000000000..1e8c2a1e3 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/ManagerGetAllVolunteersUseCase.kt @@ -0,0 +1,23 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.ReadOnlyUseCase +import team.aliens.dms.common.service.security.SecurityService +import team.aliens.dms.domain.volunteer.dto.response.VolunteerResponse +import team.aliens.dms.domain.volunteer.dto.response.VolunteersResponse +import team.aliens.dms.domain.volunteer.service.VolunteerService + +@ReadOnlyUseCase +class ManagerGetAllVolunteersUseCase( + private val securityService: SecurityService, + private val volunteerService: VolunteerService +) { + + fun execute(): VolunteersResponse { + val schoolId = securityService.getCurrentSchoolId() + + val volunteers = volunteerService.getAllVolunteersBySchoolId(schoolId) + .map { VolunteerResponse.of(it) } + + return VolunteersResponse(volunteers) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryAppliedStudentUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryAppliedStudentUseCase.kt new file mode 100644 index 000000000..8601468b0 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryAppliedStudentUseCase.kt @@ -0,0 +1,22 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.ReadOnlyUseCase +import team.aliens.dms.domain.volunteer.dto.response.VolunteerApplicantResponse +import team.aliens.dms.domain.volunteer.dto.response.VolunteerApplicantsResponse +import team.aliens.dms.domain.volunteer.service.VolunteerService +import java.util.UUID + +@ReadOnlyUseCase +class QueryAppliedStudentUseCase( + private val volunteerService: VolunteerService +) { + + fun execute(volunteerId: UUID): VolunteerApplicantsResponse { + val currentVolunteer = volunteerService.getVolunteerById(volunteerId) + + val applicants = volunteerService.getAllApplicantsByVolunteerId(currentVolunteer.id) + .map { VolunteerApplicantResponse.of(it) } + + return VolunteerApplicantsResponse(applicants) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryAvailableVolunteersUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryAvailableVolunteersUseCase.kt new file mode 100644 index 000000000..fb772dfd0 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryAvailableVolunteersUseCase.kt @@ -0,0 +1,25 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.ReadOnlyUseCase +import team.aliens.dms.domain.student.service.StudentService +import team.aliens.dms.domain.volunteer.dto.response.AvailableVolunteerResponse +import team.aliens.dms.domain.volunteer.dto.response.AvailableVolunteersResponse +import team.aliens.dms.domain.volunteer.service.VolunteerService + +@ReadOnlyUseCase +class QueryAvailableVolunteersUseCase( + private val volunteerService: VolunteerService, + private val studentService: StudentService +) { + + fun execute(): AvailableVolunteersResponse { + val student = studentService.getCurrentStudent() + + val availableVolunteers = volunteerService.getVolunteerByStudentId(student.id) + + return AvailableVolunteersResponse( + availableVolunteers + .map { AvailableVolunteerResponse.of(it) } + ) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryCurrentVolunteerApplicantsUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryCurrentVolunteerApplicantsUseCase.kt new file mode 100644 index 000000000..9f4fb04e4 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryCurrentVolunteerApplicantsUseCase.kt @@ -0,0 +1,25 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.ReadOnlyUseCase +import team.aliens.dms.common.service.security.SecurityService +import team.aliens.dms.domain.volunteer.dto.response.CurrentVolunteerApplicantResponse +import team.aliens.dms.domain.volunteer.dto.response.CurrentVolunteerApplicantsResponse +import team.aliens.dms.domain.volunteer.service.VolunteerService + +@ReadOnlyUseCase +class QueryCurrentVolunteerApplicantsUseCase( + private val securityService: SecurityService, + private val volunteerService: VolunteerService +) { + + fun execute(): CurrentVolunteerApplicantsResponse { + val schoolId = securityService.getCurrentSchoolId() + + val currentApplicantsGroup = volunteerService.getAllApplicantsBySchoolIdGroupByVolunteer(schoolId) + + return CurrentVolunteerApplicantsResponse( + currentApplicantsGroup + .map { CurrentVolunteerApplicantResponse.of(it) } + ) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryMyVolunteerApplicationUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryMyVolunteerApplicationUseCase.kt new file mode 100644 index 000000000..3151c2dc2 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/QueryMyVolunteerApplicationUseCase.kt @@ -0,0 +1,20 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.ReadOnlyUseCase +import team.aliens.dms.domain.student.service.StudentService +import team.aliens.dms.domain.volunteer.dto.response.QueryMyVolunteerApplicationResponse +import team.aliens.dms.domain.volunteer.service.VolunteerService + +@ReadOnlyUseCase +class QueryMyVolunteerApplicationUseCase( + private val volunteerService: VolunteerService, + private val studentService: StudentService +) { + fun execute(): QueryMyVolunteerApplicationResponse { + val student = studentService.getCurrentStudent() + + val applicationsWithVolunteers = volunteerService.getVolunteerApplicationsWithVolunteersByStudentId(student.id) + + return QueryMyVolunteerApplicationResponse.of(applicationsWithVolunteers) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/RejectVolunteerApplicationUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/RejectVolunteerApplicationUseCase.kt new file mode 100644 index 000000000..a8a686c24 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/RejectVolunteerApplicationUseCase.kt @@ -0,0 +1,19 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.UseCase +import team.aliens.dms.domain.volunteer.service.VolunteerService +import java.util.UUID + +@UseCase +class RejectVolunteerApplicationUseCase( + private val volunteerService: VolunteerService +) { + + fun execute(volunteerApplicationId: UUID) { + val currentVolunteerApplication = volunteerService.getVolunteerApplicationById(volunteerApplicationId) + + currentVolunteerApplication.checkIsNotApproved() + + volunteerService.deleteVolunteerApplication(currentVolunteerApplication) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/UnapplyVolunteerUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/UnapplyVolunteerUseCase.kt new file mode 100644 index 000000000..9a2513da3 --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/UnapplyVolunteerUseCase.kt @@ -0,0 +1,19 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.UseCase +import team.aliens.dms.domain.volunteer.service.VolunteerService +import java.util.UUID + +@UseCase +class UnapplyVolunteerUseCase( + private val volunteerService: VolunteerService +) { + + fun execute(volunteerApplicationId: UUID) { + val volunteer = volunteerService.getVolunteerApplicationById(volunteerApplicationId) + + volunteer.checkIsNotApproved() + + volunteerService.deleteVolunteerApplication(volunteer) + } +} diff --git a/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/UpdateVolunteerUseCase.kt b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/UpdateVolunteerUseCase.kt new file mode 100644 index 000000000..09f7b407b --- /dev/null +++ b/dms-core/src/main/kotlin/team/aliens/dms/domain/volunteer/usecase/UpdateVolunteerUseCase.kt @@ -0,0 +1,29 @@ +package team.aliens.dms.domain.volunteer.usecase + +import team.aliens.dms.common.annotation.UseCase +import team.aliens.dms.domain.student.model.Sex +import team.aliens.dms.domain.volunteer.dto.request.UpdateVolunteerRequest +import team.aliens.dms.domain.volunteer.model.GradeCondition +import team.aliens.dms.domain.volunteer.service.VolunteerService + +@UseCase +class UpdateVolunteerUseCase( + private val volunteerService: VolunteerService +) { + + fun execute(updateVolunteerRequest: UpdateVolunteerRequest) { + val currentVolunteer = volunteerService.getVolunteerById(updateVolunteerRequest.volunteerId) + + volunteerService.saveVolunteer( + currentVolunteer.copy( + name = updateVolunteerRequest.name, + content = updateVolunteerRequest.content, + availableSex = Sex.valueOf(updateVolunteerRequest.availableSex), + availableGrade = GradeCondition.valueOf(updateVolunteerRequest.availableGrade), + score = updateVolunteerRequest.score, + optionalScore = updateVolunteerRequest.optionalScore, + maxApplicants = updateVolunteerRequest.maxApplicants, + ) + ) + } +} diff --git a/dms-infrastructure/src/main/kotlin/team/aliens/dms/global/security/SecurityConfig.kt b/dms-infrastructure/src/main/kotlin/team/aliens/dms/global/security/SecurityConfig.kt index 9e7543d72..75f74496d 100644 --- a/dms-infrastructure/src/main/kotlin/team/aliens/dms/global/security/SecurityConfig.kt +++ b/dms-infrastructure/src/main/kotlin/team/aliens/dms/global/security/SecurityConfig.kt @@ -189,6 +189,21 @@ class SecurityConfig( // /bugs .requestMatchers(HttpMethod.POST, "/bugs").hasAuthority(STUDENT.name) + // /volunteers + .requestMatchers(HttpMethod.POST, "/volunteers").hasAuthority(MANAGER.name) + .requestMatchers(HttpMethod.PATCH, "/volunteers/{volunteer-id}").hasAuthority(MANAGER.name) + .requestMatchers(HttpMethod.DELETE, "/volunteers/{volunteer-id}").hasAuthority(MANAGER.name) + .requestMatchers(HttpMethod.GET, "/volunteers/manage").hasAuthority(MANAGER.name) + .requestMatchers(HttpMethod.GET, "/volunteers/{volunteer-id}").hasAuthority(MANAGER.name) + .requestMatchers(HttpMethod.GET, "/volunteers/apply/{volunteer-application-id}").hasAuthority(MANAGER.name) + .requestMatchers(HttpMethod.DELETE, "/volunteers/reject/{volunteer-application-id}").hasAuthority(MANAGER.name) + .requestMatchers(HttpMethod.DELETE, "/volunteers/exclude/{volunteer-application-id}").hasAuthority(MANAGER.name) + .requestMatchers(HttpMethod.GET, "/volunteers/current").hasAuthority(MANAGER.name) + .requestMatchers(HttpMethod.POST, "/volunteers/apply/{volunteer-id}").hasAuthority(STUDENT.name) + .requestMatchers(HttpMethod.DELETE, "/volunteers/cancel/{volunteer-application-id}").hasAuthority(STUDENT.name) + .requestMatchers(HttpMethod.GET, "/volunteers").hasAuthority(STUDENT.name) + .requestMatchers(HttpMethod.GET, "/volunteers/my/application").hasAuthority(STUDENT.name) + .anyRequest().denyAll() } http diff --git a/dms-infrastructure/src/main/resources/db/migration/V5__change_column_name_in_tbl_volunteer.sql b/dms-infrastructure/src/main/resources/db/migration/V5__change_column_name_in_tbl_volunteer.sql new file mode 100644 index 000000000..6801925bb --- /dev/null +++ b/dms-infrastructure/src/main/resources/db/migration/V5__change_column_name_in_tbl_volunteer.sql @@ -0,0 +1,4 @@ +ALTER TABLE tbl_volunteer + CHANGE COLUMN sex_condition available_sex VARCHAR(6) NOT NULL, + CHANGE COLUMN grade_condition available_grade VARCHAR(14) NOT NULL; + diff --git a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/VolunteerApplicationPersistenceAdapter.kt b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/VolunteerApplicationPersistenceAdapter.kt new file mode 100644 index 000000000..af249b343 --- /dev/null +++ b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/VolunteerApplicationPersistenceAdapter.kt @@ -0,0 +1,112 @@ +package team.aliens.dms.persistence.volunteer + +import com.querydsl.core.group.GroupBy.groupBy +import com.querydsl.core.group.GroupBy.list +import com.querydsl.jpa.impl.JPAQueryFactory +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Component +import team.aliens.dms.domain.volunteer.model.Volunteer +import team.aliens.dms.domain.volunteer.model.VolunteerApplication +import team.aliens.dms.domain.volunteer.spi.VolunteerApplicationPort +import team.aliens.dms.domain.volunteer.spi.vo.CurrentVolunteerApplicantVO +import team.aliens.dms.domain.volunteer.spi.vo.VolunteerApplicantVO +import team.aliens.dms.persistence.student.entity.QStudentJpaEntity.studentJpaEntity +import team.aliens.dms.persistence.volunteer.entity.QVolunteerApplicationJpaEntity.volunteerApplicationJpaEntity +import team.aliens.dms.persistence.volunteer.entity.QVolunteerJpaEntity.volunteerJpaEntity +import team.aliens.dms.persistence.volunteer.mapper.VolunteerApplicationMapper +import team.aliens.dms.persistence.volunteer.mapper.VolunteerMapper +import team.aliens.dms.persistence.volunteer.repository.VolunteerApplicationJpaRepository +import team.aliens.dms.persistence.volunteer.repository.vo.QQueryCurrentVolunteerApplicantVO +import team.aliens.dms.persistence.volunteer.repository.vo.QQueryVolunteerApplicantVO +import java.util.UUID + +@Component +class VolunteerApplicationPersistenceAdapter( + private val volunteerApplicationMapper: VolunteerApplicationMapper, + private val volunteerApplicationRepository: VolunteerApplicationJpaRepository, + private val queryFactory: JPAQueryFactory, + private val volunteerMapper: VolunteerMapper +) : VolunteerApplicationPort { + + override fun queryVolunteerApplicationById(volunteerApplicationId: UUID) = + volunteerApplicationMapper.toDomain( + volunteerApplicationRepository.findByIdOrNull(volunteerApplicationId) + ) + + override fun queryAllApplicantsByVolunteerId(volunteerId: UUID): List { + return queryFactory + .select( + QQueryVolunteerApplicantVO( + volunteerApplicationJpaEntity.id, + studentJpaEntity.grade, + studentJpaEntity.classRoom, + studentJpaEntity.number, + studentJpaEntity.name, + ) + ) + .from(volunteerApplicationJpaEntity) + .join(volunteerApplicationJpaEntity.student, studentJpaEntity) + .where( + volunteerApplicationJpaEntity.volunteer.id.eq(volunteerId), + volunteerApplicationJpaEntity.approved.eq(false) + ) + .fetch() + } + + override fun saveVolunteerApplication(volunteerApplication: VolunteerApplication) = + volunteerApplicationMapper.toDomain( + volunteerApplicationRepository.save( + volunteerApplicationMapper.toEntity(volunteerApplication) + ) + )!! + + override fun deleteVolunteerApplication(volunteerApplication: VolunteerApplication) { + volunteerApplicationRepository.delete( + volunteerApplicationMapper.toEntity(volunteerApplication) + ) + } + + override fun queryAllApplicantsBySchoolIdGroupByVolunteer(schoolId: UUID): List { + return queryFactory + .selectFrom(volunteerApplicationJpaEntity) + .join(volunteerApplicationJpaEntity.volunteer, volunteerJpaEntity) + .join(volunteerApplicationJpaEntity.student, studentJpaEntity) + .where( + volunteerJpaEntity.school.id.eq(schoolId), + volunteerApplicationJpaEntity.approved.eq(true) + ) + .transform( + groupBy(volunteerJpaEntity.name) + .list( + QQueryCurrentVolunteerApplicantVO( + volunteerJpaEntity.name, + list( + QQueryVolunteerApplicantVO( + volunteerApplicationJpaEntity.id, + studentJpaEntity.grade, + studentJpaEntity.classRoom, + studentJpaEntity.number, + studentJpaEntity.name, + ) + ) + ) + ) + ) + } + + override fun getVolunteerApplicationsWithVolunteersByStudentId(studentId: UUID): List> { + val result = queryFactory + .select(volunteerApplicationJpaEntity, volunteerJpaEntity) + .from(volunteerApplicationJpaEntity) + .join(volunteerApplicationJpaEntity.volunteer, volunteerJpaEntity) + .where(volunteerApplicationJpaEntity.student.id.eq(studentId)) + .fetch() + + return result.map { tuple -> + val volunteerApplication = volunteerApplicationMapper.toDomain(tuple[volunteerApplicationJpaEntity])!! + val volunteer = volunteerMapper.toDomain(tuple[volunteerJpaEntity])!! + + volunteerApplication to volunteer + } + } +} diff --git a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/VolunteerPersistenceAdapter.kt b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/VolunteerPersistenceAdapter.kt new file mode 100644 index 000000000..29f016f23 --- /dev/null +++ b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/VolunteerPersistenceAdapter.kt @@ -0,0 +1,61 @@ +package team.aliens.dms.persistence.volunteer + +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Component +import team.aliens.dms.domain.student.exception.StudentNotFoundException +import team.aliens.dms.domain.student.model.Sex +import team.aliens.dms.domain.volunteer.model.Volunteer +import team.aliens.dms.domain.volunteer.spi.VolunteerPort +import team.aliens.dms.persistence.student.repository.StudentJpaRepository +import team.aliens.dms.persistence.volunteer.mapper.VolunteerMapper +import team.aliens.dms.persistence.volunteer.repository.VolunteerJpaRepository +import java.util.UUID + +@Component +class VolunteerPersistenceAdapter( + private val volunteerMapper: VolunteerMapper, + private val volunteerJpaRepository: VolunteerJpaRepository, + private val studentRepository: StudentJpaRepository +) : VolunteerPort { + + override fun saveVolunteer(volunteer: Volunteer): Volunteer = volunteerMapper.toDomain( + volunteerJpaRepository.save( + volunteerMapper.toEntity(volunteer) + ) + )!! + + override fun deleteVolunteer(volunteer: Volunteer) { + volunteerJpaRepository.delete( + volunteerMapper.toEntity(volunteer) + ) + } + + override fun queryVolunteerById(volunteerId: UUID): Volunteer? = volunteerMapper.toDomain( + volunteerJpaRepository.findByIdOrNull(volunteerId) + ) + + override fun queryVolunteerByStudentId(studentId: UUID): List { + val student = studentRepository.findById(studentId) + .orElseThrow { throw StudentNotFoundException } + + val volunteers = volunteerJpaRepository.findAll() + return volunteers + .filter { volunteer -> + ( + volunteer.availableGrade.grades.contains(student.grade) && + (volunteer.availableSex == student.sex || volunteer.availableSex == Sex.ALL) + ) + } + .mapNotNull { volunteerMapper.toDomain(it) } + } + + override fun queryAllVolunteersBySchoolId(schoolId: UUID): List { + return volunteerJpaRepository.findAllBySchoolId(schoolId) + .map { volunteerMapper.toDomain(it)!! } + } + + override fun queryAllVolunteers(): List { + return volunteerJpaRepository.findAll() + .map { volunteerMapper.toDomain(it)!! } + } +} diff --git a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/entity/VolunteerJpaEntity.kt b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/entity/VolunteerJpaEntity.kt index 5817c11c1..71bc4fbb8 100644 --- a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/entity/VolunteerJpaEntity.kt +++ b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/entity/VolunteerJpaEntity.kt @@ -37,13 +37,14 @@ class VolunteerJpaEntity( @Column(columnDefinition = "VARCHAR(6)", nullable = false) @Enumerated(EnumType.STRING) - val sexCondition: Sex, + val availableSex: Sex, @Column(columnDefinition = "VARCHAR(14)", nullable = false) @Enumerated(EnumType.STRING) - val gradeCondition: GradeCondition, + val availableGrade: GradeCondition, @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "school_id", columnDefinition = "BINARY(16)", nullable = false) val school: SchoolJpaEntity?, + ) : BaseEntity(id) diff --git a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/mapper/VolunteerMapper.kt b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/mapper/VolunteerMapper.kt index a9daac8e6..ab2d5a6ca 100644 --- a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/mapper/VolunteerMapper.kt +++ b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/mapper/VolunteerMapper.kt @@ -21,8 +21,8 @@ class VolunteerMapper( score = it.score, optionalScore = it.optionalScore, maxApplicants = it.maxApplicants, - sexCondition = it.sexCondition, - gradeCondition = it.gradeCondition, + availableSex = it.availableSex, + availableGrade = it.availableGrade, schoolId = it.school!!.id!! ) } @@ -37,8 +37,8 @@ class VolunteerMapper( score = domain.score, optionalScore = domain.optionalScore, maxApplicants = domain.maxApplicants, - sexCondition = domain.sexCondition, - gradeCondition = domain.gradeCondition, + availableSex = domain.availableSex, + availableGrade = domain.availableGrade, school = school ) } diff --git a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/VolunteerApplicationJpaRepository.kt b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/VolunteerApplicationJpaRepository.kt index 24e6ae234..14c3eeab2 100644 --- a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/VolunteerApplicationJpaRepository.kt +++ b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/VolunteerApplicationJpaRepository.kt @@ -6,4 +6,7 @@ import team.aliens.dms.persistence.volunteer.entity.VolunteerApplicationJpaEntit import java.util.UUID @Repository -interface VolunteerApplicationJpaRepository : CrudRepository +interface VolunteerApplicationJpaRepository : CrudRepository { + + fun findByStudentId(studentId: UUID): List +} diff --git a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/VolunteerJpaRepository.kt b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/VolunteerJpaRepository.kt index a21c259d7..f52c46a4a 100644 --- a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/VolunteerJpaRepository.kt +++ b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/VolunteerJpaRepository.kt @@ -6,4 +6,7 @@ import team.aliens.dms.persistence.volunteer.entity.VolunteerJpaEntity import java.util.UUID @Repository -interface VolunteerJpaRepository : CrudRepository +interface VolunteerJpaRepository : CrudRepository { + + fun findAllBySchoolId(schoolId: UUID): List +} diff --git a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/vo/QueryCurrentVolunteerApplicantVO.kt b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/vo/QueryCurrentVolunteerApplicantVO.kt new file mode 100644 index 000000000..13da5c1af --- /dev/null +++ b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/vo/QueryCurrentVolunteerApplicantVO.kt @@ -0,0 +1,12 @@ +package team.aliens.dms.persistence.volunteer.repository.vo + +import com.querydsl.core.annotations.QueryProjection +import team.aliens.dms.domain.volunteer.spi.vo.CurrentVolunteerApplicantVO + +class QueryCurrentVolunteerApplicantVO @QueryProjection constructor( + volunteerName: String, + applicants: List +) : CurrentVolunteerApplicantVO( + volunteerName = volunteerName, + applicants = applicants +) diff --git a/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/vo/QueryVolunteerApplicantVO.kt b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/vo/QueryVolunteerApplicantVO.kt new file mode 100644 index 000000000..9fb3575cf --- /dev/null +++ b/dms-persistence/src/main/kotlin/team/aliens/dms/persistence/volunteer/repository/vo/QueryVolunteerApplicantVO.kt @@ -0,0 +1,19 @@ +package team.aliens.dms.persistence.volunteer.repository.vo + +import com.querydsl.core.annotations.QueryProjection +import team.aliens.dms.domain.volunteer.spi.vo.VolunteerApplicantVO +import java.util.UUID + +class QueryVolunteerApplicantVO @QueryProjection constructor( + id: UUID, + grade: Int, + classNumber: Int, + number: Int, + name: String +) : VolunteerApplicantVO( + id = id, + grade = grade, + classRoom = classNumber, + number = number, + name = name +) diff --git a/dms-presentation/src/main/kotlin/team/aliens/dms/domain/volunteer/VolunteerWebAdapter.kt b/dms-presentation/src/main/kotlin/team/aliens/dms/domain/volunteer/VolunteerWebAdapter.kt new file mode 100644 index 000000000..e3d98323f --- /dev/null +++ b/dms-presentation/src/main/kotlin/team/aliens/dms/domain/volunteer/VolunteerWebAdapter.kt @@ -0,0 +1,160 @@ +package team.aliens.dms.domain.volunteer + +import jakarta.validation.Valid +import org.jetbrains.annotations.NotNull +import org.springframework.http.HttpStatus +import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.DeleteMapping +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.RequestMapping +import org.springframework.web.bind.annotation.ResponseStatus +import org.springframework.web.bind.annotation.RestController +import team.aliens.dms.domain.volunteer.dto.request.CreateVolunteerRequest +import team.aliens.dms.domain.volunteer.dto.request.CreateVolunteerWebRequest +import team.aliens.dms.domain.volunteer.dto.request.UpdateVolunteerRequest +import team.aliens.dms.domain.volunteer.dto.request.UpdateVolunteerWebRequest +import team.aliens.dms.domain.volunteer.dto.response.AvailableVolunteersResponse +import team.aliens.dms.domain.volunteer.dto.response.CurrentVolunteerApplicantsResponse +import team.aliens.dms.domain.volunteer.dto.response.QueryMyVolunteerApplicationResponse +import team.aliens.dms.domain.volunteer.dto.response.VolunteerApplicantsResponse +import team.aliens.dms.domain.volunteer.dto.response.VolunteersResponse +import team.aliens.dms.domain.volunteer.usecase.ApplyVolunteerUseCase +import team.aliens.dms.domain.volunteer.usecase.ApproveVolunteerApplicationUseCase +import team.aliens.dms.domain.volunteer.usecase.CreateVolunteerUseCase +import team.aliens.dms.domain.volunteer.usecase.DeleteVolunteerUseCase +import team.aliens.dms.domain.volunteer.usecase.ExcludeVolunteerApplicationUseCase +import team.aliens.dms.domain.volunteer.usecase.ManagerGetAllVolunteersUseCase +import team.aliens.dms.domain.volunteer.usecase.QueryAppliedStudentUseCase +import team.aliens.dms.domain.volunteer.usecase.QueryAvailableVolunteersUseCase +import team.aliens.dms.domain.volunteer.usecase.QueryCurrentVolunteerApplicantsUseCase +import team.aliens.dms.domain.volunteer.usecase.QueryMyVolunteerApplicationUseCase +import team.aliens.dms.domain.volunteer.usecase.RejectVolunteerApplicationUseCase +import team.aliens.dms.domain.volunteer.usecase.UnapplyVolunteerUseCase +import team.aliens.dms.domain.volunteer.usecase.UpdateVolunteerUseCase +import java.util.UUID + +@Validated +@RequestMapping("/volunteers") +@RestController +class VolunteerWebAdapter( + private val applyVolunteerUseCase: ApplyVolunteerUseCase, + private val unapplyVolunteerUseCase: UnapplyVolunteerUseCase, + private val createVolunteerUseCase: CreateVolunteerUseCase, + private val updateVolunteerUseCase: UpdateVolunteerUseCase, + private val deleteVolunteerUseCase: DeleteVolunteerUseCase, + private val approveVolunteerApplicationUseCase: ApproveVolunteerApplicationUseCase, + private val rejectVolunteerApplicationUseCase: RejectVolunteerApplicationUseCase, + private val queryAvailableVolunteersUseCase: QueryAvailableVolunteersUseCase, + private val queryMyVolunteerApplicationUseCase: QueryMyVolunteerApplicationUseCase, + private val managerGetAllVolunteersUseCase: ManagerGetAllVolunteersUseCase, + private val queryAppliedStudentUseCase: QueryAppliedStudentUseCase, + private val queryCurrentVolunteerApplicantsUseCase: QueryCurrentVolunteerApplicantsUseCase, + private val excludeVolunteerApplicationUseCase: ExcludeVolunteerApplicationUseCase +) { + + @ResponseStatus(HttpStatus.CREATED) + @PostMapping("/apply/{volunteer-application-id}") + fun applyVolunteer(@PathVariable("volunteer-application-id") @NotNull volunteerApplicationId: UUID) { + applyVolunteerUseCase.execute(volunteerApplicationId) + } + + @ResponseStatus(HttpStatus.NO_CONTENT) + @DeleteMapping("/cancel/{volunteer-application-id}") + fun unapplyVolunteer(@PathVariable("volunteer-application-id") @NotNull volunteerApplicationId: UUID) { + unapplyVolunteerUseCase.execute(volunteerApplicationId) + } + + @ResponseStatus(HttpStatus.OK) + @GetMapping("/my/application") + fun getMyVolunteerApplications(): QueryMyVolunteerApplicationResponse { + return queryMyVolunteerApplicationUseCase.execute() + } + + @ResponseStatus(HttpStatus.OK) + @GetMapping + fun getAvailableVolunteers(): AvailableVolunteersResponse { + return queryAvailableVolunteersUseCase.execute() + } + + @ResponseStatus(HttpStatus.CREATED) + @PostMapping + fun createVolunteer(@Valid @RequestBody createVolunteerWebRequest: CreateVolunteerWebRequest) { + createVolunteerUseCase.execute( + CreateVolunteerRequest( + name = createVolunteerWebRequest.name, + content = createVolunteerWebRequest.content, + availableGrade = createVolunteerWebRequest.availableGrade, + availableSex = createVolunteerWebRequest.availableSex, + score = createVolunteerWebRequest.score, + optionalScore = createVolunteerWebRequest.optionalScore, + maxApplicants = createVolunteerWebRequest.maxApplicants, + ) + ) + } + + @ResponseStatus(HttpStatus.NO_CONTENT) + @PatchMapping("/{volunteer-id}") + fun updateVolunteer( + @Valid @RequestBody updateVolunteerWebRequest: UpdateVolunteerWebRequest, + @PathVariable("volunteer-id") @NotNull volunteerId: UUID + ) { + updateVolunteerUseCase.execute( + UpdateVolunteerRequest( + name = updateVolunteerWebRequest.name, + content = updateVolunteerWebRequest.content, + availableGrade = updateVolunteerWebRequest.availableGrade, + availableSex = updateVolunteerWebRequest.availableSex, + score = updateVolunteerWebRequest.score, + optionalScore = updateVolunteerWebRequest.optionalScore, + maxApplicants = updateVolunteerWebRequest.maxApplicants, + volunteerId = volunteerId + ) + ) + } + + @ResponseStatus(HttpStatus.NO_CONTENT) + @DeleteMapping("/{volunteer-id}") + fun deleteVolunteer(@PathVariable("volunteer-id") @NotNull volunteerId: UUID) { + deleteVolunteerUseCase.execute(volunteerId) + } + + @ResponseStatus(HttpStatus.NO_CONTENT) + @PostMapping("/approve/{volunteer-application-id}") + fun approveVolunteerApplication(@PathVariable("volunteer-application-id") volunteerApplicationId: UUID) { + approveVolunteerApplicationUseCase.execute(volunteerApplicationId) + } + + @ResponseStatus(HttpStatus.NO_CONTENT) + @DeleteMapping("/reject/{volunteer-application-id}") + fun rejectVolunteerApplication(@PathVariable("volunteer-application-id") volunteerApplicationId: UUID) { + rejectVolunteerApplicationUseCase.execute(volunteerApplicationId) + } + + @ResponseStatus(HttpStatus.NO_CONTENT) + @DeleteMapping("/exclude/{volunteer-application-id}") + fun excludeVolunteerApplication(@PathVariable("volunteer-application-id") volunteerApplicationId: UUID) { + excludeVolunteerApplicationUseCase.execute(volunteerApplicationId) + } + + @ResponseStatus(HttpStatus.OK) + @GetMapping("/manager") + fun managerGetAllVolunteers(): VolunteersResponse { + return managerGetAllVolunteersUseCase.execute() + } + + @ResponseStatus(HttpStatus.OK) + @GetMapping("/{volunteer-id}") + fun queryAppliedStudent(@PathVariable("volunteer-id") @NotNull volunteerId: UUID): VolunteerApplicantsResponse { + return queryAppliedStudentUseCase.execute(volunteerId) + } + + @ResponseStatus(HttpStatus.OK) + @GetMapping("/current") + fun queryAppliedStudent(): CurrentVolunteerApplicantsResponse { + return queryCurrentVolunteerApplicantsUseCase.execute() + } +} diff --git a/dms-presentation/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/CreateVolunteerWebRequest.kt b/dms-presentation/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/CreateVolunteerWebRequest.kt new file mode 100644 index 000000000..c40ddd17e --- /dev/null +++ b/dms-presentation/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/CreateVolunteerWebRequest.kt @@ -0,0 +1,30 @@ +package team.aliens.dms.domain.volunteer.dto.request + +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.NotNull +import jakarta.validation.constraints.Size + +data class CreateVolunteerWebRequest( + + @field:NotBlank + val name: String, + + @field:NotBlank + val content: String, + + @field:Size(min = 1, max = 6) + @field:NotBlank + val availableSex: String, + + @field:Size(min = 1, max = 14) + @field:NotBlank + val availableGrade: String, + + @field:NotNull + val score: Int, + + val optionalScore: Int = 0, + + @field:NotNull + val maxApplicants: Int +) diff --git a/dms-presentation/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/UpdateVolunteerWebRequest.kt b/dms-presentation/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/UpdateVolunteerWebRequest.kt new file mode 100644 index 000000000..8a819a3bf --- /dev/null +++ b/dms-presentation/src/main/kotlin/team/aliens/dms/domain/volunteer/dto/request/UpdateVolunteerWebRequest.kt @@ -0,0 +1,30 @@ +package team.aliens.dms.domain.volunteer.dto.request + +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.NotNull +import jakarta.validation.constraints.Size + +data class UpdateVolunteerWebRequest( + + @field:NotBlank + val name: String, + + @field:NotBlank + val content: String, + + @field:Size(min = 1, max = 6) + @field:NotBlank + val availableSex: String, + + @field:Size(min = 1, max = 14) + @field:NotBlank + val availableGrade: String, + + @field:NotNull + val score: Int, + + val optionalScore: Int = 0, + + @field:NotNull + val maxApplicants: Int +)