Skip to content

Commit

Permalink
TDRD-373 DTA Add email address to request details page (#4061)
Browse files Browse the repository at this point in the history
* New userDetails method
* Replace userId with email in dta action page
* Alter `MetadataReviewSubmittedEvent`to include status and userEmail
* Read `READ_AUTH_SECRET` environment variable
  • Loading branch information
thanhz authored Aug 6, 2024
1 parent df7c855 commit 9310c01
Show file tree
Hide file tree
Showing 11 changed files with 58 additions and 29 deletions.
17 changes: 14 additions & 3 deletions app/configuration/KeycloakConfiguration.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
package configuration

import javax.inject.Inject
import play.api.Configuration
import sttp.client3.{HttpURLConnectionBackend, Identity, SttpBackend}
import uk.gov.nationalarchives.tdr.keycloak.{KeycloakUtils, TdrKeycloakDeployment, Token}

import scala.concurrent.ExecutionContext
import javax.inject.Inject
import scala.concurrent.{ExecutionContext, Future}

class KeycloakConfiguration @Inject() (configuration: Configuration)(implicit val executionContext: ExecutionContext) {
implicit val backend: SttpBackend[Identity, Any] = HttpURLConnectionBackend()
val authUrl: String = configuration.get[String]("auth.url")
val secret: String = configuration.get[String]("read.auth.secret")

def token(value: String): Option[Token] = {
implicit val tdrKeycloakDeployment: TdrKeycloakDeployment =
TdrKeycloakDeployment(s"${configuration.get[String]("auth.url")}", "tdr", 3600)
TdrKeycloakDeployment(authUrl, "tdr", 3600)
KeycloakUtils().token(value).toOption
}

def userDetails(userId: String): Future[KeycloakUtils.UserDetails] = {
implicit val tdrKeycloakDeployment: TdrKeycloakDeployment =
TdrKeycloakDeployment(authUrl, "tdr", 3600)
KeycloakUtils().userDetails(userId, "tdr-user-read", secret)
}
}
10 changes: 7 additions & 3 deletions app/controllers/MetadataReviewActionController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class MetadataReviewActionController @Inject() (
getConsignmentMetadataDetails(consignmentId, request, Ok, selectedDecisionForm)
}

def submitReview(consignmentId: UUID, consignmentRef: String): Action[AnyContent] = tnaUserAction { implicit request: Request[AnyContent] =>
def submitReview(consignmentId: UUID, consignmentRef: String, userEmail: String): Action[AnyContent] = tnaUserAction { implicit request: Request[AnyContent] =>
val formValidationResult: Form[SelectedStatusData] = selectedDecisionForm.bindFromRequest()

val errorFunction: Form[SelectedStatusData] => Future[Result] = { formWithErrors: Form[SelectedStatusData] =>
Expand All @@ -57,8 +57,10 @@ class MetadataReviewActionController @Inject() (
} yield {
messagingService.sendMetadataReviewSubmittedNotification(
MetadataReviewSubmittedEvent(
consignmentReference = consignmentRef,
urlLink = generateUrlLink(request, routes.RequestMetadataReviewController.requestMetadataReviewPage(consignmentId).url)
consignmentRef,
urlLink = generateUrlLink(request, routes.MetadataReviewStatusController.metadataReviewStatusPage(consignmentId).url),
userEmail,
formData.statusId
)
)
Redirect(routes.MetadataReviewController.metadataReviews())
Expand All @@ -76,11 +78,13 @@ class MetadataReviewActionController @Inject() (
): Future[Result] = {
for {
consignment <- consignmentService.getConsignmentDetailForMetadataReview(consignmentId, request.token.bearerAccessToken)
userDetails <- keycloakConfiguration.userDetails(consignment.userid.toString)
} yield {
status(
views.html.tna.metadataReviewAction(
consignmentId,
consignment,
userDetails.email,
createDropDownField(List(InputNameAndValue("Approve", CompletedValue.value), InputNameAndValue("Reject", CompletedWithIssuesValue.value)), form)
)
)
Expand Down
4 changes: 3 additions & 1 deletion app/services/MessagingService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ object MessagingService {
)
case class MetadataReviewSubmittedEvent(
consignmentReference: String,
urlLink: String
urlLink: String,
userEmail: String,
status: String
)
}
8 changes: 4 additions & 4 deletions app/views/tna/metadataReviewAction.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
@import views.html.partials.{backLink, errorSummary, inputDropdown, downloadMetadataLink}

@import java.util.UUID
@(consignmentId: UUID, consignmentDetails: gcdfmr.GetConsignment, dropdownField: DropdownField)(implicit request: RequestHeader, messages: Messages)
@(consignmentId: UUID, consignmentDetails: gcdfmr.GetConsignment, userEmail: String, dropdownField: DropdownField)(implicit request: RequestHeader, messages: Messages)
@main("View Request for Metadata", hasError = dropdownField.fieldErrors.nonEmpty, backLink = Some(backLink(routes.MetadataReviewController.metadataReviews().url, "Back")), isTnaUser = true) {
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
Expand Down Expand Up @@ -39,10 +39,10 @@ <h1 class="govuk-heading-l govuk-!-margin-bottom-3">
</div>
<div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key">
UserId
Contact email
</dt>
<dd class="govuk-summary-list__value">
@consignmentDetails.userid
@userEmail
</dd>
</div>
</dl>
Expand All @@ -61,7 +61,7 @@ <h2 class="govuk-label-wrapper">
</label>
</h2>

@form(routes.MetadataReviewActionController.submitReview(consignmentId, consignmentDetails.consignmentReference), (Symbol("novalidate"), "")) {
@form(routes.MetadataReviewActionController.submitReview(consignmentId, consignmentDetails.consignmentReference, userEmail), (Symbol("novalidate"), "")) {
@CSRF.formField
@inputDropdown(
dropdownField.fieldId,
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ libraryDependencies ++= Seq(
"com.softwaremill.sttp.client" %% "circe" % sttpVersion,
"com.softwaremill.sttp.client" %% "async-http-client-backend-future" % sttpVersion,
"uk.gov.nationalarchives" %% "tdr-graphql-client" % "0.0.172",
"uk.gov.nationalarchives" %% "tdr-auth-utils" % "0.0.207",
"uk.gov.nationalarchives" %% "tdr-auth-utils" % "0.0.208",
"uk.gov.nationalarchives" %% "tdr-generated-graphql" % "0.0.380",
"uk.gov.nationalarchives" %% "tdr-metadata-validation" % "0.0.39",
"uk.gov.nationalarchives" %% "s3-utils" % "0.1.196",
Expand Down
1 change: 1 addition & 0 deletions conf/application.base.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pekko.actor.allow-java-serialization = "on"
pekko.actor.warn-about-java-serializer-usage = "off"

auth.secret = ${AUTH_SECRET}
read.auth.secret = ${READ_AUTH_SECRET}
auth.url=${AUTH_URL}

consignmentapi.url = ${consignmentapi.domain}"/graphql"
Expand Down
2 changes: 1 addition & 1 deletion conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,4 @@ GET /judgment/:consignmentId/transfer-complete
# Routes for TNA-User
GET /admin/metadata-review controllers.MetadataReviewController.metadataReviews()
GET /admin/metadata-review/:consignmentId controllers.MetadataReviewActionController.consignmentMetadataDetails(consignmentId: java.util.UUID)
POST /admin/metadata-review/:consignmentId controllers.MetadataReviewActionController.submitReview(consignmentId: java.util.UUID, consignmentRef: String)
POST /admin/metadata-review/:consignmentId controllers.MetadataReviewActionController.submitReview(consignmentId: java.util.UUID, consignmentRef: String, userEmail: String)
32 changes: 18 additions & 14 deletions test/controllers/MetadataReviewActionControllerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,11 @@ class MetadataReviewActionControllerSpec extends FrontEndTestHelper {

"MetadataReviewActionController GET" should {

"render the correct series details page with an authenticated user" in {
"render the correct metadata details page with an authenticated user" in {
setGetConsignmentDetailsForMetadataReviewResponse()

val controller = instantiateMetadataReviewActionController(getAuthorisedSecurityComponents, getValidTNAUserKeycloakConfiguration)
val metadataReviewActionPage = controller.consignmentMetadataDetails(consignmentId).apply(FakeRequest(GET, s"/admin/metadata-review/$consignmentId").withCSRFToken)

val metadataReviewActionPageAsString = contentAsString(metadataReviewActionPage)

playStatus(metadataReviewActionPage) mustBe OK
Expand All @@ -75,23 +74,27 @@ class MetadataReviewActionControllerSpec extends FrontEndTestHelper {
status(response) mustBe FORBIDDEN
}

"Update the consignment status and send metadata decision message when a valid form is submitted and the api response is successful" in {
"Update the consignment status and send MetadataReviewSubmittedEvent message when a valid form is submitted and the api response is successful" in {
val controller = instantiateMetadataReviewActionController(getAuthorisedSecurityComponents, getValidTNAUserKeycloakConfiguration)
val consignmentRef = "TDR-TEST-2024"
val expectedPath = s"/consignment/$consignmentId/metadata-review/request"
val userEmail = "[email protected]"
val status = CompletedValue.value
val expectedPath = s"/consignment/$consignmentId/metadata-review/review-progress"

// Custom ArgumentMatcher to match the event based on the consignment reference and the path
class MetadataReviewSubmittedEventMatcher(expectedConsignmentRef: String, expectedPath: String) extends ArgumentMatcher[MetadataReviewSubmittedEvent] {
// Custom ArgumentMatcher to match the event based on the consignment reference, path, userEmail and status
class MetadataReviewSubmittedEventMatcher(expectedConsignmentRef: String, expectedPath: String, expectedEmail: String, expectedStatus: String)
extends ArgumentMatcher[MetadataReviewSubmittedEvent] {
override def matches(event: MetadataReviewSubmittedEvent): Boolean = {
event.consignmentReference == expectedConsignmentRef && event.urlLink.contains(expectedPath)
event.consignmentReference == expectedConsignmentRef && event.urlLink.contains(expectedPath) && event.userEmail == expectedEmail && event.status == expectedStatus
}
}

val metadataReviewDecisionEventMatcher = new MetadataReviewSubmittedEventMatcher(consignmentRef, expectedPath)
val metadataReviewDecisionEventMatcher = new MetadataReviewSubmittedEventMatcher(consignmentRef, expectedPath, userEmail, status)

setUpdateConsignmentStatus(wiremockServer)

val reviewSubmit = controller.submitReview(consignmentId, consignmentRef).apply(FakeRequest().withFormUrlEncodedBody(("status", CompletedValue.value)).withCSRFToken)
val reviewSubmit =
controller.submitReview(consignmentId, consignmentRef, userEmail).apply(FakeRequest().withFormUrlEncodedBody(("status", status)).withCSRFToken)
playStatus(reviewSubmit) mustBe SEE_OTHER
redirectLocation(reviewSubmit) must be(Some(s"/admin/metadata-review"))
verify(messagingService, times(1)).sendMetadataReviewSubmittedNotification(argThat(metadataReviewDecisionEventMatcher))
Expand All @@ -100,8 +103,9 @@ class MetadataReviewActionControllerSpec extends FrontEndTestHelper {
"display errors when an invalid form is submitted" in {
val controller = instantiateMetadataReviewActionController(getAuthorisedSecurityComponents, getValidTNAUserKeycloakConfiguration)
val consignmentRef = "TDR-TEST-2024"
val metadataReviewDecisionEvent = MetadataReviewSubmittedEvent(consignmentRef, "SomeUrl")
val reviewSubmit = controller.submitReview(consignmentId, consignmentRef).apply(FakeRequest().withFormUrlEncodedBody(("status", "")).withCSRFToken)
val userEmail = "[email protected]"
val metadataReviewDecisionEvent = MetadataReviewSubmittedEvent(consignmentRef, "SomeUrl", userEmail, "status")
val reviewSubmit = controller.submitReview(consignmentId, consignmentRef, userEmail).apply(FakeRequest().withFormUrlEncodedBody(("status", "")).withCSRFToken)
setUpdateConsignmentStatus(wiremockServer)
setGetConsignmentDetailsForMetadataReviewResponse()
playStatus(reviewSubmit) mustBe BAD_REQUEST
Expand Down Expand Up @@ -174,15 +178,15 @@ class MetadataReviewActionControllerSpec extends FrontEndTestHelper {
| SeriesName
| </dd>""".stripMargin)
pageAsString must include(s"""<dt class="govuk-summary-list__key">
| UserId
| Contact email
| </dt>
| <dd class="govuk-summary-list__value">
| $userId
| [email protected]
| </dd>""".stripMargin)
pageAsString must include("""1. Download and review transfer metadata""")
pageAsString must include(downloadLinkHTML(consignmentId))
pageAsString must include("""2. Set the status of this review""")
pageAsString must include(s"""<form action="/admin/metadata-review/$consignmentId?consignmentRef=TDR-2024-TEST" method="POST" novalidate="">""")
pageAsString must include(s"""<form action="/admin/metadata-review/$consignmentId?consignmentRef=TDR-2024-TEST&amp;userEmail=email%40test.com" method="POST" novalidate="">""")
pageAsString must include(s"""<option value="" selected>
| Select a status
| </option>""".stripMargin)
Expand Down
1 change: 1 addition & 0 deletions test/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ auth.domain="localhost:9005"
auth.url="http://localhost:9005"
auth.callback="http://localhost:9000/callback"
auth.secret="f5d12779-2927-4992-a7cf-77358cf42e20"
read.auth.secret="f5d12779-2927-4992-a7cf-77358cf42e20"

consignmentapi.url="http://localhost:9006/graphql"

Expand Down
8 changes: 6 additions & 2 deletions test/services/MessagingServiceSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,15 @@ class MessagingServiceSpec extends AnyFlatSpec with Matchers {
val service = createService
val metadataReviewSubmittedEvent = MessagingService.MetadataReviewSubmittedEvent(
consignmentReference = "Ref123",
urlLink = "example.com"
urlLink = "example.com",
userEmail = "[email protected]",
status = "Status"
)
val expectedMessageString = """{
| "consignmentReference" : "Ref123",
| "urlLink" : "example.com"
| "urlLink" : "example.com",
| "userEmail" : "[email protected]",
| "status" : "Status"
|}""".stripMargin
service.sendMetadataReviewSubmittedNotification(metadataReviewSubmittedEvent)
verify(mockUtils).publish(expectedMessageString, testArn)
Expand Down
2 changes: 2 additions & 0 deletions test/testUtils/FrontEndTestHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import play.api.test.Injecting
import play.api.{Application, Configuration}
import services.Statuses.{InProgressValue, SeriesType}
import uk.gov.nationalarchives.tdr.GraphQLClient
import uk.gov.nationalarchives.tdr.keycloak.KeycloakUtils.UserDetails
import uk.gov.nationalarchives.tdr.keycloak.Token
import viewsapi.FrontEndInfo

Expand Down Expand Up @@ -929,6 +930,7 @@ trait FrontEndTestHelper extends PlaySpec with MockitoSugar with Injecting with
accessToken.setEmail("[email protected]")
val token = Token(accessToken, new BearerAccessToken)
doAnswer(_ => Some(token)).when(keycloakMock).token(any[String])
when(keycloakMock.userDetails(any[String])).thenReturn(Future(UserDetails("[email protected]")))
keycloakMock
}

Expand Down

0 comments on commit 9310c01

Please sign in to comment.