Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into update/scala-stewar…
Browse files Browse the repository at this point in the history
…d-dependencies/play-redis-4.1.0

# Conflicts:
#	build.sbt
  • Loading branch information
thanhz committed Apr 16, 2024
2 parents ebf79cd + 6e31816 commit 71eaac5
Show file tree
Hide file tree
Showing 50 changed files with 6,017 additions and 6,507 deletions.
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ updates:
directory: "/npm"
schedule:
interval: "daily"
groups:
npm-dependencies:
applies-to: version-updates
patterns:
- "*"
versioning-strategy: increase
- package-ecosystem: "docker"
directory: "/"
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ jobs:
pre-deploy:
uses: nationalarchives/tdr-github-actions/.github/workflows/ecs_build.yml@main
with:
java-version: '17'
repo-name: tdr-transfer-frontend
image-name: transfer-frontend
build-command: |
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ jobs:
npm --prefix npm ci
npm --prefix npm run checks
sbt scalafmtCheckAll test
java-version: '17'
secrets:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
22 changes: 0 additions & 22 deletions .github/workflows/upsert-scala-steward-dependencies-branch.yml

This file was deleted.

14 changes: 9 additions & 5 deletions app/auth/TokenSecurity.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package auth
import com.nimbusds.oauth2.sdk.token.BearerAccessToken
import configuration.KeycloakConfiguration
import io.opentelemetry.api.trace.Span
import org.pac4j.core.profile.{ProfileManager, UserProfile}
import org.pac4j.core.profile.UserProfile
import org.pac4j.oidc.profile.OidcProfile
import org.pac4j.play.PlayWebContext
import org.pac4j.play.context.PlayFrameworkParameters
import play.api.i18n.I18nSupport
import play.api.mvc.{Action, AnyContent, Request, Result}
import services.ConsignmentService
Expand All @@ -24,14 +26,16 @@ trait TokenSecurity extends OidcSecurity with I18nSupport {
val userIdKey = "UserId"

def getProfile(request: Request[AnyContent]): Optional[UserProfile] = {
val webContext = new PlayWebContext(request)
val profileManager = new ProfileManager(webContext, sessionStore)
val parameters = new PlayFrameworkParameters(request)
val webContext = controllerComponents.config.getWebContextFactory.newContext(parameters).asInstanceOf[PlayWebContext]
val sessionStore = config.getSessionStoreFactory.newSessionStore(parameters)
val profileManager = controllerComponents.config.getProfileManagerFactory.apply(webContext, sessionStore)
profileManager.getProfile
}

implicit def requestToRequestWithToken(request: Request[AnyContent]): RequestWithToken = {
val profile = getProfile(request)
val token: BearerAccessToken = profile.get().getAttribute("access_token").asInstanceOf[BearerAccessToken]
val profile = getProfile(request).get().asInstanceOf[OidcProfile]
val token: BearerAccessToken = profile.getAccessToken.asInstanceOf[BearerAccessToken]
val accessToken: Option[Token] = keycloakConfiguration.token(token.getValue)
RequestWithToken(request, accessToken)
}
Expand Down
12 changes: 8 additions & 4 deletions app/auth/UnprotectedPageController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ package auth

import com.nimbusds.jwt.SignedJWT
import com.nimbusds.oauth2.sdk.token.BearerAccessToken
import org.pac4j.core.profile.{CommonProfile, ProfileManager}
import org.pac4j.core.profile.{CommonProfile, ProfileManager, UserProfile}
import org.pac4j.oidc.profile.OidcProfile
import org.pac4j.play.PlayWebContext
import org.pac4j.play.scala.{Security, SecurityComponents}
import org.pac4j.play.context.PlayFrameworkParameters
import org.pac4j.play.scala.{Pac4jScalaTemplateHelper, Security, SecurityComponents}
import play.api.mvc.{AnyContent, Request}

import javax.inject.Inject

class UnprotectedPageController @Inject() (val controllerComponents: SecurityComponents) extends Security[CommonProfile] {

private def getProfile(request: Request[AnyContent]): ProfileManager = {
val parameters = new PlayFrameworkParameters(request)
val sessionStore = config.getSessionStoreFactory.newSessionStore(parameters)
val webContext = new PlayWebContext(request)
new ProfileManager(webContext, sessionStore)
}
Expand All @@ -26,7 +30,7 @@ class UnprotectedPageController @Inject() (val controllerComponents: SecurityCom
val profileManager = getProfile(request)
val profile = profileManager.getProfile
if (profile.isPresent) {
val token: BearerAccessToken = profile.get().getAttribute("access_token").asInstanceOf[BearerAccessToken]
val token: BearerAccessToken = profile.get().asInstanceOf[OidcProfile].getAccessToken.asInstanceOf[BearerAccessToken]
val parsedToken = SignedJWT.parse(token.getValue).getJWTClaimsSet
parsedToken.getClaim("name").toString
} else {
Expand All @@ -38,7 +42,7 @@ class UnprotectedPageController @Inject() (val controllerComponents: SecurityCom
val profileManager = getProfile(request)
val profile = profileManager.getProfile
if (profile.isPresent) {
val token: BearerAccessToken = profile.get().getAttribute("access_token").asInstanceOf[BearerAccessToken]
val token: BearerAccessToken = profile.get().asInstanceOf[OidcProfile].getAccessToken.asInstanceOf[BearerAccessToken]
val parsedToken = SignedJWT.parse(token.getValue).getJWTClaimsSet
parsedToken.getBooleanClaim("judgment_user")
} else {
Expand Down
16 changes: 10 additions & 6 deletions app/configuration/AccessLoggingFilter.scala
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package configuration

import akka.stream.Materializer
import auth.OidcSecurity
import com.nimbusds.oauth2.sdk.token.BearerAccessToken
import org.apache.pekko.stream.Materializer
import org.pac4j.core.profile.ProfileManager
import org.pac4j.oidc.profile.OidcProfile
import org.pac4j.play.PlayWebContext
import org.pac4j.play.context.PlayFrameworkParameters
import org.pac4j.play.scala.SecurityComponents
import play.api.Logging
import play.api.mvc.{Filter, RequestHeader, Result}

import javax.inject.Inject
import scala.compat.java8.OptionConverters._
import scala.concurrent.{ExecutionContext, Future}
import scala.jdk.OptionConverters.RichOptional

class AccessLoggingFilter @Inject() (implicit
val mat: Materializer,
Expand All @@ -29,11 +30,14 @@ class AccessLoggingFilter @Inject() (implicit
nextFilter(request)
} else {
nextFilter(request).map { result =>
val parameters = new PlayFrameworkParameters(request)
val sessionStore = config.getSessionStoreFactory.newSessionStore(parameters)
val webContext = new PlayWebContext(request)
val profileManager = new ProfileManager(webContext, sessionStore)
val userId: String = profileManager.getProfile.asScala
.map(_.getAttribute("access_token").asInstanceOf[BearerAccessToken])
.flatMap(token => keycloakConfiguration.token(token.getValue))

val userId: String = profileManager.getProfile.toScala
.map(_.asInstanceOf[OidcProfile].getAccessToken.toString)
.flatMap(token => keycloakConfiguration.token(token))
.map(_.userId.toString)
.getOrElse("user-logged-out")

Expand Down
7 changes: 7 additions & 0 deletions app/configuration/ApplicationConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,12 @@ class ApplicationConfig @Inject() (configuration: Configuration) {

val blockDraftMetadataUpload: Boolean = configuration.get[Boolean]("featureAccessBlock.blockDraftMetadataUpload")

val blockAutomateJudgmentTransfers: Boolean = configuration.get[Boolean]("featureAccessBlock.blockAutomateJudgmentTransfers")

val metadataValidationBaseUrl: String = configuration.get[String]("metadatavalidation.baseUrl")

val s3Endpoint: String = configuration.get[String]("s3.endpoint")

val draft_metadata_s3_bucket_name: String = configuration.get[String]("draft_metadata_s3_bucket_name")

}
21 changes: 11 additions & 10 deletions app/configuration/CustomSavedRequestHandler.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package configuration

import org.pac4j.core.context.WebContext
import org.pac4j.core.context.session.SessionStore
import org.pac4j.core.context.{CallContext, WebContext}
import org.pac4j.core.engine.savedrequest.SavedRequestHandler
import org.pac4j.core.exception.http.{FoundAction, HttpAction}
import org.pac4j.core.util.{HttpActionHelper, Pac4jConstants}
Expand All @@ -10,25 +9,27 @@ import play.api.Logging
import scala.jdk.OptionConverters.RichOptional

class CustomSavedRequestHandler extends SavedRequestHandler with Logging {
override def save(context: WebContext, sessionStore: SessionStore): Unit = {
override def save(context: CallContext): Unit = {
logger.info("Saving webContext")
val webContext = context.webContext()

val requestedUrl = getRequestedUrl(context)
val requestedUrl = getRequestedUrl(webContext)

// Need to specify the type of SessionStore so that we can pass the context into the set method context.
sessionStore
.set(context, Pac4jConstants.REQUESTED_URL, new FoundAction(requestedUrl))
context.sessionStore().set(webContext, Pac4jConstants.REQUESTED_URL, new FoundAction(requestedUrl))
}

private def getRequestedUrl(context: WebContext): String = context.getFullRequestURL

override def restore(context: WebContext, sessionStore: SessionStore, defaultUrl: String): HttpAction = {
val optRequestedUrl = sessionStore
.get(context, Pac4jConstants.REQUESTED_URL)
override def restore(context: CallContext, defaultUrl: String): HttpAction = {
val webContext = context.webContext()
val optRequestedUrl = context
.sessionStore()
.get(webContext, Pac4jConstants.REQUESTED_URL)

val redirectAction = optRequestedUrl.toScala
.map(_.asInstanceOf[FoundAction])
.getOrElse(new FoundAction(defaultUrl))
HttpActionHelper.buildRedirectUrlAction(context, redirectAction.getLocation)
HttpActionHelper.buildRedirectUrlAction(webContext, redirectAction.getLocation)
}
}
21 changes: 16 additions & 5 deletions app/controllers/AdditionalMetadataEntryMethodController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package controllers

import auth.TokenSecurity
import configuration.{ApplicationConfig, KeycloakConfiguration}
import graphql.codegen.types.ConsignmentStatusInput
import org.pac4j.play.scala.SecurityComponents
import play.api.data.Form
import play.api.data.Forms.{mapping, optional, text}
import play.api.i18n.I18nSupport
import play.api.mvc.{Action, AnyContent, Request, Result}
import services.Statuses.InProgressValue
import services.Statuses.{DraftMetadataType, InProgressValue}
import services._
import viewsapi.Caching.preventCaching

Expand Down Expand Up @@ -46,14 +47,15 @@ class AdditionalMetadataEntryMethodController @Inject() (
}

def submitAdditionalMetadataEntryMethod(consignmentId: UUID): Action[AnyContent] = standardTypeAction(consignmentId) { implicit request: Request[AnyContent] =>
val token = request.token.bearerAccessToken
if (applicationConfig.blockDraftMetadataUpload) {
Future(Ok(views.html.notFoundError(name = request.token.name, isLoggedIn = true, isJudgmentUser = false)))
} else {
val formValidationResult: Form[AdditionalMetadataEntryData] = additionalMetadataEntryForm.bindFromRequest()

val errorFunction: Form[AdditionalMetadataEntryData] => Future[Result] = { formWithErrors: Form[AdditionalMetadataEntryData] =>
for {
reference <- consignmentService.getConsignmentRef(consignmentId, request.token.bearerAccessToken)
reference <- consignmentService.getConsignmentRef(consignmentId, token)
} yield {
Ok(views.html.standard.additionalMetadataEntryMethod(consignmentId, reference, formWithErrors, request.token.name))
.uncache()
Expand All @@ -64,9 +66,18 @@ class AdditionalMetadataEntryMethodController @Inject() (
formData.metadataRoute match {
case Some("manual") => Future.successful(Redirect(routes.AdditionalMetadataController.start(consignmentId)))
case Some("csv") =>
consignmentStatusService
.addConsignmentStatus(consignmentId, "DraftMetadata", InProgressValue.value, request.token.bearerAccessToken)
.map(_ => Redirect(routes.DraftMetadataUploadController.draftMetadataUploadPage(consignmentId)))
for {
consignmentStatuses <- consignmentStatusService.getConsignmentStatuses(consignmentId, token)
statusesToValue = consignmentStatusService.getStatusValues(consignmentStatuses, DraftMetadataType).values.headOption.flatten
_ <-
if (statusesToValue.isEmpty) {
consignmentStatusService.addConsignmentStatus(consignmentId, DraftMetadataType.id, InProgressValue.value, token)
} else {
consignmentStatusService.updateConsignmentStatus(ConsignmentStatusInput(consignmentId, DraftMetadataType.id, Some(InProgressValue.value)), token)
}
} yield {
Redirect(routes.DraftMetadataUploadController.draftMetadataUploadPage(consignmentId))
}
case _ => Future.successful(Redirect(routes.DownloadMetadataController.downloadMetadataPage(consignmentId)))
}
}
Expand Down
3 changes: 3 additions & 0 deletions app/controllers/ConfirmTransferController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ class ConfirmTransferController @Inject() (
}
} yield res
}

def judgmentChecksPassedSubmit(consignmentId: UUID): Action[AnyContent] = finalJudgmentTransferConfirmationSubmit(consignmentId: UUID)

}

case class ConsignmentSummaryData(seriesCode: String, transferringBody: String, totalFiles: Int, consignmentReference: String)
Expand Down
36 changes: 34 additions & 2 deletions app/controllers/DraftMetadataUploadController.scala
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
package controllers

import auth.TokenSecurity
import cats.effect.IO
import cats.effect.IO.fromOption
import cats.effect.unsafe.implicits.global
import configuration.{ApplicationConfig, KeycloakConfiguration}
import org.pac4j.play.scala.SecurityComponents
import play.api.i18n.I18nSupport
import play.api.mvc.{Action, AnyContent, Request}
import play.api.libs.Files.TemporaryFile
import play.api.mvc.{Action, AnyContent, MultipartFormData, Request, Result}
import services._
import viewsapi.Caching.preventCaching

import java.util.UUID
import javax.inject.{Inject, Singleton}
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Using

@Singleton
class DraftMetadataUploadController @Inject() (
val controllerComponents: SecurityComponents,
val keycloakConfiguration: KeycloakConfiguration,
val frontEndInfoConfiguration: ApplicationConfig,
val consignmentService: ConsignmentService,
val uploadService: UploadService,
val draftMetadataService: DraftMetadataService,
val applicationConfig: ApplicationConfig
)(implicit val ec: ExecutionContext)
extends TokenSecurity
Expand All @@ -30,9 +37,34 @@ class DraftMetadataUploadController @Inject() (
for {
reference <- consignmentService.getConsignmentRef(consignmentId, request.token.bearerAccessToken)
} yield {
Ok(views.html.draftmetadata.draftMetadataUpload(consignmentId, reference, frontEndInfoConfiguration.frontEndInfo, request.token.name))
Ok(views.html.draftmetadata.draftMetadataUpload(consignmentId, reference, frontEndInfoConfiguration.frontEndInfo, request.token.bearerAccessToken.getValue))
.uncache()
}
}
}

def saveDraftMetadata(consignmentId: java.util.UUID): Action[MultipartFormData[TemporaryFile]] = secureAction.async(parse.multipartFormData) {

implicit request: Request[MultipartFormData[TemporaryFile]] =>
val successPage = routes.DraftMetadataChecksController.draftMetadataChecksPage(consignmentId)
val token = request.asInstanceOf[Request[AnyContent]].token
val uploadBucket = s"${applicationConfig.draft_metadata_s3_bucket_name}"
val uploadKey = s"$consignmentId/draft-metadata.csv"
val noDraftMetadataFileUploaded: String = "No meta data file provided"

def uploadDraftMetadata: IO[Result] = for {
firstFilePart <- fromOption(request.body.files.headOption)(new RuntimeException(noDraftMetadataFileUploaded))
file <- fromOption(request.body.file(firstFilePart.key))(new RuntimeException(noDraftMetadataFileUploaded))
draftMetadata <- fromOption(Using(scala.io.Source.fromFile(file.ref.getAbsoluteFile))(_.mkString).toOption)(new RuntimeException(noDraftMetadataFileUploaded))
_ <- IO.fromFuture(IO(uploadService.uploadDraftMetadata(uploadBucket, uploadKey, draftMetadata)))
_ <- IO.fromFuture(IO { draftMetadataService.triggerDraftMetadataValidator(consignmentId, token.bearerAccessToken.getValue) })
successPage <- IO(play.api.mvc.Results.Redirect(successPage))
} yield successPage

uploadDraftMetadata
.recoverWith { case error =>
IO(InternalServerError(s"Unable to upload draft metadata to : $uploadBucket/$uploadKey: Error:" + error.getMessage + " stack" + error.getStackTrace.mkString))
}
.unsafeToFuture()
}
}
20 changes: 13 additions & 7 deletions app/controllers/FileChecksResultsController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class FileChecksResultsController @Inject() (
pageTitle,
consignmentId,
reference,
request.token.name
request.token.name,
applicationConfig.blockDraftMetadataUpload
)
)
} else {
Expand All @@ -56,6 +57,7 @@ class FileChecksResultsController @Inject() (

def judgmentFileCheckResultsPage(consignmentId: UUID): Action[AnyContent] = judgmentTypeAction(consignmentId) { implicit request: Request[AnyContent] =>
val pageTitle = "Results of checks"
val blockAutomateJudgmentTransfers = applicationConfig.blockAutomateJudgmentTransfers
for {
consignmentStatuses <- consignmentStatusService.getConsignmentStatuses(consignmentId, request.token.bearerAccessToken)
reference <- consignmentService.getConsignmentRef(consignmentId, request.token.bearerAccessToken)
Expand All @@ -68,12 +70,16 @@ class FileChecksResultsController @Inject() (
fileCheck <- consignmentService.getConsignmentFileChecks(consignmentId, request.token.bearerAccessToken)
result <-
if (fileCheck.allChecksSucceeded) {
consignmentService
.getConsignmentFilesData(consignmentId, request.token.bearerAccessToken)
.flatMap(files => {
val filename = files.files.head.metadata.clientSideOriginalFilePath.get
Future(Ok(views.html.judgment.judgmentFileChecksResults(filename, pageTitle, consignmentId, reference, request.token.name)).uncache())
})
if (blockAutomateJudgmentTransfers) {
consignmentService
.getConsignmentFilesData(consignmentId, request.token.bearerAccessToken)
.flatMap(files => {
val filename = files.files.head.metadata.clientSideOriginalFilePath.get
Future(Ok(views.html.judgment.judgmentFileChecksResults(filename, pageTitle, consignmentId, reference, request.token.name)).uncache())
})
} else {
Future(Redirect(routes.ConfirmTransferController.judgmentChecksPassedSubmit(consignmentId)).uncache())
}
} else {
Future(Ok(views.html.fileChecksResultsFailed(request.token.name, pageTitle, reference, isJudgmentUser = true)).uncache())
}
Expand Down
Loading

0 comments on commit 71eaac5

Please sign in to comment.