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: Add possibility to delete physical items by manifestation ID (TT-1702) #90

Merged
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -18,10 +18,6 @@ class CollectionsObjectUpdateDto @OptIn(ExperimentalSerializationApi::class) con
@EncodeDefault(EncodeDefault.Mode.NEVER)
val notes: String? = null,

@SerialName("dating.date.start")
@EncodeDefault(EncodeDefault.Mode.NEVER)
val date: String? = null,

@SerialName("Alternative_number")
@EncodeDefault(EncodeDefault.Mode.NEVER)
val alternativeNumbers: List<AlternativeNumberInput>? = null,
Expand All @@ -40,15 +36,13 @@ fun createUpdateManifestationDto(
id: String,
username: String,
notes: String?,
date: LocalDate?,
number: String?
): CollectionsObjectUpdateDto {
val altNumbers = number?.let { listOf(AlternativeNumberInput(it, "Nummer")) }

return CollectionsObjectUpdateDto(
priRef = id,
notes = notes,
date = date?.let { DateUtils.createDateString(date) },
alternativeNumbers = altNumbers,
editName = username,
editDate = DateUtils.createDateString(LocalDate.now()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class CollectionsRepository(
@Throws(CollectionsException::class)
fun getSingleCollectionsModelWithoutChildren(titleCatalogId: String): Mono<CollectionsModel> {
val fields = "priref and title and work.description_type and record_type " +
"and dating.date.start and dating.date.end and publisher " +
"and dating.date.start and dating.date.end and edition.date and publisher " +
"and association.geographical_keyword and language and submedium " +
"and format and alternative_number and alternative_number.type " +
"and part_of_reference and PID_data_URN and current_location.barcode"
Expand All @@ -50,7 +50,7 @@ class CollectionsRepository(
return searchTexts(
"record_type=${CollectionsRecordType.MANIFESTATION} and " +
"part_of_reference.lref=${titleCatalogId} and " +
"dating.date.start='${dateString}'"
"edition.date='${dateString}'"
)
}

Expand Down Expand Up @@ -94,6 +94,10 @@ class CollectionsRepository(
return updateRecordWebClientRequest(serializedBody, CollectionsDatabase.TEXTS).bodyToMono<CollectionsModel>()
}

fun deleteTextsRecord(id: String): Mono<CollectionsModel> {
return deleteRecordWebClientRequest(id, CollectionsDatabase.TEXTS).bodyToMono<CollectionsModel>()
}

private fun searchTexts(query: String): Mono<CollectionsModel> {
return getRecordsWebClientRequest(query, CollectionsDatabase.TEXTS).bodyToMono<CollectionsModel>()
}
Expand Down Expand Up @@ -184,4 +188,22 @@ class CollectionsRepository(
{ Mono.error(CollectionsException("Error updating catalog item")) }
)
}

private fun deleteRecordWebClientRequest(id: String, db: CollectionsDatabase): WebClient.ResponseSpec {
return webClient()
.post()
.uri {
it
.queryParam("database", db.value)
.queryParam("command", "deleterecord")
.queryParam("output", "json")
.queryParam("priref", id)
.build()
}
.retrieve()
.onStatus(
{ it.is4xxClientError || it.is5xxServerError },
{ Mono.error(CollectionsException("Error deleting catalog item")) }
)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package no.nb.bikube.core.model.inputDto

import java.time.LocalDate

data class ItemUpdateDto(
val manifestationId: String,
val username: String,
val date: LocalDate? = null,
val notes: String? = null,
val number: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ class DtoValidationService {

@Throws(BadRequestBodyException::class)
fun validateItemUpdateDto(dto: ItemUpdateDto) {
if (dto.date == null && dto.notes == null && dto.number == null) {
throw BadRequestBodyException("Need to provide at least one field to update")
}

if (dto.username.isBlank()) {
throw BadRequestBodyException("Need to provide username")
}

if (dto.manifestationId.isBlank()) {
throw BadRequestBodyException("Need to provide manifestation ID")
}

if (dto.notes == null && dto.number == null) {
throw BadRequestBodyException("Need to provide either notes or number")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ import no.nb.bikube.newspaper.service.NewspaperService
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.*
import reactor.core.publisher.Mono

@RestController
Expand Down Expand Up @@ -73,8 +69,9 @@ class ItemController (
@PutMapping("")
@Operation(
summary = "Update a single physical newspaper by manifestation ID.",
description = "Update newspaper. All fields are optional (except ID and username), and fields not provided will not be updated. " +
"All possible fields are only present on the manifestation in the current catalog, and will be updated there."
description = "Update newspaper. Notes and number is optional (not ID and username), and fields not provided will not be updated. " +
"All possible fields are only present on the manifestation in the current catalog, and will be updated there." +
"Date cannot be changed. In case of date change, delete the physical item and create a new one."
)
@ApiResponses(value = [
ApiResponse(responseCode = "204", description = "Newspaper item updated"),
Expand All @@ -94,4 +91,28 @@ class ItemController (
ResponseEntity.noContent().build()
}
}

@DeleteMapping("/physical/{id}")
@Operation(
summary = "Delete a single physical newspaper by ID of manifestation.",
description = "Delete a single physical newspaper by the ID of its manifestation." +
"The manifestation will also be deleted if there are no other items attached."
)
@ApiResponses(value = [
ApiResponse(responseCode = "204", description = "Newspaper item deleted"),
ApiResponse(responseCode = "400", description = "Bad request", content = [Content()]),
ApiResponse(responseCode = "404", description = "Not found", content = [Content()]),
ApiResponse(responseCode = "500", description = "Server error", content = [Content()])
])
fun deleteItem(
@PathVariable id: String
): Mono<ResponseEntity<Void>> {
logger().info("Trying to delete newspaper item where its manifestation has id: $id")

return newspaperService.deletePhysicalItemByManifestationId(id)
.map {
logger().info("Newspaper item deleted with manifestation id: $id")
ResponseEntity.noContent().build()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,43 @@ class NewspaperService (
}
}

fun deletePhysicalItemByManifestationId(manifestationId: String): Mono<CollectionsModel> {
return collectionsRepository.getSingleCollectionsModel(manifestationId)
.flatMap { manifestation ->
println(manifestation)
pierrebeauguitte marked this conversation as resolved.
Show resolved Hide resolved
if (manifestation.hasError()) {
Mono.error(CollectionsException("Error when finding manifestation for deletion: ${manifestation.getError()}"))
} else if (!manifestation.hasObjects()) {
Mono.error(CollectionsManifestationNotFound("Manifestation with id $manifestationId not found."))
} else if (manifestation.getFirstObject().getRecordType() == CollectionsRecordType.MANIFESTATION) {
deleteItemAndManifestationIfNoOtherItems(manifestation.getFirstObject())
pierrebeauguitte marked this conversation as resolved.
Show resolved Hide resolved
} else {
Mono.error(NotSupportedException("Catalog item with id $manifestationId is not a manifestation or does not exist."))
}
}
}

private fun deleteItemAndManifestationIfNoOtherItems(
manifestation: CollectionsObject
): Mono<CollectionsModel> {
val allItems = manifestation.getParts()
val physicalItems = allItems?.filter {
it.partsReference?.getFormat() == CollectionsFormat.PHYSICAL
}

val firstPhysicalItem = physicalItems?.firstOrNull()
return if (physicalItems?.size == 1 && firstPhysicalItem?.partsReference != null) {
if (allItems.size == 1) {
collectionsRepository.deleteTextsRecord(firstPhysicalItem.partsReference.priRef)
.then(collectionsRepository.deleteTextsRecord(manifestation.priRef))
} else {
collectionsRepository.deleteTextsRecord(firstPhysicalItem.partsReference.priRef)
}
} else {
Mono.error(CollectionsException("Manifestation had ${physicalItems?.size ?: 0} physical items, expected 1"))
}
}

private fun createLinkedNewspaperItem(
item: ItemInputDto,
parentId: String
Expand Down Expand Up @@ -297,7 +334,7 @@ class NewspaperService (
private fun updateManifestation(
item: ItemUpdateDto
): Mono<CollectionsObject> {
val dto = createUpdateManifestationDto(item.manifestationId, item.username, item.notes, item.date, item.number)
val dto = createUpdateManifestationDto(item.manifestationId, item.username, item.notes, item.number)
val encodedBody = Json.encodeToString(dto)
return collectionsRepository.updateTextsRecord(encodedBody)
.handle { collectionsModel, sink ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ class CollectionsModelMockData {
publisherList = null,
languageList = null,
placeOfPublicationList = null,
partsList = listOf(collectionsPartsObjectMockItemA),
partsList = listOf(collectionsPartsObjectMockItemA, collectionsPartsObjectMockItemB),
alternativeNumberList = listOf(CollectionsAlternativeNumber("URN", "bikubeavisen_null_null_19991224_1_1_1")),
inputName = listOf(TEST_USERNAME),
notes = listOf(TEST_NOTES)
Expand Down Expand Up @@ -287,6 +287,54 @@ class CollectionsModelMockData {
)
)

// Manifestation with 2 physical parts
val collectionsModelMockManifestationD = CollectionsModel(
adlibJson = CollectionsRecordList(
recordList = listOf(
CollectionsObject(
priRef = "46",
titleList = listOf(CollectionsTitle(title = "Bikubeavisen")),
recordTypeList = collectionsRecordTypeListManifestMock,
formatList = null,
partOfList = listOf(collectionsPartOfObjectMockSerialWorkA),
subMediumList = null,
mediumList = null,
datingList = null,
publisherList = null,
languageList = null,
placeOfPublicationList = null,
partsList = listOf(collectionsPartsObjectMockItemB, collectionsPartsObjectMockItemB),
alternativeNumberList = null,
inputName = listOf(TEST_USERNAME)
)
)
)
)

// Manifestation with 1 physical part
val collectionsModelMockManifestationE = CollectionsModel(
adlibJson = CollectionsRecordList(
recordList = listOf(
CollectionsObject(
priRef = "46",
titleList = listOf(CollectionsTitle(title = "Bikubeavisen")),
recordTypeList = collectionsRecordTypeListManifestMock,
formatList = null,
partOfList = listOf(collectionsPartOfObjectMockSerialWorkA),
subMediumList = null,
mediumList = null,
datingList = null,
publisherList = null,
languageList = null,
placeOfPublicationList = null,
partsList = listOf(collectionsPartsObjectMockItemB),
alternativeNumberList = null,
inputName = listOf(TEST_USERNAME)
)
)
)
)

val collectionsNameModelMockA = CollectionsNameModel(
adlibJson = CollectionsNameRecordList(
recordList = listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,14 @@ class DtoValidationServiceTest {
}

@Test
fun `validateItemUpdateDto should throw exception if neither date, notes or number is provided`() {
fun `validateItemUpdateDto should throw exception if neither notes or number is provided`() {
assertThrows<BadRequestBodyException> { dtoValidationService.validateItemUpdateDto(
ItemUpdateDto(username = TEST_USERNAME, manifestationId = "1")
)}
}

@Test
fun `validateItemUpdateDto should not throw exception if only of date, notes or number is provided`() {
assertDoesNotThrow { dtoValidationService.validateItemUpdateDto(
ItemUpdateDto(username = TEST_USERNAME, manifestationId = "1", date = LocalDate.now())
)}

fun `validateItemUpdateDto should not throw exception if only notes or number is provided`() {
assertDoesNotThrow { dtoValidationService.validateItemUpdateDto(
ItemUpdateDto(username = TEST_USERNAME, manifestationId = "1", notes = "notes")
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ class NewspaperMockData {
val newspaperItemUpdateDtoMockA = ItemUpdateDto(
manifestationId = "24",
username = TEST_USERNAME,
date = LocalDate.parse("2020-01-01"),
notes = TEST_NOTES,
number = "1"
)
Expand Down
Loading