Skip to content

Commit

Permalink
Merge branch 'develop' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
rlaisqls committed Apr 3, 2023
2 parents e9b5ec0 + 088bff5 commit 0368930
Show file tree
Hide file tree
Showing 15 changed files with 189 additions and 59 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package team.aliens.dms.domain.notice.dto

import java.time.LocalDateTime
import java.util.UUID

data class QueryNoticeDetailsResponse(
val id: UUID,
val title: String,
val content: String,
val createdAt: LocalDateTime
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package team.aliens.dms.domain.notice.usecase

import java.util.UUID
import team.aliens.dms.common.annotation.ReadOnlyUseCase
import team.aliens.dms.domain.manager.exception.ManagerNotFoundException
import team.aliens.dms.domain.notice.dto.QueryNoticeDetailsResponse
Expand All @@ -9,7 +10,6 @@ import team.aliens.dms.domain.notice.spi.NoticeSecurityPort
import team.aliens.dms.domain.notice.spi.QueryNoticePort
import team.aliens.dms.domain.school.validateSameSchool
import team.aliens.dms.domain.user.exception.UserNotFoundException
import java.util.UUID

@ReadOnlyUseCase
class QueryNoticeDetailsUseCase(
Expand All @@ -28,6 +28,7 @@ class QueryNoticeDetailsUseCase(
validateSameSchool(writer.schoolId, viewer.schoolId)

return QueryNoticeDetailsResponse(
id = notice.id,
title = notice.title,
content = notice.content,
createdAt = notice.createdAt!!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package team.aliens.dms.domain.studyroom.spi

import team.aliens.dms.domain.studyroom.model.SeatType
import java.util.UUID
import team.aliens.dms.domain.studyroom.model.SeatType

interface QuerySeatTypePort {

fun queryAllSeatTypeBySchoolId(schoolId: UUID): List<SeatType>

fun queryAllSeatTypeByStudyRoomId(studyRoomId: UUID): List<SeatType>

fun existsSeatTypeByName(name: String): Boolean

fun querySeatTypeById(seatTypeId: UUID): SeatType?
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package team.aliens.dms.domain.studyroom.usecase

import java.util.UUID
import team.aliens.dms.common.annotation.ReadOnlyUseCase
import team.aliens.dms.domain.studyroom.dto.QuerySeatTypesResponse
import team.aliens.dms.domain.studyroom.dto.QuerySeatTypesResponse.TypeElement
Expand All @@ -15,19 +16,22 @@ class QuerySeatTypesUseCase(
private val querySeatTypePort: QuerySeatTypePort
) {

fun execute(): QuerySeatTypesResponse {
fun execute(studyRoomId: UUID?): QuerySeatTypesResponse {
val currentUserId = securityPort.getCurrentUserId()
val user = queryUserPort.queryUserById(currentUserId) ?: throw UserNotFoundException

val seatTypes = querySeatTypePort
.queryAllSeatTypeBySchoolId(user.schoolId).map {
val seatTypes = studyRoomId?.let {
querySeatTypePort.queryAllSeatTypeByStudyRoomId(studyRoomId)
} ?: querySeatTypePort.queryAllSeatTypeBySchoolId(user.schoolId)

return QuerySeatTypesResponse(
seatTypes.map {
TypeElement(
id = it.id,
name = it.name,
color = it.color
)
}

return QuerySeatTypesResponse(seatTypes)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class QueryNoticeDetailsUseCaseTests {

private val queryNoticeDetailsResponseStub by lazy {
QueryNoticeDetailsResponse(
id = noticeStub.id,
title = noticeStub.title,
content = noticeStub.content,
createdAt = createdAt
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package team.aliens.dms.domain.studyroom.stub

import java.time.LocalTime
import java.util.UUID
import team.aliens.dms.domain.student.model.Sex
import team.aliens.dms.domain.studyroom.model.Seat
import team.aliens.dms.domain.studyroom.model.SeatApplication
import team.aliens.dms.domain.studyroom.model.SeatStatus
import team.aliens.dms.domain.studyroom.model.SeatType
import team.aliens.dms.domain.studyroom.model.StudyRoom
import team.aliens.dms.domain.studyroom.model.TimeSlot
import java.time.LocalTime
import java.util.UUID

internal fun createStudyRoomStub(
id: UUID = UUID.randomUUID(),
Expand Down Expand Up @@ -78,3 +79,15 @@ internal fun createSeatApplicationStub(
timeSlotId = timeSlotId,
studentId = studentId
)

internal fun createSeatTypeStub(
id: UUID = UUID.randomUUID(),
schoolId: UUID = UUID.randomUUID(),
name: String = "자리",
color: String = "#FFFFFF",
) = SeatType(
id = id,
schoolId = schoolId,
name = name,
color = color
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package team.aliens.dms.domain.studyroom.usecase

import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import java.util.UUID
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertAll
import org.junit.jupiter.api.assertThrows
import team.aliens.dms.domain.studyroom.spi.QuerySeatTypePort
import team.aliens.dms.domain.studyroom.spi.StudyRoomQueryUserPort
import team.aliens.dms.domain.studyroom.spi.StudyRoomSecurityPort
import team.aliens.dms.domain.studyroom.stub.createSeatTypeStub
import team.aliens.dms.domain.user.exception.UserNotFoundException
import team.aliens.dms.domain.user.stub.createUserStub

class QuerySeatTypesUseCaseTests {

private val securityPort: StudyRoomSecurityPort = mockk(relaxed = true)
private val queryUserPort: StudyRoomQueryUserPort = mockk(relaxed = true)
private val querySeatTypePort: QuerySeatTypePort = mockk(relaxed = true)

private val querySeatTypesUseCase = QuerySeatTypesUseCase(
securityPort, queryUserPort, querySeatTypePort
)

private val userId = UUID.randomUUID()
private val schoolId = UUID.randomUUID()
private val studyRoomId = UUID.randomUUID()

private val userStub by lazy {
createUserStub(
id = userId,
schoolId = schoolId
)
}

private val seatTypesStub by lazy {
listOf(createSeatTypeStub())
}

@Test
fun `자리 종류 조회 성공 (studyRoomId가 null인 경우)`() {
// given
every { securityPort.getCurrentUserId() } returns userId
every { queryUserPort.queryUserById(userId) } returns userStub
every { querySeatTypePort.queryAllSeatTypeBySchoolId(schoolId) } returns seatTypesStub

// when
val response = querySeatTypesUseCase.execute(null)

// then
assertAll(
{ verify(exactly = 1) { querySeatTypePort.queryAllSeatTypeBySchoolId(schoolId) } },
{ assertEquals(response.types.size, seatTypesStub.size) }
)
}

@Test
fun `자리 종류 조회 성공 (studyRoomId가 null이 아닌 경우)`() {
// given
every { securityPort.getCurrentUserId() } returns userId
every { queryUserPort.queryUserById(userId) } returns userStub
every { querySeatTypePort.queryAllSeatTypeByStudyRoomId(studyRoomId) } returns seatTypesStub

// when
val response = querySeatTypesUseCase.execute(studyRoomId)

// then
assertAll(
{ verify(exactly = 1) { querySeatTypePort.queryAllSeatTypeByStudyRoomId(studyRoomId) } },
{ assertEquals(response.types.size, seatTypesStub.size) }
)
}

@Test
fun `유저가 존재하지 않음`() {
// given
every { securityPort.getCurrentUserId() } returns userId
every { queryUserPort.queryUserById(userId) } returns null

// when
assertThrows<UserNotFoundException> {
querySeatTypesUseCase.execute(null)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.querydsl.core.types.dsl.CaseBuilder
import com.querydsl.core.types.dsl.Expressions
import com.querydsl.jpa.JPAExpressions.select
import com.querydsl.jpa.impl.JPAQueryFactory
import java.util.UUID
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Component
import team.aliens.dms.domain.manager.dto.PointFilter
Expand All @@ -35,7 +36,6 @@ import team.aliens.dms.persistence.tag.entity.QStudentTagJpaEntity.studentTagJpa
import team.aliens.dms.persistence.tag.entity.QTagJpaEntity.tagJpaEntity
import team.aliens.dms.persistence.tag.mapper.TagMapper
import team.aliens.dms.persistence.user.entity.QUserJpaEntity.userJpaEntity
import java.util.UUID

@Component
class StudentPersistenceAdapter(
Expand Down Expand Up @@ -127,16 +127,16 @@ class StudentPersistenceAdapter(
.join(studentJpaEntity.user, userJpaEntity)
.join(userJpaEntity.school, schoolJpaEntity)
.leftJoin(studentTagJpaEntity)
.on(studentTagJpaEntity.student.id.eq(studentJpaEntity.id))
.leftJoin(tagJpaEntity).distinct()
.on(eqTag())
.on(studentJpaEntity.id.eq(studentTagJpaEntity.student.id)).fetchJoin()
.leftJoin(tagJpaEntity)
.on(studentTagJpaEntity.tag.id.eq(tagJpaEntity.id))
.leftJoin(pointHistoryJpaEntity)
.on(eqStudentRecentPointHistory())
.on(eqStudentRecentPointHistory())
.where(
userJpaEntity.school.id.eq(schoolId),
nameContains(name),
pointTotalBetween(pointFilter),
schoolEq(schoolId),
tagIdsIn(tagIds)
hasAllTags(tagIds)
)
.orderBy(
sortFilter(sort),
Expand Down Expand Up @@ -171,25 +171,13 @@ class StudentPersistenceAdapter(
profileImageUrl = it.profileImageUrl,
sex = it.sex,
tags = it.tags
.map {
tag ->
.map { tag ->
tagMapper.toDomain(tag)!!
}
)
}
}

private fun tagIdsIn(tagIds: List<UUID>?) =
tagIds?.run { studentTagJpaEntity.tag.id.`in`(tagIds) }

private fun eqTag(): BooleanExpression? {
return tagJpaEntity.id.`in`(
select(studentTagJpaEntity.tag.id)
.from(studentTagJpaEntity)
.where(studentTagJpaEntity.student.id.eq(studentJpaEntity.id))
)
}

private fun nameContains(name: String?) = name?.run { studentJpaEntity.name.contains(this) }

private fun pointTotalBetween(pointFilter: PointFilter): BooleanExpression? {
Expand Down Expand Up @@ -221,7 +209,16 @@ class StudentPersistenceAdapter(
}
}

private fun schoolEq(schoolId: UUID) = userJpaEntity.school.id.eq(schoolId)
private fun hasAllTags(tagIds: List<UUID>?): BooleanExpression? =
tagIds?.run {
studentJpaEntity.id.`in`(
select(studentTagJpaEntity.student.id)
.from(studentTagJpaEntity)
.where(studentTagJpaEntity.tag.id.`in`(tagIds))
.groupBy(studentTagJpaEntity.student)
.having(studentTagJpaEntity.count().eq(tagIds.size.toLong()))
)
}

private fun sortFilter(sort: Sort): OrderSpecifier<*>? {
return when (sort) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
package team.aliens.dms.persistence.studyroom

import com.querydsl.jpa.impl.JPAQueryFactory
import java.util.UUID
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Component
import team.aliens.dms.domain.studyroom.model.SeatType
import team.aliens.dms.domain.studyroom.spi.SeatTypePort
import team.aliens.dms.persistence.studyroom.entity.QSeatJpaEntity.seatJpaEntity
import team.aliens.dms.persistence.studyroom.entity.QSeatTypeJpaEntity.seatTypeJpaEntity
import team.aliens.dms.persistence.studyroom.entity.QStudyRoomJpaEntity.studyRoomJpaEntity
import team.aliens.dms.persistence.studyroom.mapper.SeatTypeMapper
import team.aliens.dms.persistence.studyroom.repository.SeatTypeJpaRepository
import java.util.UUID

@Component
class SeatTypePersistenceAdapter(
private val seatTypeMapper: SeatTypeMapper,
private val seatTypeRepository: SeatTypeJpaRepository
private val seatTypeRepository: SeatTypeJpaRepository,
private val queryFactory: JPAQueryFactory,
) : SeatTypePort {

override fun queryAllSeatTypeBySchoolId(schoolId: UUID) = seatTypeRepository
.findAllBySchoolId(schoolId).map {
seatTypeMapper.toDomain(it)!!
}

override fun queryAllSeatTypeByStudyRoomId(studyRoomId: UUID) =
queryFactory
.select(seatTypeJpaEntity).distinct()
.from(studyRoomJpaEntity)
.join(seatJpaEntity).on(studyRoomJpaEntity.id.eq(seatJpaEntity.studyRoom.id))
.join(seatJpaEntity.type, seatTypeJpaEntity)
.where(studyRoomJpaEntity.id.eq(studyRoomId))
.fetch()
.map {
seatTypeMapper.toDomain(it)!!
}

override fun existsSeatTypeByName(name: String) = seatTypeRepository.existsByName(name)

override fun querySeatTypeById(seatTypeId: UUID) = seatTypeMapper.toDomain(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package team.aliens.dms.thirdparty.parser

import com.fasterxml.uuid.Generators
import java.io.ByteArrayOutputStream
import java.io.File
import java.time.format.DateTimeFormatter
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.ss.usermodel.Cell
import org.apache.poi.ss.usermodel.CellStyle
import org.apache.poi.ss.usermodel.HorizontalAlignment
import org.apache.poi.ss.usermodel.IndexedColors
Expand All @@ -28,9 +32,6 @@ import team.aliens.dms.domain.studyroom.spi.vo.StudentSeatInfo
import team.aliens.dms.domain.user.exception.UserNotFoundException
import team.aliens.dms.thirdparty.parser.exception.ExcelExtensionMismatchException
import team.aliens.dms.thirdparty.parser.exception.ExcelInvalidFileException
import java.io.ByteArrayOutputStream
import java.io.File
import java.time.format.DateTimeFormatter

@Component
class ExcelAdapter : ParseFilePort, WriteFilePort {
Expand All @@ -43,7 +44,10 @@ class ExcelAdapter : ParseFilePort, WriteFilePort {
try {
val worksheet = workbook.getSheetAt(0)
for (i in 1..worksheet.lastRowNum) {
val excelData = worksheet.getRow(i).run {
val row = worksheet.getRow(i)
if (row.isFirstCellBlank()) continue

val excelData = row.run {
VerifiedStudent(
id = Generators.timeBasedGenerator().generate(),
schoolName = schoolName,
Expand All @@ -70,6 +74,8 @@ class ExcelAdapter : ParseFilePort, WriteFilePort {
return verifiedStudents
}

private fun Row.isFirstCellBlank() = cellIterator().next().cellType == Cell.CELL_TYPE_BLANK

private fun Row.getStringValue(idx: Int) = getCell(idx, CREATE_NULL_AS_BLANK).stringCellValue

private fun Row.getIntValue(idx: Int) = getCell(idx, CREATE_NULL_AS_BLANK).numericCellValue.toInt()
Expand Down Expand Up @@ -151,6 +157,8 @@ class ExcelAdapter : ParseFilePort, WriteFilePort {

for (i in 1..worksheet.lastRowNum) {
val row = worksheet.getRow(i)
if (row.isFirstCellBlank()) continue

val studentSeat = row.run {
try {
studentSeatsMap[
Expand Down
Loading

0 comments on commit 0368930

Please sign in to comment.