Skip to content

Commit

Permalink
Tdrd 351 handle error when user clicks upload but no file was selected (
Browse files Browse the repository at this point in the history
#4268)

Adding a proper error page if app fails on trying to upload. Not the debug message
  • Loading branch information
ian-hoyle authored Nov 8, 2024
1 parent 50d864f commit e3951b7
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 12 deletions.
14 changes: 11 additions & 3 deletions app/controllers/DraftMetadataUploadController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import cats.effect.IO.fromOption
import cats.effect.unsafe.implicits.global
import configuration.{ApplicationConfig, KeycloakConfiguration}
import org.pac4j.play.scala.SecurityComponents
import play.api._
import play.api.i18n.I18nSupport
import play.api.libs.Files.TemporaryFile
import play.api.mvc.{Action, AnyContent, MultipartFormData, Request, Result}
import play.api.mvc._
import services._
import viewsapi.Caching.preventCaching

Expand All @@ -28,7 +29,8 @@ class DraftMetadataUploadController @Inject() (
val applicationConfig: ApplicationConfig
)(implicit val ec: ExecutionContext)
extends TokenSecurity
with I18nSupport {
with I18nSupport
with Logging {

def draftMetadataUploadPage(consignmentId: UUID): Action[AnyContent] = standardUserAndTypeAction(consignmentId) { implicit request: Request[AnyContent] =>
if (applicationConfig.blockDraftMetadataUpload) {
Expand Down Expand Up @@ -64,7 +66,13 @@ class DraftMetadataUploadController @Inject() (

uploadDraftMetadata
.recoverWith { case error =>
IO(InternalServerError(s"Unable to upload draft metadata to : $uploadBucket/$uploadKey: Error:" + error.getMessage + " stack" + error.getStackTrace.mkString))
val errorPage = for {
reference <- consignmentService.getConsignmentRef(consignmentId, token.bearerAccessToken)
} yield {
logger.error(error.getMessage, error)
Ok(views.html.draftmetadata.draftMetadataUploadError(consignmentId, reference, frontEndInfoConfiguration.frontEndInfo, token.bearerAccessToken.getValue)).uncache()
}
IO.fromFuture(IO(errorPage))
}
.unsafeToFuture()
}
Expand Down
62 changes: 62 additions & 0 deletions app/views/draftmetadata/draftMetadataUploadError.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@import helper._
@import views.html.partials._
@import viewsapi.FrontEndInfo

@import java.util.UUID
@(consignmentId: UUID, consignmentRef: String, frontEndInfo: FrontEndInfo, name: String)(implicit request: RequestHeader, messages: Messages)

@main("Upload a metadata CSV", name = name, backLink = Some(backLink(routes.AdditionalMetadataEntryMethodController.additionalMetadataEntryMethodPage(consignmentId).url, "How would you like to enter metadata?"))) {
<div id="metadata-file-upload" class="govuk-grid-row" >

<div class="govuk-grid-column-two-thirds">
<div class="govuk-error-summary" data-module="govuk-error-summary">
<div role="alert">
<h2 class="govuk-error-summary__title">
There is a problem
</h2>
<div class="govuk-error-summary__body">
<ul class="govuk-list govuk-error-summary__list">
<li>
<a href="#file-selection">Select a CSV file to upload</a>
</li>
</ul>
</div>
</div>
</div>

<h1 class="govuk-heading-l">Upload a metadata CSV</h1>
<div class="govuk-body">
<p>In your CSV, include a header row for the column titles and one row for every record that requires metadata.</p>
</div>
<div>
@downloadMetadataLink(consignmentId, "Download metadata Excel template", routes.DownloadMetadataController.downloadMetadataFile(consignmentId).url)
</div>

<form action="@routes.DraftMetadataUploadController.saveDraftMetadata(consignmentId)" id="draft-metadata-upload-forms" enctype="multipart/form-data" method="post" >
@CSRF.formField
<div class="govuk-form-group govuk-form-group--error">
@loggedOutErrorMessage("file-upload")
@frontEndInputs(frontEndInfo)
<label class="govuk-label govuk-!-font-weight-bold" for="file-selection">
Select a CSV
</label>

<p id="file-upload-1-error" class="govuk-error-message">
<span class="govuk-visually-hidden">Error:</span> Select a CSV file to upload
</p>

<div >
<input class="govuk-file-upload govuk-file-upload--error" type="file" id="file-selection" name="files"
accept=".csv">
</div>
</div>
<div>
<button id="to-draft-metadata-checks" class="govuk-button" type="submit" data-module="govuk-button" role="button">
Upload
</button>
</div>
</form>
</div>
@transferReference(consignmentRef, isJudgmentUser = false)
</div>
}
33 changes: 24 additions & 9 deletions test/controllers/DraftMetadataUploadControllerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.pac4j.play.scala.SecurityComponents
import org.scalatest.matchers.should.Matchers._
import play.api.Configuration
import play.api.Play.materializer
import play.api.libs.Files
import play.api.libs.Files.SingletonTemporaryFileCreator
import play.api.mvc.MultipartFormData.FilePart
import play.api.mvc.{MultipartFormData, Result}
Expand Down Expand Up @@ -117,21 +118,25 @@ class DraftMetadataUploadControllerSpec extends FrontEndTestHelper {
redirect.getOrElse(s"incorrect redirect $redirect") must include regex "/consignment/*.*/draft-metadata/checks"
}

"render error page when upload unsuccessful" in {
"render error page when upload unsuccessful when no file uploaded" in {
val uploadServiceMock = mock[UploadService]
when(uploadServiceMock.uploadDraftMetadata(anyString, anyString, anyString))
.thenReturn(Future.failed(new RuntimeException("Upload failed")))
setConsignmentReferenceResponse(wiremockServer)
when(configuration.get[String]("draftMetadata.fileName")).thenReturn("wrong name")
val putObjectResponse = PutObjectResponse.builder().eTag("testEtag").build()
when(uploadServiceMock.uploadDraftMetadata(anyString, anyString, anyString)).thenReturn(Future.successful(putObjectResponse))

val draftMetadataServiceMock = mock[DraftMetadataService]
when(draftMetadataServiceMock.triggerDraftMetadataValidator(any[UUID], anyString, anyString)).thenReturn(Future.successful(true))
val response = requestFileUpload(uploadServiceMock, draftMetadataServiceMock)
val response = requestFileUploadWithoutFile(uploadServiceMock, draftMetadataServiceMock)

playStatus(response) mustBe 500
playStatus(response) mustBe 200

contentAsString(response) must include("Upload failed")
contentAsString(response) must include("There is a problem")
}

"render error page when upload success but trigger fails" in {
val uploadServiceMock = mock[UploadService]
setConsignmentReferenceResponse(wiremockServer)
val putObjectResponse = PutObjectResponse.builder().eTag("testEtag").build()
when(configuration.get[String]("draftMetadata.fileName")).thenReturn(uploadFilename)
when(uploadServiceMock.uploadDraftMetadata(anyString, anyString, anyString)).thenReturn(Future.successful(putObjectResponse))
Expand All @@ -140,9 +145,9 @@ class DraftMetadataUploadControllerSpec extends FrontEndTestHelper {
when(draftMetadataServiceMock.triggerDraftMetadataValidator(any[UUID], anyString, anyString)).thenReturn(Future.failed(new RuntimeException("Trigger failed")))
val response = requestFileUpload(uploadServiceMock, draftMetadataServiceMock)

playStatus(response) mustBe 500
playStatus(response) mustBe 200

contentAsString(response) must include("Trigger failed")
contentAsString(response) must include("There is a problem")
}
}

Expand Down Expand Up @@ -170,6 +175,15 @@ class DraftMetadataUploadControllerSpec extends FrontEndTestHelper {
)
}

private def requestFileUploadWithoutFile(uploadServiceMock: UploadService, draftMetadataServiceMock: DraftMetadataService): Future[Result] = {
val controller = instantiateDraftMetadataUploadController(blockDraftMetadataUpload = false, uploadService = uploadServiceMock, draftMetadataService = draftMetadataServiceMock)

val formData = MultipartFormData(dataParts = Map("" -> Seq("dummy data")), files = Seq.empty[FilePart[Files.TemporaryFile]], badParts = Seq())

val request = FakeRequest(POST, "/consignment/1234567/draft-metadata").withCSRFToken.withBody(formData).withHeaders(FakeHeaders())
controller.saveDraftMetadata(UUID.randomUUID()).apply(request)
}

private def requestFileUpload(uploadServiceMock: UploadService, draftMetadataServiceMock: DraftMetadataService): Future[Result] = {
val controller = instantiateDraftMetadataUploadController(blockDraftMetadataUpload = false, uploadService = uploadServiceMock, draftMetadataService = draftMetadataServiceMock)

Expand All @@ -183,7 +197,8 @@ class DraftMetadataUploadControllerSpec extends FrontEndTestHelper {
val file = FilePart("upload", "hello.txt", Option("text/plain"), tempFile)
val formData = MultipartFormData(dataParts = Map("" -> Seq("dummy data")), files = Seq(file), badParts = Seq())

val request = FakeRequest(POST, "/consignment/1234567/draft-metadata").withBody(formData).withHeaders(FakeHeaders())
val request = FakeRequest(POST, "/consignment/1234567/draft-metadata").withCSRFToken.withBody(formData).withHeaders(FakeHeaders())

controller.saveDraftMetadata(UUID.randomUUID()).apply(request)
}
}

0 comments on commit e3951b7

Please sign in to comment.