Skip to content

Commit

Permalink
Accessibility 도메인을 JPA로 변환 (#366)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zeniuus authored Aug 18, 2024
1 parent 074fda7 commit e061e09
Show file tree
Hide file tree
Showing 76 changed files with 903 additions and 1,943 deletions.
2 changes: 0 additions & 2 deletions app-server/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
name: scc

services:
postgres:
image: postgres:14.5-alpine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ dependencies {
implementation("org.sejda.webp-imageio:webp-imageio-sejda:0.1.0")
implementation("org.bytedeco:javacv-platform:1.5.10")

implementation("org.springframework.boot:spring-boot-starter-data-jpa")

testImplementation("org.mockito.kotlin:mockito-kotlin:5.1.0")

integrationTestImplementation(projects.crossCuttingConcern.test.springIt)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.mockito.Mockito
import org.mockito.kotlin.any
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.data.repository.findByIdOrNull
import java.time.Duration

@SpringBootTest(classes = [SccSpringITApplication::class])
Expand All @@ -39,9 +40,9 @@ class BlurFacesInLatestBuildingAccessibilityImagesUseCaseTest : BlurFacesITBase(
mockDetectFacesWithNoFaceImage(MockDetectFacesService.URL_WITHOUT_FACES, imageBytes)
Mockito.`when`(imageProcessor.blur(any(), any(), any())).thenReturn(imageBytes)

placeAccessibilityRepository.removeAll()
buildingAccessibilityRepository.removeAll()
accessibilityImageFaceBlurringHistoryRepository.removeAll()
placeAccessibilityRepository.deleteAll()
buildingAccessibilityRepository.deleteAll()
accessibilityImageFaceBlurringHistoryRepository.deleteAll()
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.mockito.Mockito
import org.mockito.kotlin.any
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.data.repository.findByIdOrNull
import java.time.Duration

@SpringBootTest(classes = [SccSpringITApplication::class])
Expand All @@ -39,9 +40,9 @@ class BlurFacesInLatestPlaceAccessibilityImagesUseCaseTest : BlurFacesITBase() {
mockDetectFacesWithNoFaceImage(MockDetectFacesService.URL_WITHOUT_FACES, imageBytes)
Mockito.`when`(imageProcessor.blur(any(), any(), any())).thenReturn(imageBytes)

placeAccessibilityRepository.removeAll()
buildingAccessibilityRepository.removeAll()
accessibilityImageFaceBlurringHistoryRepository.removeAll()
placeAccessibilityRepository.deleteAll()
buildingAccessibilityRepository.deleteAll()
accessibilityImageFaceBlurringHistoryRepository.deleteAll()
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ class AccessibilityApplicationService(

internal fun doGetAccessibility(placeId: String, userId: String?): GetAccessibilityResult {
val place = placeApplicationService.findPlace(placeId) ?: error("Cannot find place with $placeId")
val buildingAccessibility = buildingAccessibilityRepository.findByBuildingId(place.building.id)
val buildingAccessibility = buildingAccessibilityRepository.findFirstByBuildingIdAndDeletedAtIsNull(place.building.id)
val buildingAccessibilityComments = buildingAccessibilityCommentRepository.findByBuildingId(place.building.id)
val buildingAccessibilityChallengeCrusherGroup = buildingAccessibility?.id?.let { challengeService.getBuildingAccessibilityCrusherGroup(it) }
val placeAccessibility = placeAccessibilityRepository.findByPlaceId(placeId)
val placeAccessibility = placeAccessibilityRepository.findFirstByPlaceIdAndDeletedAtIsNull(placeId)
val placeAccessibilityComments = placeAccessibilityCommentRepository.findByPlaceId(placeId)
val placeAccessibilityChallengeCrusherGroup = placeAccessibility?.id?.let { challengeService.getPlaceAccessibilityCrusherGroup(it) }
val userInfoById = userApplicationService.getUsers(
Expand All @@ -91,7 +91,7 @@ class AccessibilityApplicationService(
buildingAccessibility.id,
)
} != null,
totalUpvoteCount = buildingAccessibilityUpvoteRepository.countUpvotes(buildingAccessibility.id),
totalUpvoteCount = buildingAccessibilityUpvoteRepository.countByBuildingAccessibilityId(buildingAccessibility.id),
)
}

Expand All @@ -113,18 +113,26 @@ class AccessibilityApplicationService(
)
},
placeAccessibilityChallengeCrusherGroup = placeAccessibilityChallengeCrusherGroup,
hasOtherPlacesToRegisterInSameBuilding = placeAccessibilityRepository.hasAccessibilityNotRegisteredPlaceInBuilding(
place.building.id
),
hasOtherPlacesToRegisterInSameBuilding = hasOtherPlacesToRegisterInSameBuilding(place.building),
isLastPlaceAccessibilityInBuilding = placeAccessibility?.isLastPlaceAccessibilityInBuilding(place.building.id)
?: false,
isFavoritePlace = userId?.let { placeFavoriteRepository.findFirstByUserIdAndPlaceIdAndDeletedAtIsNull(it, placeId) } != null,
totalFavoriteCount = placeFavoriteRepository.countByPlaceIdAndDeletedAtIsNull(placeId),
)
}

private fun hasOtherPlacesToRegisterInSameBuilding(building: Building): Boolean {
val placesInBuilding = placeApplicationService.findByBuildingId(building.id)
val placeAccessibilityExistingPlaceIds = placeAccessibilityRepository.findByPlaceIdInAndDeletedAtIsNull(placesInBuilding.map { it.id })
.map { it.placeId }
return placesInBuilding.any { it.id !in placeAccessibilityExistingPlaceIds }
}

private fun PlaceAccessibility.isLastPlaceAccessibilityInBuilding(buildingId: String): Boolean {
return placeAccessibilityRepository.findByBuildingId(buildingId).let {
val placeIds = placeApplicationService.findByBuildingId(buildingId)
.map { it.id }
.toSet()
return placeAccessibilityRepository.findByPlaceIdInAndDeletedAtIsNull(placeIds).let {
it.size == 1 && it[0].id == this.id
}
}
Expand All @@ -146,8 +154,9 @@ class AccessibilityApplicationService(
}
val placeIds = places.map { it.id }
// 현재 place 당 pa, ba 는 정책상 1개 이므로 단순 associateBy 해준다.
val pas = placeAccessibilityRepository.findByPlaceIds(placeIds).associateBy { it.placeId }
val bas = buildingAccessibilityRepository.findByPlaceIds(placeIds).associateBy { it.buildingId }
val pas = placeAccessibilityRepository.findByPlaceIdInAndDeletedAtIsNull(placeIds).associateBy { it.placeId }
val buildingIds = places.map { it.building.id }.toSet()
val bas = buildingAccessibilityRepository.findByBuildingIdInAndDeletedAtIsNull(buildingIds).associateBy { it.buildingId }
return places.map {
pas[it.id] to bas[it.building.id]
}
Expand Down Expand Up @@ -210,7 +219,7 @@ class AccessibilityApplicationService(
)
}
val buildingId = createBuildingAccessibilityParams.buildingId
if (buildingAccessibilityRepository.findByBuildingId(buildingId) != null) {
if (buildingAccessibilityRepository.findFirstByBuildingIdAndDeletedAtIsNull(buildingId) != null) {
throw SccDomainException("이미 접근성 정보가 등록된 건물입니다.")
}
val building = buildingService.getById(buildingId)!!
Expand Down Expand Up @@ -267,7 +276,7 @@ class AccessibilityApplicationService(
createPlaceAccessibilityParams: PlaceAccessibilityRepository.CreateParams,
createPlaceAccessibilityCommentParams: PlaceAccessibilityCommentRepository.CreateParams?,
): RegisterPlaceAccessibilityResult {
if (placeAccessibilityRepository.findByPlaceId(createPlaceAccessibilityParams.placeId) != null) {
if (placeAccessibilityRepository.findFirstByPlaceIdAndDeletedAtIsNull(createPlaceAccessibilityParams.placeId) != null) {
throw SccDomainException("이미 접근성 정보가 등록된 장소입니다.")
}
val place = placeApplicationService.findPlace(createPlaceAccessibilityParams.placeId)!!
Expand Down Expand Up @@ -311,7 +320,7 @@ class AccessibilityApplicationService(
placeAccessibility = result,
placeAccessibilityComment = placeAccessibilityComment,
accessibilityRegisterer = userInfo,
registrationOrder = placeAccessibilityRepository.countAll(),
registrationOrder = placeAccessibilityRepository.countBy(),
isLastPlaceAccessibilityInBuilding = result.isLastPlaceAccessibilityInBuilding(buildingId) ?: false,
)
}
Expand Down Expand Up @@ -378,25 +387,26 @@ class AccessibilityApplicationService(
if (placeIds.isEmpty()) return emptyList()

return transactionManager.doInTransaction {
placeAccessibilityRepository.findByPlaceIds(placeIds).map { it.placeId }
placeAccessibilityRepository.findByPlaceIdInAndDeletedAtIsNull(placeIds).map { it.placeId }
}
}

fun findByUserId(userId: String): Pair<List<PlaceAccessibility>, List<BuildingAccessibility>> {
val placeAccessibilities = placeAccessibilityRepository.findByUserId(userId)
val placeAccessibilities = placeAccessibilityRepository.findByUserIdAndDeletedAtIsNull(userId)
if (placeAccessibilities.isEmpty()) return Pair(emptyList(), emptyList())

val buildingAccessibilities =
buildingAccessibilityRepository.findByPlaceIds(placeAccessibilities.map { it.placeId })
val buildingIds = placeApplicationService.findAllByIds(placeAccessibilities.map { it.placeId })
.map { it.building.id }
val buildingAccessibilities = buildingAccessibilityRepository.findByBuildingIdInAndDeletedAtIsNull(buildingIds)
return Pair(placeAccessibilities, buildingAccessibilities)
}

fun countByUserIdAndCreatedAtBetween(userId: String, from: Instant, to: Instant): Int =
placeAccessibilityRepository.countByUserIdAndCreatedAtBetween(
placeAccessibilityRepository.countByUserIdAndCreatedAtBetweenAndDeletedAtIsNull(
userId,
from,
to
) + buildingAccessibilityRepository.countByUserIdCreatedAtBetween(
) + buildingAccessibilityRepository.countByUserIdAndCreatedAtBetweenAndDeletedAtIsNull(
userId,
from,
to
Expand All @@ -407,8 +417,8 @@ class AccessibilityApplicationService(
from: Instant,
to: Instant
): Pair<List<PlaceAccessibility>, List<BuildingAccessibility>> {
val placeAccessibilities = placeAccessibilityRepository.findByUserIdAndCreatedAtBetween(userId, from, to)
val buildingAccessibilities = buildingAccessibilityRepository.findByUserIdAndCreatedAtBetween(userId, from, to)
val placeAccessibilities = placeAccessibilityRepository.findByUserIdAndCreatedAtBetweenAndDeletedAtIsNull(userId, from, to)
val buildingAccessibilities = buildingAccessibilityRepository.findByUserIdAndCreatedAtBetweenAndDeletedAtIsNull(userId, from, to)
return Pair(placeAccessibilities, buildingAccessibilities)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,36 @@ class AccessibilityImageService(
placeAccessibilityId: String? = null
): PlaceAccessibility? {
val placeAccessibility =
placeId?.let { placeAccessibilityRepository.findByPlaceId(it) }
?: placeAccessibilityId?.let { placeAccessibilityRepository.findById(it) }
placeId?.let { placeAccessibilityRepository.findFirstByPlaceIdAndDeletedAtIsNull(it) }
?: placeAccessibilityId?.let { placeAccessibilityRepository.findById(it).get() }?.takeIf { it.deletedAt == null }
?: return null
if (placeAccessibility.images.isEmpty() && placeAccessibility.imageUrls.isNotEmpty()) {
val placeAccessibilityImages = placeAccessibility.imageUrls.map { AccessibilityImage(imageUrl = it, thumbnailUrl = null) }
placeAccessibilityRepository.updateImages(placeAccessibility.id, placeAccessibilityImages)
placeAccessibility.updateImages(placeAccessibilityImages)
placeAccessibilityRepository.save(placeAccessibility)
}
return placeId?.let { placeAccessibilityRepository.findByPlaceId(it) } ?: placeAccessibilityId?.let { placeAccessibilityRepository.findById(it) }
return placeAccessibility
}

fun doMigrateBuildingAccessibilityImageUrlsToImagesIfNeeded(
buildingId: String? = null,
buildingAccessibilityId: String? = null,
): BuildingAccessibility? {
val buildingAccessibility = buildingId?.let { buildingAccessibilityRepository.findByBuildingId(it) }
?: buildingAccessibilityId?.let { buildingAccessibilityRepository.findById(it) } ?: return null
val buildingAccessibility = buildingId?.let { buildingAccessibilityRepository.findFirstByBuildingIdAndDeletedAtIsNull(it) }
?: buildingAccessibilityId?.let { buildingAccessibilityRepository.findById(it).get() }?.takeIf { it.deletedAt == null }
?: return null
if (buildingAccessibility.entranceImages.isEmpty() && buildingAccessibility.entranceImageUrls.isNotEmpty()) {
val buildingEntranceImages = buildingAccessibility.entranceImageUrls.map { AccessibilityImage(imageUrl = it, thumbnailUrl = null) }
buildingAccessibilityRepository.updateEntranceImages(buildingAccessibility.id, buildingEntranceImages)
buildingAccessibility.updateEntranceImages(buildingEntranceImages)
}

if (buildingAccessibility.elevatorImages.isEmpty() && buildingAccessibility.elevatorImageUrls.isNotEmpty()) {
val buildingElevatorImages = buildingAccessibility.elevatorImageUrls.map { AccessibilityImage(imageUrl = it, thumbnailUrl = null) }
buildingAccessibilityRepository.updateElevatorImages(buildingAccessibility.id, buildingElevatorImages)
buildingAccessibility.updateElevatorImages(buildingElevatorImages)
}

return buildingId?.let { buildingAccessibilityRepository.findByBuildingId(it) } ?: buildingAccessibilityId?.let { buildingAccessibilityRepository.findById(it) }
buildingAccessibilityRepository.save(buildingAccessibility)
return buildingAccessibility
}

fun generateThumbnailsIfNeeded(placeId: String) {
Expand All @@ -85,8 +88,8 @@ class AccessibilityImageService(
private fun getThumbnailGenerationRequiredImages(placeId: String) = transactionManager.doInTransaction {
val place = placeApplicationService.findPlace(placeId) ?: return@doInTransaction emptyList()

val placeAccessibility = placeAccessibilityRepository.findByPlaceId(placeId)
val buildingAccessibility = buildingAccessibilityRepository.findByBuildingId(place.building.id)
val placeAccessibility = placeAccessibilityRepository.findFirstByPlaceIdAndDeletedAtIsNull(placeId)
val buildingAccessibility = buildingAccessibilityRepository.findFirstByBuildingIdAndDeletedAtIsNull(place.building.id)

val accessibilityImages = listOfNotNull(placeAccessibility?.images, buildingAccessibility?.entranceImages, buildingAccessibility?.elevatorImages).flatten()

Expand All @@ -96,30 +99,33 @@ class AccessibilityImageService(
private fun saveThumbnailUrls(placeId: String, thumbnailUrls: List<String>) {
transactionManager.doInTransaction(isolationLevel = TransactionIsolationLevel.REPEATABLE_READ) {
val place = placeApplicationService.findPlace(placeId)!!
val placeAccessibility = placeAccessibilityRepository.findByPlaceId(placeId)
val buildingAccessibility = buildingAccessibilityRepository.findByBuildingId(place.building.id)
val placeAccessibility = placeAccessibilityRepository.findFirstByPlaceIdAndDeletedAtIsNull(placeId)
val buildingAccessibility = buildingAccessibilityRepository.findFirstByBuildingIdAndDeletedAtIsNull(place.building.id)

if (placeAccessibility != null) {
val updatedImages = placeAccessibility.images.map { image ->
findGeneratedThumbnailUrl(image.imageUrl, thumbnailUrls)?.let { image.thumbnailUrl = it }
image
}

placeAccessibilityRepository.updateImages(placeAccessibility.id, updatedImages)
placeAccessibility.updateImages(updatedImages)
placeAccessibilityRepository.save(placeAccessibility)
}

if (buildingAccessibility != null) {
val updatedEntranceImages = buildingAccessibility.entranceImages.map { image ->
findGeneratedThumbnailUrl(image.imageUrl, thumbnailUrls)?.let { image.thumbnailUrl = it }
image
}
buildingAccessibilityRepository.updateEntranceImages(buildingAccessibility.id, updatedEntranceImages)
buildingAccessibility.updateEntranceImages(updatedEntranceImages)

val updatedElevatorImages = buildingAccessibility.elevatorImages.map { image ->
findGeneratedThumbnailUrl(image.imageUrl, thumbnailUrls)?.let { image.thumbnailUrl = it }
image
}
buildingAccessibilityRepository.updateElevatorImages(buildingAccessibility.id, updatedElevatorImages)
buildingAccessibility.updateElevatorImages(updatedElevatorImages)

buildingAccessibilityRepository.save(buildingAccessibility)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class AdminDeleteBuildingAccessibilityUseCase(
fun handle(
buildingAccessibilityId: String,
) : Unit = transactionManager.doInTransaction(TransactionIsolationLevel.SERIALIZABLE) {
val buildingAccessibility = buildingAccessibilityRepository.findById(buildingAccessibilityId)
val buildingAccessibility = buildingAccessibilityRepository.findById(buildingAccessibilityId).get()
val building = buildingService.getById(buildingAccessibility.buildingId)!!
deleteAccessibilityAplService.deleteBuildingAccessibility(buildingAccessibility, building)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class AdminDeletePlaceAccessibilityUseCase(
fun handle(
placeAccessibilityId: String,
) : Unit = transactionManager.doInTransaction(TransactionIsolationLevel.SERIALIZABLE) {
val placeAccessibility = placeAccessibilityRepository.findById(placeAccessibilityId)
val placeAccessibility = placeAccessibilityRepository.findById(placeAccessibilityId).get()
val place = placeApplicationService.findPlace(placeAccessibility.placeId)!!
deleteAccessibilityAplService.deletePlaceAccessibility(placeAccessibility, place)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class AdminSearchAccessibilitiesUseCase(
val placeById = placeApplicationService.findAllByIds(placeAccessibilities.map { it.placeId })
.associateBy { it.id }
val buildingAccessibilityByBuildingId = buildingAccessibilityRepository
.findByBuildingIds(placeById.values.map { it.building.id })
.findByBuildingIdInAndDeletedAtIsNull(placeById.values.map { it.building.id })
.associateBy { it.buildingId }
val userById = userAplService.getUsers(
userIds = placeAccessibilities.mapNotNull { it.userId } +
Expand Down
Loading

0 comments on commit e061e09

Please sign in to comment.