Skip to content

Commit

Permalink
feat: Support manifestation without item as missing item (TT-1565) (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
MariusLevang authored Jul 30, 2024
1 parent 859ac09 commit 192f9b4
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fun mapCollectionsObjectToGenericItem(model: CollectionsObject): Item {
materialType = model.getMaterialTypeFromParent()?.norwegian,
titleCatalogueId = model.getTitleCatalogueId(),
titleName = model.getTitleName(),
digital = model.getFormat() == CollectionsFormat.DIGITAL,
digital = model.getFormat()?.let { model.getFormat() == CollectionsFormat.DIGITAL },
urn = model.getUrn(),
location = model.locationBarcode
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package no.nb.bikube.core.model.inputDto

import java.time.LocalDate

data class MissingPeriodicalItemDto(
val date: LocalDate,
val titleCatalogueId: String,
val username: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.tags.Tag
import no.nb.bikube.core.model.Item
import no.nb.bikube.core.model.inputDto.ItemInputDto
import no.nb.bikube.core.model.inputDto.MissingPeriodicalItemDto
import no.nb.bikube.core.service.CreationValidationService
import no.nb.bikube.core.util.logger
import no.nb.bikube.newspaper.service.NewspaperService
Expand Down Expand Up @@ -47,4 +48,23 @@ class ItemController (
logger().info("Newspaper item created with id: ${responseEntity.body?.catalogueId}")
}
}

@PostMapping("/missing", produces = [MediaType.APPLICATION_JSON_VALUE])
@Operation(summary = "Create a 'missing item', in other words create a manifestation without item")
@ApiResponses(value = [
ApiResponse(responseCode = "201", description = "Manifestation/missing item created"),
ApiResponse(responseCode = "400", description = "Bad request", content = [Content()]),
ApiResponse(responseCode = "500", description = "Server error", content = [Content()])
])
fun createManifestationOnly(
@RequestBody item: MissingPeriodicalItemDto
): Mono<ResponseEntity<Item>> {
logger().info("Trying to create manifestation as missing item: $item")

return newspaperService.createMissingItem(item)
.map { ResponseEntity.status(HttpStatus.CREATED).body(it) }
.doOnSuccess { responseEntity ->
logger().info("Manifestation created with id: ${responseEntity.body?.catalogueId}")
}
}
}
31 changes: 27 additions & 4 deletions src/main/kotlin/no/nb/bikube/newspaper/service/NewspaperService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import no.nb.bikube.core.enum.*
import no.nb.bikube.core.exception.*
import no.nb.bikube.core.model.*
import no.nb.bikube.core.model.inputDto.ItemInputDto
import no.nb.bikube.core.model.inputDto.MissingPeriodicalItemDto
import no.nb.bikube.core.model.inputDto.TitleInputDto
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
Expand Down Expand Up @@ -52,6 +53,15 @@ class NewspaperService (
}
}

@Throws(CollectionsException::class, CollectionsTitleNotFound::class)
fun getSingleManifestationAsItem(catalogId: String): Mono<Item> {
return collectionsRepository.getSingleCollectionsModel(catalogId)
.map {
validateSingleCollectionsModel(it, CollectionsRecordType.MANIFESTATION)
mapCollectionsObjectToGenericItem(it.getFirstObject()!!)
}
}

@Throws(CollectionsException::class, CollectionsTitleNotFound::class)
fun getSingleTitle(catalogId: String): Mono<Title> {
return collectionsRepository.getSingleCollectionsModelWithoutChildren(catalogId)
Expand Down Expand Up @@ -194,7 +204,7 @@ class NewspaperService (
if (title.hasError() || title.getFirstObject() == null) {
Mono.error(CollectionsItemNotFound("Title with id ${item.titleCatalogueId} not found: ${title.getError()}"))
} else {
findOrCreateManifestationRecord(item)
findOrCreateManifestationRecord(item.titleCatalogueId, item.date, item.username)
}
}.flatMap { manifestation ->
if (item.digital == false && !item.containerId.isNullOrBlank()) {
Expand All @@ -214,6 +224,17 @@ class NewspaperService (
}
}

fun createMissingItem(item: MissingPeriodicalItemDto): Mono<Item> {
return collectionsRepository.getSingleCollectionsModelWithoutChildren(item.titleCatalogueId)
.flatMap { title ->
if (title.hasError() || title.getFirstObject() == null) {
Mono.error(CollectionsItemNotFound("Title with id ${item.titleCatalogueId} not found: ${title.getError()}"))
} else {
findOrCreateManifestationRecord(item.titleCatalogueId, item.date, item.username)
}
}.flatMap { getSingleManifestationAsItem(it.priRef) }
}

private fun createLinkedNewspaperItem(
item: ItemInputDto,
parentId: String
Expand All @@ -229,13 +250,15 @@ class NewspaperService (
}

private fun findOrCreateManifestationRecord(
item: ItemInputDto,
titleId: String,
date: LocalDate,
username: String
): Mono<CollectionsObject> {
return collectionsRepository.getManifestationsByDateAndTitle(
item.date, item.titleCatalogueId
date, titleId
).flatMap {
if (it.isEmpty()) {
createManifestation(item.titleCatalogueId, item.date, item.username)
createManifestation(titleId, date, username)
} else {
Mono.just(it.getFirstObject()!!)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ class CollectionsModelMockData {
languageList = null,
placeOfPublicationList = null,
partsList = null,
alternativeNumberList = listOf(CollectionsAlternativeNumber("URN", "bikubeavisen_null_null_19991224_1_1_1")),
alternativeNumberList = null,
inputName = listOf(TEST_USERNAME)
)
)
Expand Down
19 changes: 19 additions & 0 deletions src/test/kotlin/no/nb/bikube/newspaper/NewspaperMockData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import no.nb.bikube.core.model.Item
import no.nb.bikube.core.model.Language
import no.nb.bikube.core.model.Title
import no.nb.bikube.core.model.inputDto.ItemInputDto
import no.nb.bikube.core.model.inputDto.MissingPeriodicalItemDto
import no.nb.bikube.core.model.inputDto.TitleInputDto
import java.time.LocalDate

Expand Down Expand Up @@ -111,5 +112,23 @@ class NewspaperMockData {
name = newspaperItemMockB.urn!!,
type = "URN"
)

val missingItemDtoMock = MissingPeriodicalItemDto(
date = LocalDate.parse("2020-01-01"),
titleCatalogueId = "1",
username = TEST_USERNAME
)

// Equals to collectionsModelMockManifestationB
val newspaperItemMockDNoItem = Item(
catalogueId = "46",
name = "Bikubeavisen",
date = missingItemDtoMock.date,
materialType = MaterialType.NEWSPAPER.norwegian,
titleCatalogueId = missingItemDtoMock.titleCatalogueId,
titleName = "Bikubeavisen",
digital = null,
urn = null
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import kotlinx.serialization.json.Json
import no.nb.bikube.catalogue.collections.CollectionsModelMockData.Companion.collectionsModelEmptyRecordListMock
import no.nb.bikube.catalogue.collections.CollectionsModelMockData.Companion.collectionsModelMockItemA
import no.nb.bikube.catalogue.collections.CollectionsModelMockData.Companion.collectionsModelMockManifestationA
import no.nb.bikube.catalogue.collections.CollectionsModelMockData.Companion.collectionsModelMockManifestationB
import no.nb.bikube.catalogue.collections.CollectionsModelMockData.Companion.collectionsModelMockManifestationC
import no.nb.bikube.catalogue.collections.CollectionsModelMockData.Companion.collectionsModelMockTitleA
import no.nb.bikube.catalogue.collections.CollectionsModelMockData.Companion.collectionsModelMockTitleB
Expand All @@ -19,6 +20,7 @@ import no.nb.bikube.catalogue.collections.model.*
import no.nb.bikube.catalogue.collections.repository.CollectionsRepository
import no.nb.bikube.core.model.Item
import no.nb.bikube.core.model.inputDto.ItemInputDto
import no.nb.bikube.newspaper.NewspaperMockData.Companion.missingItemDtoMock
import no.nb.bikube.newspaper.NewspaperMockData.Companion.newspaperItemMockCValidForCreation
import no.nb.bikube.newspaper.service.UniqueIdService
import org.junit.jupiter.api.Assertions
Expand Down Expand Up @@ -49,6 +51,7 @@ class ItemControllerIntegrationTest {

private val titleId = collectionsModelMockTitleA.getFirstId()!!
private val manifestationId = collectionsModelMockManifestationC.getFirstId()!!
private val manifestationId2 = collectionsModelMockManifestationA.getFirstId()!!
private val itemId = collectionsModelMockItemA.getFirstId()!!

private fun createItem(item: ItemInputDto): ResponseSpec {
Expand All @@ -69,6 +72,7 @@ class ItemControllerIntegrationTest {
every { collectionsRepository.getSingleCollectionsModel(any()) } returns Mono.just(collectionsModelEmptyRecordListMock.copy())
every { collectionsRepository.getSingleCollectionsModel(titleId) } returns Mono.just(collectionsModelMockTitleA.copy())
every { collectionsRepository.getSingleCollectionsModel(manifestationId) } returns Mono.just(collectionsModelMockManifestationA.copy())
every { collectionsRepository.getSingleCollectionsModel(manifestationId2) } returns Mono.just(collectionsModelMockManifestationB.copy())
every { collectionsRepository.getSingleCollectionsModel(itemId) } returns Mono.just(collectionsModelMockItemA.copy())
every { collectionsRepository.getSingleCollectionsModelWithoutChildren(any()) } returns Mono.just(collectionsModelEmptyRecordListMock.copy())
every { collectionsRepository.getSingleCollectionsModelWithoutChildren(titleId) } returns Mono.just(collectionsModelMockTitleA.copy())
Expand Down Expand Up @@ -175,4 +179,78 @@ class ItemControllerIntegrationTest {
}
.verifyComplete()
}

@Test
fun `post missing-item should return 201 Created with item`() {
webClient
.post()
.uri("/newspapers/items/missing")
.bodyValue(missingItemDtoMock)
.exchange()
.expectStatus().isCreated
.expectBody<Item>()
}

@Test
fun `post missing-item should return correctly mapped item`() {
val testReturn = collectionsModelMockManifestationB.getFirstObject()!!

webClient
.post()
.uri("/newspapers/items/missing")
.bodyValue(missingItemDtoMock)
.exchange()
.returnResult<Item>()
.responseBody
.test()
.expectNext(Item(
catalogueId = testReturn.priRef,
name = testReturn.getName(),
date = testReturn.getStartDate(),
materialType = "Avis",
titleCatalogueId = testReturn.getTitleCatalogueId(),
titleName = testReturn.getTitleName(),
digital = null,
urn = null,
location = null
))
.verifyComplete()
}

@Test
fun `post missing-item should return 404 not found if title ID is not found`() {
webClient
.post()
.uri("/newspapers/items/missing")
.bodyValue(missingItemDtoMock.copy(titleCatalogueId = "489653148"))
.exchange()
.expectStatus().isNotFound
}

@Test
fun `post missing-item should use manifestation if it exists`() {
webClient
.post()
.uri("/newspapers/items/missing")
.bodyValue(missingItemDtoMock)
.exchange()
.expectStatus().isCreated

verify(exactly = 0) { collectionsRepository.createTextsRecord(any()) }
}

@Test
fun `post missing-item create correct manifestation if not found`() {
every { collectionsRepository.getSingleCollectionsModel(titleId) } returns Mono.just(collectionsModelMockTitleB.copy())
every { collectionsRepository.getManifestationsByDateAndTitle(any(), any()) } returns Mono.just(collectionsModelEmptyRecordListMock)

webClient
.post()
.uri("/newspapers/items/missing")
.bodyValue(missingItemDtoMock)
.exchange()
.expectStatus().isCreated

verify(exactly = 1) { collectionsRepository.createTextsRecord(any()) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ import no.nb.bikube.core.enum.MaterialType
import no.nb.bikube.core.exception.BadRequestBodyException
import no.nb.bikube.core.exception.RecordAlreadyExistsException
import no.nb.bikube.core.model.*
import no.nb.bikube.newspaper.NewspaperMockData.Companion.missingItemDtoMock
import no.nb.bikube.newspaper.NewspaperMockData.Companion.newspaperInputDtoItemMockB
import no.nb.bikube.newspaper.NewspaperMockData.Companion.newspaperItemMockB
import no.nb.bikube.newspaper.NewspaperMockData.Companion.newspaperItemMockDNoItem
import no.nb.bikube.newspaper.NewspaperMockData.Companion.newspaperTitleInputDtoMockB
import no.nb.bikube.newspaper.NewspaperMockData.Companion.newspaperTitleMockB
import no.nb.bikube.newspaper.NewspaperMockData.Companion.urnMock
Expand Down Expand Up @@ -724,4 +726,59 @@ class NewspaperServiceTest {
val result = newspaperService.createTitleString(item, "")
Assertions.assertEquals("Some fancy title", result)
}

@Test
fun `createMissingItem should return correctly mapped item`() {
every { collectionsRepository.getSingleCollectionsModelWithoutChildren(any()) } returns Mono.just(collectionsModelMockItemB)
every { collectionsRepository.getManifestationsByDateAndTitle(any(), any()) } returns Mono.just(collectionsModelMockManifestationB)
every { collectionsRepository.getSingleCollectionsModel(any()) } returns Mono.just(collectionsModelMockManifestationB)

newspaperService.createMissingItem(missingItemDtoMock)
.test()
.expectSubscription()
.assertNext { Assertions.assertEquals(newspaperItemMockDNoItem.copy(date = null, titleCatalogueId = "22"), it) }
.verifyComplete()
}

@Test
fun `createMissingItem should create manifestation if it does not exist`() {
every { collectionsRepository.getSingleCollectionsModelWithoutChildren(any()) } returns Mono.just(collectionsModelMockItemB)
every { collectionsRepository.getManifestationsByDateAndTitle(any(), any()) } returns Mono.just(collectionsModelEmptyRecordListMock)
every { collectionsRepository.getSingleCollectionsModel(any()) } returns Mono.just(collectionsModelMockManifestationB)
every { collectionsRepository.createTextsRecord(any()) } returns Mono.just(collectionsModelMockItemB)

newspaperService.createMissingItem(missingItemDtoMock)
.test()
.expectSubscription()
.expectNextCount(1)
.verifyComplete()

verify (exactly = 1) { collectionsRepository.createTextsRecord(any()) }
}

@Test
fun `createMissingItem should return manifestation if it exists`() {
every { collectionsRepository.getSingleCollectionsModelWithoutChildren(any()) } returns Mono.just(collectionsModelMockItemB)
every { collectionsRepository.getManifestationsByDateAndTitle(any(), any()) } returns Mono.just(collectionsModelMockManifestationB)
every { collectionsRepository.getSingleCollectionsModel(any()) } returns Mono.just(collectionsModelMockManifestationB)

newspaperService.createMissingItem(missingItemDtoMock)
.test()
.expectSubscription()
.expectNextCount(1)
.verifyComplete()

verify (exactly = 0) { collectionsRepository.createTextsRecord(any()) }
}

@Test
fun `createMissingItem should return error if title does not exist`() {
every { collectionsRepository.getSingleCollectionsModelWithoutChildren(any()) } returns Mono.just(collectionsModelEmptyRecordListMock)

newspaperService.createMissingItem(missingItemDtoMock)
.test()
.expectSubscription()
.expectError()
.verify()
}
}

0 comments on commit 192f9b4

Please sign in to comment.