Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
17 changes: 3 additions & 14 deletions app/uk/gov/hmrc/bindingtarifffilestore/config/AppConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,22 @@ class AppConfig @Inject() (

lazy val authorization: String = config.get[String]("auth.api-token")

lazy val s3Configuration: S3Configuration = S3Configuration(
config.get[String]("s3.region"),
config.get[String]("s3.bucket"),
Option(config.get[String]("s3.endpoint")).filter(_.nonEmpty)
)
lazy val appName: String = config.get[String]("appName")

lazy val upscanInitiateUrl: String = servicesConfig.baseUrl("upscan-initiate")
lazy val fileStoreSizeConfiguration: FileStoreSizeConfiguration = FileStoreSizeConfiguration(
maxFileSize = config.get[Int]("upscan.maxFileSize"),
minFileSize = config.get[Int]("upscan.minFileSize")
)

lazy val s3bucket: String = config.get[String]("s3.bucket")

lazy val filestoreUrl: String = config.get[String]("filestore.url")
lazy val filestoreSSL: Boolean = config.get[Boolean]("filestore.ssl")

lazy val isTestMode: Boolean = config.getOptional[Boolean]("testMode").getOrElse(false)
}

case class S3Configuration(
region: String,
bucket: String,
endpoint: Option[String]
) {

def baseUrl: String = endpoint.getOrElse(s"https://s3-$region.amazonaws.com")
}

case class FileStoreSizeConfiguration(
minFileSize: Int,
maxFileSize: Int
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright 2025 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.gov.hmrc.bindingtarifffilestore.connector

import com.google.inject.Inject
import uk.gov.hmrc.bindingtarifffilestore.config.AppConfig
import uk.gov.hmrc.bindingtarifffilestore.model.FileMetadata
import uk.gov.hmrc.bindingtarifffilestore.util.Logging
import uk.gov.hmrc.http.HeaderCarrier
import uk.gov.hmrc.objectstore.client.play.PlayObjectStoreClient
import uk.gov.hmrc.objectstore.client.{ObjectSummary, Path}

import java.net.URI
import javax.inject.Singleton
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success, Try}

@Singleton
class ObjectStoreConnector @Inject() (
client: PlayObjectStoreClient,
config: AppConfig
)(implicit
val ec: ExecutionContext
) extends Logging {

private val directory: Path.Directory =
Path.Directory(config.s3bucket)

def getAll(path: Path.Directory)(implicit hc: HeaderCarrier): Future[List[ObjectSummary]] =
client
.listObjects(path)
.map(_.objectSummaries.map(o => ObjectSummary(o.location, o.contentLength, o.lastModified)))

def upload(fileMetaData: FileMetadata)(implicit hc: HeaderCarrier): FileMetadata =
Try(
client
.uploadFromUrl(
from = new URI(fileMetaData.url.getOrElse(throw new IllegalArgumentException("Missing URL"))).toURL,
to = directory.file(fileMetaData.fileName.getOrElse(""))
)
) match {
case Success(_) =>
log.info("File uploaded to Object Store")
fileMetaData
case Failure(e: Throwable) =>
log.error("Failed to upload to the object store.", e)
throw e
}

def delete(fileName: String)(implicit hc: HeaderCarrier): Future[Unit] =
client.deleteObject(
path = directory.file(fileName)
)

def deleteAll()(implicit hc: HeaderCarrier): Future[Unit] =
getAll(directory).map(files =>
if (files.nonEmpty) {
log.info(s"Removing [${files.length}] files from object store")
Future.traverse(files) { filename =>
client.deleteObject(
path = directory.file(filename.location.fileName)
)
}

} else {
log.info(s"No files to remove from object store")
}
)

def sign(fileMetaData: FileMetadata)(implicit hc: HeaderCarrier): Future[FileMetadata] =
if (fileMetaData.url.isDefined) {
client
.presignedDownloadUrl(
path = directory.file(fileMetaData.fileName.get)
)
.transformWith {
case scala.util.Failure(exception) =>
log.error(s"Failure to get pre-signed URL to ${directory.file(fileMetaData.id)} because of $exception")
exception.printStackTrace()
Future.successful(fileMetaData)
case scala.util.Success(presignedDownloadUrl) =>
val updatedMetaData = fileMetaData.copy(url = Some(presignedDownloadUrl.downloadUrl.toString))
Future.successful(updatedMetaData)
}
} else {
Future.successful(fileMetaData)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ package uk.gov.hmrc.bindingtarifffilestore.controllers

import play.api.Logging
import play.api.libs.Files.TemporaryFile
import play.api.libs.json.Format.GenericFormat
import play.api.libs.json.OFormat.oFormatFromReadsAndOWrites
import play.api.libs.json.{JsValue, Json}
import play.api.mvc._
import uk.gov.hmrc.bindingtarifffilestore.config.AppConfig
import uk.gov.hmrc.bindingtarifffilestore.model.FileMetadataREST._
import uk.gov.hmrc.bindingtarifffilestore.model.FileMetadataREST.format
import uk.gov.hmrc.bindingtarifffilestore.model._
import uk.gov.hmrc.bindingtarifffilestore.model.upscan.ScanResult
import uk.gov.hmrc.bindingtarifffilestore.model.upscan.v2._
Expand Down Expand Up @@ -52,11 +54,13 @@ class FileStoreController @Inject() (
def encodeInBase64(text: String): String =
Base64.getEncoder.encodeToString(text.getBytes(StandardCharsets.UTF_8))

private def withFileMetadata(id: String)(f: FileMetadata => Future[Result]): Future[Result] =
private def withFileMetadata(id: String)(f: FileMetadata => Future[Result])(implicit
hc: HeaderCarrier
): Future[Result] =
service.find(id).flatMap {
case Some(meta) =>
logger.info(
s"[FileStoreController][withFileMetadata] Attachement File: $id, Scan succeeded with details fileMetadata: ${encodeInBase64(meta.toString)}"
s"[FileStoreController][withFileMetadata] Attachment File: $id, Scan succeeded with details fileMetadata: ${encodeInBase64(meta.toString)}"
)
f(meta)
case None =>
Expand All @@ -67,16 +71,20 @@ class FileStoreController @Inject() (
lazy private val testModeFilter = TestMode.actionFilter(appConfig, parse.default)

def deleteAll(): Action[AnyContent] = withErrorHandling {
implicit val hc: HeaderCarrier = HeaderCarrier()

testModeFilter.async {
service
.deleteAll()
.map(_ => NoContent)
}
}

def delete(id: String): Action[AnyContent] = withErrorHandling { _ =>
def delete(id: String, filename: String): Action[AnyContent] = withErrorHandling { _ =>
implicit val hc: HeaderCarrier = HeaderCarrier()

service
.delete(id)
.delete(id, filename)
.map(_ => NoContent)
}

Expand Down Expand Up @@ -106,8 +114,10 @@ class FileStoreController @Inject() (
}
}

def get(id: String): Action[AnyContent] = Action.async {
withFileMetadata(id)(meta => Future.successful(Ok(Json.toJson(meta))))
def get(id: String): Action[AnyContent] = Action.async { implicit request =>
withFileMetadata(id) { meta =>
Future.successful(Ok(Json.toJson(meta)))
}
}

def notification(id: String): Action[JsValue] = withErrorHandling {
Expand All @@ -134,6 +144,8 @@ class FileStoreController @Inject() (
}

def getAll(search: Search, pagination: Option[Pagination]): Action[AnyContent] = withErrorHandling { _ =>
implicit val hc: HeaderCarrier = HeaderCarrier()

service.find(search, pagination.getOrElse(Pagination.max)).map { pagedResults =>
if (pagination.isDefined) {
Ok(Json.toJson(pagedResults))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package uk.gov.hmrc.bindingtarifffilestore.model

import play.api.mvc.QueryStringBindable
import uk.gov.hmrc.bindingtarifffilestore.model.Pagination.{defaultPageSize, defaultPageStart}

case class Pagination(
page: Int = defaultPageStart,
Expand All @@ -28,7 +27,7 @@ object Pagination {
val defaultPageStart = 1
val defaultPageSize = 100

val max: Pagination = Pagination(1, Integer.MAX_VALUE)
val max: Pagination = Pagination(1, 10000)

private val pageKey = "page"
private val pageSizeKey = "page_size"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,13 @@
package uk.gov.hmrc.bindingtarifffilestore.repository

import org.mongodb.scala.bson.conversions.Bson
import org.mongodb.scala.model.Filters._
import org.mongodb.scala.model._
import org.mongodb.scala.model.*
import org.mongodb.scala.model.Filters.*
import org.mongodb.scala.result.UpdateResult
import uk.gov.hmrc.bindingtarifffilestore.model._
import uk.gov.hmrc.bindingtarifffilestore.model.*
import uk.gov.hmrc.bindingtarifffilestore.util.Logging
import uk.gov.hmrc.mongo.MongoComponent
import uk.gov.hmrc.mongo.play.json.PlayMongoRepository
import org.mongodb.scala.SingleObservableFuture
import org.mongodb.scala.ObservableFuture

import java.time.Instant
import javax.inject.{Inject, Singleton}
Expand Down
Loading