Skip to content
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

merge: (#798) 모범학생 후보 리스트 조회 기능 추가 #803

Open
wants to merge 21 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
893a946
feat: (#798) 모범학생 후보 리스트 조회 기능 추가
pji-min Feb 11, 2025
53c05bb
refactor: (#798) 변수명 변경
pji-min Feb 12, 2025
da740a6
refactor: (#798) 변수명 변경
pji-min Feb 12, 2025
320c0d6
refactor: (#798) requestDate 변수명 변경
pji-min Feb 12, 2025
39dca3a
refactor: (#798) 어노테이션 변경
pji-min Feb 12, 2025
6916cc3
fix: (#798) API 경로 수정
pji-min Feb 12, 2025
a7a9c5d
style: (#798) 줄바꿈 수정
pji-min Feb 14, 2025
347cdcb
refactor: (#798) 예외 처리 방식 개선
pji-min Feb 14, 2025
894ac8e
refactor: (#798) GetModelStudentsUseCase 및 컨트롤러 students 도메인 이동
pji-min Feb 14, 2025
5b88709
refactor: (#798) 모범학생 조회 로직 정리 및 도메인 이동
pji-min Feb 15, 2025
7e4d5e8
refactor: (#798) 불필요한 repository 삭제
pji-min Feb 17, 2025
8eea190
refactor: (#798) spi.vo 디렉토리로 이동
pji-min Feb 17, 2025
c02d515
refactor: (#798) DTO명 수정
pji-min Feb 17, 2025
dcfd03a
feat: (#798) DTO 추가
pji-min Feb 17, 2025
03f95b1
refactor: (#798) 와일드카드 삭제 및 응답 형식 수정
pji-min Feb 17, 2025
15ffd75
refactor: (#798) 클래스 명 변경
pji-min Feb 17, 2025
e8b3259
refactor: (#798) id null 체크 로직 수정
pji-min Feb 17, 2025
d1451e9
style: (#798) 줄바꿈 수정
pji-min Feb 17, 2025
e8f0add
refactor: (#798) StudentService 주입으로 변경
pji-min Feb 19, 2025
7cc6def
Merge branch 'develop' into feature/(798)-todo
pji-min Feb 24, 2025
74810de
Merge branch 'develop' into feature/(798)-todo
pji-min Mar 3, 2025
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
Expand Up @@ -8,6 +8,8 @@ import team.aliens.dms.domain.point.spi.vo.StudentWithPointVO
import team.aliens.dms.domain.room.model.Room
import team.aliens.dms.domain.student.model.Student
import team.aliens.dms.domain.student.spi.vo.AllStudentsVO
import team.aliens.dms.domain.vote.dto.response.ModelStudentResponse
import java.time.LocalDate
import java.util.UUID

interface GetStudentService {
Expand Down Expand Up @@ -54,4 +56,7 @@ interface GetStudentService {
fun getAllStudentsByName(name: String?, schoolId: UUID): List<AllStudentsVO>

fun isApplicant(studentId: UUID): Boolean

fun getModelStudentList(date: LocalDate): List<ModelStudentResponse>

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import team.aliens.dms.domain.student.exception.StudentNotFoundException
import team.aliens.dms.domain.student.exception.StudentUpdateInfoNotFoundException
import team.aliens.dms.domain.student.model.Student
import team.aliens.dms.domain.student.spi.QueryStudentPort
import team.aliens.dms.domain.vote.dto.response.ModelStudentResponse
import team.aliens.dms.domain.vote.exception.validateStudentList
import java.time.LocalDate
import java.util.UUID
import java.util.function.Function

Expand Down Expand Up @@ -136,4 +139,30 @@ class GetStudentServiceImpl(
}
}
}

override fun getModelStudentList(date: LocalDate): List<ModelStudentResponse> {
val firstDayOfMonth = date.withDayOfMonth(1)
val lastDayOfMonth = date.withDayOfMonth(date.lengthOfMonth())

val startOfDay = firstDayOfMonth.atStartOfDay()
val endOfDay = lastDayOfMonth.atTime(23, 59, 59)

val modelStudentList = queryStudentPort.queryModelStudents(startOfDay, endOfDay)

if (modelStudentList.isEmpty()) {
throw StudentNotFoundException
}

validateStudentList(modelStudentList)

return modelStudentList.map { student ->
ModelStudentResponse(
id = student.id,
gcn = student.studentGcn,
name = student.studentName,
profileImageUrl = student.studentProfile
)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import team.aliens.dms.domain.manager.spi.vo.StudentWithTag
import team.aliens.dms.domain.point.spi.vo.StudentWithPointVO
import team.aliens.dms.domain.student.model.Student
import team.aliens.dms.domain.student.spi.vo.AllStudentsVO
import team.aliens.dms.domain.student.spi.vo.ModelStudentVO
import java.time.LocalDateTime
import java.util.UUID

interface QueryStudentPort {
Expand Down Expand Up @@ -41,4 +43,7 @@ interface QueryStudentPort {
fun queryAllStudentsByIdsIn(studentIds: List<UUID>): List<Student>

fun queryAllStudentsByName(name: String?, schoolId: UUID): List<AllStudentsVO>

fun queryModelStudents(startOfDay: LocalDateTime, endOfDay: LocalDateTime): List<ModelStudentVO>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package team.aliens.dms.domain.student.spi.vo

import java.util.UUID

data class ModelStudentVO(
val id: UUID,
val studentGcn: String,
val studentName: String,
val studentProfile: String?

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package team.aliens.dms.domain.student.usecase

import org.springframework.beans.factory.annotation.Qualifier
import team.aliens.dms.common.annotation.ReadOnlyUseCase
import team.aliens.dms.domain.student.service.GetStudentService
import team.aliens.dms.domain.vote.dto.response.ModelStudentResponse
import java.time.LocalDate

@ReadOnlyUseCase
class GetModelStudentsUseCase(
@Qualifier("getStudentServiceImpl") private val getStudentService: GetStudentService
) {
fun execute(date: LocalDate): List<ModelStudentResponse> {
return getStudentService.getModelStudentList(date)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.aliens.dms.domain.vote.dto.request

import java.time.LocalDate

data class ModelStudentListRequest(
val date: LocalDate

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package team.aliens.dms.domain.vote.dto.response

import java.util.UUID

data class ModelStudentResponse(
val id: UUID,
val gcn: String,
val name: String,
val profileImageUrl: String?

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package team.aliens.dms.domain.vote.dto.response

data class ModelStudentsResponse(
val students: List<ModelStudentResponse>

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package team.aliens.dms.domain.vote.exception

import team.aliens.dms.common.error.ErrorProperty
import team.aliens.dms.common.error.ErrorStatus

enum class VoteErrorCode(
private val status: Int,
private val message: String,
private val sequence: Int
) : ErrorProperty {

STUDENT_NOT_FOUND(ErrorStatus.NOT_FOUND, "Student Not Found", 1),
STUDENT_ID_NOT_FOUND(ErrorStatus.BAD_REQUEST, "Student ID Not Found", 2)
;

override fun status(): Int = status
override fun message(): String = message
override fun code(): String = "Vote-$status-$sequence"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package team.aliens.dms.domain.vote.exception

import team.aliens.dms.common.error.DmsException
import team.aliens.dms.domain.student.spi.vo.ModelStudentVO

object StudentNotFoundException : DmsException(
VoteErrorCode.STUDENT_NOT_FOUND
)

object StudentIdNotFoundException : DmsException(
VoteErrorCode.STUDENT_ID_NOT_FOUND
)

fun validateStudentList(modelStudentList: List<ModelStudentVO>) {
if (modelStudentList.isEmpty()) {
throw StudentNotFoundException
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package team.aliens.dms.global.security

import org.apache.http.protocol.HTTP
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
Expand Down Expand Up @@ -223,6 +224,10 @@ class SecurityConfig(
.requestMatchers(HttpMethod.GET, "/volunteers").hasAuthority(STUDENT.name)
.requestMatchers(HttpMethod.GET, "/volunteers/my/application").hasAuthority(STUDENT.name)

authorize
// /vote
.requestMatchers(HttpMethod.GET, "/vote/candidate-list/{requestDate}").hasAnyAuthority(MANAGER.name)

.anyRequest().denyAll()
}
http
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ import team.aliens.dms.domain.manager.dto.PointFilter
import team.aliens.dms.domain.manager.dto.PointFilterType
import team.aliens.dms.domain.manager.dto.Sort
import team.aliens.dms.domain.manager.spi.vo.StudentWithTag
import team.aliens.dms.domain.point.model.PointType
import team.aliens.dms.domain.point.spi.vo.StudentWithPointVO
import team.aliens.dms.domain.student.model.Student
import team.aliens.dms.domain.student.spi.StudentPort
import team.aliens.dms.domain.student.spi.vo.AllStudentsVO
import team.aliens.dms.domain.student.spi.vo.ModelStudentVO
import team.aliens.dms.persistence.point.entity.QPointHistoryJpaEntity
import team.aliens.dms.persistence.point.entity.QPointHistoryJpaEntity.pointHistoryJpaEntity
import team.aliens.dms.persistence.room.entity.QRoomJpaEntity.roomJpaEntity
import team.aliens.dms.persistence.student.entity.QStudentJpaEntity.studentJpaEntity
Expand All @@ -32,6 +35,7 @@ import team.aliens.dms.persistence.student.repository.vo.QQueryStudentsWithTagVO
import team.aliens.dms.persistence.tag.entity.QStudentTagJpaEntity.studentTagJpaEntity
import team.aliens.dms.persistence.tag.entity.QTagJpaEntity.tagJpaEntity
import team.aliens.dms.persistence.tag.mapper.TagMapper
import java.time.LocalDateTime
import java.util.UUID

@Component
Expand All @@ -40,6 +44,7 @@ class StudentPersistenceAdapter(
private val tagMapper: TagMapper,
private val studentRepository: StudentJpaRepository,
private val queryFactory: JPAQueryFactory,
private val studentJpaRepository: StudentJpaRepository,
) : StudentPort {

override fun queryStudentBySchoolIdAndGcn(
Expand Down Expand Up @@ -385,4 +390,45 @@ class StudentPersistenceAdapter(
)
.fetch()
}

override fun queryModelStudents(startOfDay: LocalDateTime, endOfDay: LocalDateTime): List<ModelStudentVO> {

val penalizedStudentGcn = findPenalizedStudentGcn(startOfDay, endOfDay)

val students = studentJpaRepository.findAll()

return students
.mapNotNull { student ->
student.id?.let {
val gcn = createGcn(student.grade, student.classRoom, student.number)
ModelStudentVO(
id = it,
studentGcn = gcn,
studentName = student.name,
studentProfile = student.profileImageUrl
)
}
}
.filter { it.studentGcn !in penalizedStudentGcn }
}

private fun findPenalizedStudentGcn(startOfDay: LocalDateTime, endOfDay: LocalDateTime): List<String> {
return queryFactory
.select(
QPointHistoryJpaEntity.pointHistoryJpaEntity.studentGcn
)
.from(QPointHistoryJpaEntity.pointHistoryJpaEntity)
.where(
QPointHistoryJpaEntity.pointHistoryJpaEntity.isCancel.isFalse,
QPointHistoryJpaEntity.pointHistoryJpaEntity.pointType.eq(PointType.MINUS),
QPointHistoryJpaEntity.pointHistoryJpaEntity.createdAt.between(startOfDay, endOfDay)
)
.fetch()
}

private fun createGcn(grade: Int, classRoom: Int, number: Int): String {
val formattedNumber = String.format("%02d", number)
return "$grade$classRoom$formattedNumber"
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import jakarta.validation.Valid
import jakarta.validation.constraints.Email
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.NotNull
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.http.HttpStatus
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.DeleteMapping
Expand Down Expand Up @@ -40,20 +41,23 @@ import team.aliens.dms.domain.student.dto.request.UpdateStudentProfileWebRequest
import team.aliens.dms.domain.student.usecase.CheckDuplicatedAccountIdUseCase
import team.aliens.dms.domain.student.usecase.CheckDuplicatedEmailUseCase
import team.aliens.dms.domain.student.usecase.CheckStudentGcnUseCase
import team.aliens.dms.domain.student.usecase.ExportStudentUseCase
import team.aliens.dms.domain.student.usecase.SignUpUseCase
import team.aliens.dms.domain.student.usecase.FindStudentAccountIdUseCase
import team.aliens.dms.domain.student.usecase.ImportStudentUseCase
import team.aliens.dms.domain.student.usecase.ManagerGetAllStudentsUseCase
import team.aliens.dms.domain.student.usecase.QueryStudentDetailsUseCase
import team.aliens.dms.domain.student.usecase.RemoveStudentUseCase
import team.aliens.dms.domain.student.usecase.ResetStudentPasswordUseCase
import team.aliens.dms.domain.student.usecase.SignUpUseCase
import team.aliens.dms.domain.student.usecase.StudentGetAllStudentsUseCase
import team.aliens.dms.domain.student.usecase.UpdateStudentProfileUseCase
import team.aliens.dms.domain.student.usecase.StudentMyPageUseCase
import team.aliens.dms.domain.student.usecase.StudentWithdrawalUseCase
import team.aliens.dms.domain.student.usecase.ExportStudentUseCase
import team.aliens.dms.domain.student.usecase.ManagerGetAllStudentsUseCase
import team.aliens.dms.domain.student.usecase.QueryStudentDetailsUseCase
import team.aliens.dms.domain.student.usecase.RemoveStudentUseCase
import team.aliens.dms.domain.student.usecase.UpdateStudentGcnByFileUseCase
import team.aliens.dms.domain.student.usecase.UpdateStudentProfileUseCase
import team.aliens.dms.domain.student.usecase.UpdateStudentRoomByFileUseCase
import team.aliens.dms.domain.student.usecase.ImportStudentUseCase
import team.aliens.dms.domain.student.usecase.StudentGetAllStudentsUseCase
import team.aliens.dms.domain.student.usecase.GetModelStudentsUseCase
import team.aliens.dms.domain.vote.dto.response.ModelStudentsResponse
import java.time.LocalDate
import java.util.UUID

@Validated
Expand All @@ -76,7 +80,8 @@ class StudentWebAdapter(
private val updateStudentGcnByFileUseCase: UpdateStudentGcnByFileUseCase,
private val updateStudentRoomByFileUseCase: UpdateStudentRoomByFileUseCase,
private val importStudentUseCase: ImportStudentUseCase,
private val studentGetAllStudentsUseCase: StudentGetAllStudentsUseCase
private val studentGetAllStudentsUseCase: StudentGetAllStudentsUseCase,
private val getModelStudentsUseCase: GetModelStudentsUseCase
) {

@ResponseStatus(HttpStatus.CREATED)
Expand Down Expand Up @@ -237,4 +242,15 @@ class StudentWebAdapter(
fun studentGetAllStudents(@RequestParam(required = false) name: String?): StudentsResponse {
return studentGetAllStudentsUseCase.execute(name)
}

@GetMapping("/candidate-list")
fun getModelStudents(
@RequestParam
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
date: LocalDate
): ModelStudentsResponse {
val students = getModelStudentsUseCase.execute(date)
return ModelStudentsResponse(students = students)
}

}