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

feat: Support manifestation without item as missing item (TT-1565) #82

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -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()
}
}