diff --git a/app/configuration/ApplicationConfig.scala b/app/configuration/ApplicationConfig.scala index c170e895a..cb10fecd3 100644 --- a/app/configuration/ApplicationConfig.scala +++ b/app/configuration/ApplicationConfig.scala @@ -21,6 +21,8 @@ class ApplicationConfig @Inject() (configuration: Configuration) { val blockMetadataReview: Boolean = configuration.get[Boolean]("featureAccessBlock.blockMetadataReview") + val blockSkipMetadataReview: Boolean = configuration.get[Boolean]("featureAccessBlock.blockSkipMetadataReview") + val metadataValidationBaseUrl: String = configuration.get[String]("metadatavalidation.baseUrl") val s3Endpoint: String = configuration.get[String]("s3.endpoint") diff --git a/app/controllers/ConfirmTransferController.scala b/app/controllers/ConfirmTransferController.scala index 47a072e0a..6914e9a5b 100644 --- a/app/controllers/ConfirmTransferController.scala +++ b/app/controllers/ConfirmTransferController.scala @@ -2,15 +2,15 @@ package controllers import auth.TokenSecurity import com.nimbusds.oauth2.sdk.token.BearerAccessToken -import configuration.{GraphQLConfiguration, KeycloakConfiguration} +import configuration.{ApplicationConfig, GraphQLConfiguration, KeycloakConfiguration} +import controllers.util.RedirectUtils import org.pac4j.play.scala.SecurityComponents import play.api.data.Form import play.api.data.Forms.{boolean, mapping} import play.api.i18n.{I18nSupport, Lang, Langs} import play.api.mvc._ -import play.api.mvc.Results._ -import services.Statuses.{ClientChecksType, CompletedValue, ExportType, FailedValue, InProgressValue, SeriesType, TransferAgreementType, UploadType} -import services.{ConfirmTransferService, ConsignmentExportService, ConsignmentService, ConsignmentStatusService, Statuses} +import services.Statuses._ +import services._ import viewsapi.Caching.preventCaching import java.util.UUID @@ -25,6 +25,7 @@ class ConfirmTransferController @Inject() ( val confirmTransferService: ConfirmTransferService, val consignmentExportService: ConsignmentExportService, val consignmentStatusService: ConsignmentStatusService, + val applicationConfig: ApplicationConfig, langs: Langs )(implicit val ec: ExecutionContext) extends TokenSecurity @@ -70,8 +71,21 @@ class ConfirmTransferController @Inject() ( Ok(views.html.transferAlreadyCompleted(consignmentId, consignmentRef, request.token.name)).uncache() } case None => - getConsignmentSummary(request, consignmentId).map { consignmentSummary => - httpStatus(views.html.standard.confirmTransfer(consignmentId, consignmentSummary, finalTransferForm, request.token.name)).uncache() + if (applicationConfig.blockSkipMetadataReview) { + val metadataReviewType = consignmentStatuses.find(_.statusType == MetadataReviewType.id) + if (metadataReviewType.isEmpty) { + Future(Redirect(routes.AdditionalMetadataController.start(consignmentId))) + } else { + getConsignmentSummary(request, consignmentId).map { consignmentSummary => + RedirectUtils.redirectIfReviewNotCompleted(consignmentId, consignmentStatuses)( + httpStatus(views.html.standard.confirmTransfer(consignmentId, consignmentSummary, finalTransferForm, request.token.name)).uncache() + ) + } + } + } else { + getConsignmentSummary(request, consignmentId).map { consignmentSummary => + httpStatus(views.html.standard.confirmTransfer(consignmentId, consignmentSummary, finalTransferForm, request.token.name)).uncache() + } } case _ => throw new IllegalStateException(s"Unexpected Export status: $exportTransferStatus for consignment $consignmentId") diff --git a/app/controllers/util/RedirectUtils.scala b/app/controllers/util/RedirectUtils.scala index 80223bf43..ef5ad3b39 100644 --- a/app/controllers/util/RedirectUtils.scala +++ b/app/controllers/util/RedirectUtils.scala @@ -5,7 +5,7 @@ import graphql.codegen.GetConsignmentStatus.getConsignmentStatus.GetConsignment. import play.api.mvc.Result import play.api.mvc.Results.Redirect import services.ConsignmentStatusService -import services.Statuses.{InProgressValue, MetadataReviewType} +import services.Statuses.{CompletedValue, InProgressValue, MetadataReviewType} import java.util.UUID @@ -18,4 +18,10 @@ object RedirectUtils { Redirect(routes.MetadataReviewStatusController.metadataReviewStatusPage(consignmentId)) } else requestedPage } + + def redirectIfReviewNotCompleted(consignmentId: UUID, consignmentStatuses: Seq[ConsignmentStatuses]): Result => Result = requestedPage => { + if (ConsignmentStatusService.statusValue(MetadataReviewType)(consignmentStatuses) != CompletedValue) { + Redirect(routes.MetadataReviewStatusController.metadataReviewStatusPage(consignmentId)) + } else requestedPage + } } diff --git a/conf/application.base.conf b/conf/application.base.conf index 9a6e350a3..01a1f9133 100644 --- a/conf/application.base.conf +++ b/conf/application.base.conf @@ -60,6 +60,7 @@ draft_metadata_s3_bucket_name = ${DRAFT_METADATA_S3_BUCKET_NAME} featureAccessBlock { blockDraftMetadataUpload=${BLOCK_DRAFT_METADATA_UPLOAD} blockMetadataReview=${BLOCK_METADATA_REVIEW} + blockSkipMetadataReview=${BLOCK_SKIP_METADATA_REVIEW} } draftMetadata { diff --git a/conf/application.local-base.conf b/conf/application.local-base.conf index a9fbf3ff2..ae0cf1736 100644 --- a/conf/application.local-base.conf +++ b/conf/application.local-base.conf @@ -22,4 +22,5 @@ draft_metadata_s3_bucket_name = "tdr-draft-metadata-intg" featureAccessBlock { blockDraftMetadataUpload=false blockMetadataReview=false + blockSkipMetadataReview=false } diff --git a/test/controllers/ConfirmTransferControllerSpec.scala b/test/controllers/ConfirmTransferControllerSpec.scala index 95acbc32a..ccbd0eb5f 100644 --- a/test/controllers/ConfirmTransferControllerSpec.scala +++ b/test/controllers/ConfirmTransferControllerSpec.scala @@ -2,7 +2,8 @@ package controllers import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock._ -import configuration.{GraphQLConfiguration, KeycloakConfiguration} +import com.typesafe.config.{ConfigFactory, ConfigValue, ConfigValueFactory} +import configuration.{ApplicationConfig, GraphQLConfiguration, KeycloakConfiguration} import errors.AuthorisationException import graphql.codegen.AddFinalTransferConfirmation.{addFinalTransferConfirmation => aftc} import graphql.codegen.GetConsignment.{getConsignment => gc} @@ -33,6 +34,7 @@ import java.time.{LocalDateTime, ZoneId, ZonedDateTime} import java.util.UUID import scala.collection.immutable.TreeMap import scala.concurrent.ExecutionContext +import scala.jdk.CollectionConverters.CollectionHasAsScala class ConfirmTransferControllerSpec extends FrontEndTestHelper { implicit val ec: ExecutionContext = ExecutionContext.global @@ -158,9 +160,11 @@ class ConfirmTransferControllerSpec extends FrontEndTestHelper { redirectLocation(confirmTransferPage).get must equal(s"/consignment/$consignmentId/file-checks?uploadFailed=false") } - "render the confirm transfer page with an authenticated user when all relevant statuses are 'Completed'" in { + "redirect to the add additional metadata page with an authenticated user if the MetadataReview status is not present & blockSkipMetadataReview is 'true'" in { + val consignmentId = UUID.randomUUID() + val client = new GraphQLConfiguration(app.configuration).getClient[gcs.Data, gcs.Variables]() - val controller = instantiateConfirmTransferController(getAuthorisedSecurityComponents) + val controller = instantiateConfirmTransferController(getAuthorisedSecurityComponents, blockSkipMetadataReview = true) val consignmentStatuses = List( ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "Series", "Completed", someDateTime, None), ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "TransferAgreement", "Completed", someDateTime, None), @@ -178,96 +182,117 @@ class ConfirmTransferControllerSpec extends FrontEndTestHelper { .confirmTransfer(consignmentId) .apply(FakeRequest(GET, s"/consignment/$consignmentId/confirm-transfer").withCSRFToken) - val confirmTransferPageAsString = contentAsString(confirmTransferPage) + playStatus(confirmTransferPage) mustBe SEE_OTHER + redirectLocation(confirmTransferPage).get must equal(s"/consignment/$consignmentId/additional-metadata") + } - playStatus(confirmTransferPage) mustBe OK - contentType(confirmTransferPage) mustBe Some("text/html") - confirmTransferPageAsString must include("Confirm transfer - Transfer Digital Records - GOV.UK") - confirmTransferPageAsString must include(s"""Back""") - confirmTransferPageAsString must include("""

Confirm transfer

""") - - confirmTransferPageAsString must include( - """
- |
- |

- | notification.savedProgress.title - |

- |
- |
- |

- | notification.savedProgress.heading - |

- |

notification.savedProgress.metadataInfo

- |
- |
""".stripMargin + "redirect to the review progress page with an authenticated user if the MetadataReview status is 'InProgress' & blockSkipMetadataReview is 'true'" in { + val consignmentId = UUID.randomUUID() + + val client = new GraphQLConfiguration(app.configuration).getClient[gcs.Data, gcs.Variables]() + val controller = instantiateConfirmTransferController(getAuthorisedSecurityComponents, blockSkipMetadataReview = true) + val consignmentStatuses = List( + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "Series", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "TransferAgreement", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "Upload", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "ClientChecks", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "MetadataReview", "InProgress", someDateTime, None) ) + setConsignmentStatusResponse(app.configuration, wiremockServer, consignmentStatuses = consignmentStatuses) - confirmTransferPageAsString must include("""

Here is a summary of the records you have uploaded.

""") + val consignmentSummaryResponse: gcs.GetConsignment = getConsignmentSummaryResponse + val data: client.GraphqlData = client.GraphqlData(Some(gcs.Data(Some(consignmentSummaryResponse))), List()) + val dataString: String = data.asJson.printWith(Printer(dropNullValues = false, "")) + mockGraphqlConsignmentSummaryResponse(dataString) - confirmTransferPageAsString must include( - """
- | Series reference - |
""".stripMargin - ) + val confirmTransferPage = controller + .confirmTransfer(consignmentId) + .apply(FakeRequest(GET, s"/consignment/$consignmentId/confirm-transfer").withCSRFToken) - confirmTransferPageAsString must include( - s"""
- | ${consignmentSummaryResponse.seriesName.get} - |
""".stripMargin - ) + playStatus(confirmTransferPage) mustBe SEE_OTHER + redirectLocation(confirmTransferPage).get must equal(s"/consignment/$consignmentId/metadata-review/review-progress") + } - confirmTransferPageAsString must include( - """
- | Consignment reference - |
""".stripMargin - ) + "redirect to the review progress page with an authenticated user if the MetadataReview status is 'CompletedWithIssues' & blockSkipMetadataReview is 'true'" in { + val consignmentId = UUID.randomUUID() - confirmTransferPageAsString must include( - s"""
- | ${consignmentSummaryResponse.consignmentReference} - |
""".stripMargin + val client = new GraphQLConfiguration(app.configuration).getClient[gcs.Data, gcs.Variables]() + val controller = instantiateConfirmTransferController(getAuthorisedSecurityComponents, blockSkipMetadataReview = true) + val consignmentStatuses = List( + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "Series", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "TransferAgreement", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "Upload", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "ClientChecks", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "MetadataReview", "CompletedWithIssues", someDateTime, None) ) + setConsignmentStatusResponse(app.configuration, wiremockServer, consignmentStatuses = consignmentStatuses) - confirmTransferPageAsString must include( - s"""
- | Transferring body - |
""".stripMargin - ) + val consignmentSummaryResponse: gcs.GetConsignment = getConsignmentSummaryResponse + val data: client.GraphqlData = client.GraphqlData(Some(gcs.Data(Some(consignmentSummaryResponse))), List()) + val dataString: String = data.asJson.printWith(Printer(dropNullValues = false, "")) + mockGraphqlConsignmentSummaryResponse(dataString) - confirmTransferPageAsString must include( - s"""
- | ${consignmentSummaryResponse.transferringBodyName.get} - |
""".stripMargin - ) + val confirmTransferPage = controller + .confirmTransfer(consignmentId) + .apply(FakeRequest(GET, s"/consignment/$consignmentId/confirm-transfer").withCSRFToken) - confirmTransferPageAsString must include( - s"""
- | Files uploaded for transfer - |
""".stripMargin - ) + playStatus(confirmTransferPage) mustBe SEE_OTHER + redirectLocation(confirmTransferPage).get must equal(s"/consignment/$consignmentId/metadata-review/review-progress") + } - confirmTransferPageAsString must include( - s"""
- | ${consignmentSummaryResponse.totalFiles} files uploaded - |
""".stripMargin + "render the confirm transfer page with an authenticated user if the MetadataReview status is 'Completed' & blockSkipMetadataReview is 'true'" in { + val client = new GraphQLConfiguration(app.configuration).getClient[gcs.Data, gcs.Variables]() + val controller = instantiateConfirmTransferController(getAuthorisedSecurityComponents, blockSkipMetadataReview = true) + val consignmentStatuses = List( + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "Series", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "TransferAgreement", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "Upload", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "ClientChecks", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "MetadataReview", "Completed", someDateTime, None) ) + setConsignmentStatusResponse(app.configuration, wiremockServer, consignmentStatuses = consignmentStatuses) - confirmTransferPageAsString must include( - s"""
""" - ) + val consignmentSummaryResponse: gcs.GetConsignment = getConsignmentSummaryResponse + val data: client.GraphqlData = client.GraphqlData(Some(gcs.Data(Some(consignmentSummaryResponse))), List()) + val dataString: String = data.asJson.printWith(Printer(dropNullValues = false, "")) + mockGraphqlConsignmentSummaryResponse(dataString) - confirmTransferPageAsString must include regex ( - s"""""" - ) + val confirmTransferPage = controller + .confirmTransfer(consignmentId) + .apply(FakeRequest(GET, s"/consignment/$consignmentId/confirm-transfer").withCSRFToken) + + val confirmTransferPageAsString = contentAsString(confirmTransferPage) - confirmTransferPageAsString must include( - s"""
- | - |
""".stripMargin + playStatus(confirmTransferPage) mustBe OK + contentType(confirmTransferPage) mustBe Some("text/html") + checkConfirmTransferContent(confirmTransferPageAsString, consignmentSummaryResponse) + } + + "render the confirm transfer page with an authenticated user when all relevant statuses are 'Completed'" in { + val client = new GraphQLConfiguration(app.configuration).getClient[gcs.Data, gcs.Variables]() + val controller = instantiateConfirmTransferController(getAuthorisedSecurityComponents) + val consignmentStatuses = List( + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "Series", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "TransferAgreement", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "Upload", "Completed", someDateTime, None), + ConsignmentStatuses(UUID.randomUUID(), UUID.randomUUID(), "ClientChecks", "Completed", someDateTime, None) ) + setConsignmentStatusResponse(app.configuration, wiremockServer, consignmentStatuses = consignmentStatuses) + + val consignmentSummaryResponse: gcs.GetConsignment = getConsignmentSummaryResponse + val data: client.GraphqlData = client.GraphqlData(Some(gcs.Data(Some(consignmentSummaryResponse))), List()) + val dataString: String = data.asJson.printWith(Printer(dropNullValues = false, "")) + mockGraphqlConsignmentSummaryResponse(dataString) + val confirmTransferPage = controller + .confirmTransfer(consignmentId) + .apply(FakeRequest(GET, s"/consignment/$consignmentId/confirm-transfer").withCSRFToken) + + val confirmTransferPageAsString = contentAsString(confirmTransferPage) + + playStatus(confirmTransferPage) mustBe OK + contentType(confirmTransferPage) mustBe Some("text/html") + checkConfirmTransferContent(confirmTransferPageAsString, consignmentSummaryResponse) checkPageForStaticElements.checkContentOfPagesThatUseMainScala(confirmTransferPageAsString, userType = "standard") formTester.checkHtmlForOptionAndItsAttributes(confirmTransferPageAsString, Map()) } @@ -622,9 +647,21 @@ class ConfirmTransferControllerSpec extends FrontEndTestHelper { setConsignmentTypeResponse(wiremockServer, consignmentType) } + private def getApplicationConfig(blockSkipMetadataReview: Boolean): ApplicationConfig = { + val config: Map[String, ConfigValue] = ConfigFactory + .load() + .withValue("featureAccessBlock.blockSkipMetadataReview", ConfigValueFactory.fromAnyRef(blockSkipMetadataReview)) + .entrySet() + .asScala + .map(e => e.getKey -> e.getValue) + .toMap + new ApplicationConfig(Configuration.from(config)) + } + private def instantiateConfirmTransferController( securityComponents: SecurityComponents, - keycloakConfiguration: KeycloakConfiguration = getValidStandardUserKeycloakConfiguration + keycloakConfiguration: KeycloakConfiguration = getValidStandardUserKeycloakConfiguration, + blockSkipMetadataReview: Boolean = false ) = { val graphQLConfiguration = new GraphQLConfiguration(app.configuration) val confirmTransferService = new ConfirmTransferService(graphQLConfiguration) @@ -639,6 +676,7 @@ class ConfirmTransferControllerSpec extends FrontEndTestHelper { confirmTransferService, exportService(app.configuration), consignmentStatusService, + getApplicationConfig(blockSkipMetadataReview), langs ) } @@ -713,4 +751,92 @@ class ConfirmTransferControllerSpec extends FrontEndTestHelper { s"""href="/$transferType/$consignmentId/transfer-complete">Continue""".stripMargin ) } + + private def checkConfirmTransferContent(confirmTransferPageAsString: String, consignmentSummaryResponse: gcs.GetConsignment) = { + confirmTransferPageAsString must include("Confirm transfer - Transfer Digital Records - GOV.UK") + confirmTransferPageAsString must include(s"""Back""") + confirmTransferPageAsString must include("""

Confirm transfer

""") + + confirmTransferPageAsString must include( + """
+ |
+ |

+ | notification.savedProgress.title + |

+ |
+ |
+ |

+ | notification.savedProgress.heading + |

+ |

notification.savedProgress.metadataInfo

+ |
+ |
""".stripMargin + ) + + confirmTransferPageAsString must include("""

Here is a summary of the records you have uploaded.

""") + + confirmTransferPageAsString must include( + """
+ | Series reference + |
""".stripMargin + ) + + confirmTransferPageAsString must include( + s"""
+ | ${consignmentSummaryResponse.seriesName.get} + |
""".stripMargin + ) + + confirmTransferPageAsString must include( + """
+ | Consignment reference + |
""".stripMargin + ) + + confirmTransferPageAsString must include( + s"""
+ | ${consignmentSummaryResponse.consignmentReference} + |
""".stripMargin + ) + + confirmTransferPageAsString must include( + s"""
+ | Transferring body + |
""".stripMargin + ) + + confirmTransferPageAsString must include( + s"""
+ | ${consignmentSummaryResponse.transferringBodyName.get} + |
""".stripMargin + ) + + confirmTransferPageAsString must include( + s"""
+ | Files uploaded for transfer + |
""".stripMargin + ) + + confirmTransferPageAsString must include( + s"""
+ | ${consignmentSummaryResponse.totalFiles} files uploaded + |
""".stripMargin + ) + + confirmTransferPageAsString must include( + s"""""" + ) + + confirmTransferPageAsString must include regex ( + s"""""" + ) + + confirmTransferPageAsString must include( + s"""
+ | + |
""".stripMargin + ) + } }