Skip to content

Commit

Permalink
APIS-6688 - Update mongo driver (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobias1087 authored Jan 31, 2024
1 parent 0844db7 commit 7cd8e60
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@ import org.scalatest.OptionValues
import play.api.libs.json.Json
import play.api.mvc._
import play.api.test.Helpers._
import uk.gov.hmrc.apisubscriptionfields.model.ErrorCode.{INVALID_REQUEST_PAYLOAD, NOT_FOUND_CODE}
import uk.gov.hmrc.apisubscriptionfields.model.ErrorCode
import uk.gov.hmrc.apisubscriptionfields.model.JsErrorResponse
import uk.gov.hmrc.apisubscriptionfields.utils.ApplicationLogger

import scala.concurrent.Future

class ApiSubscriptionFieldsUnhappySpec extends AcceptanceTestSpec
with OptionValues
with SubscriptionFieldsTestData
with ApplicationLogger {
with OptionValues
with SubscriptionFieldsTestData
with ApplicationLogger {

Feature("Subscription-Fields") {
appLogger.logger.info(s"App.mode = ${app.mode.toString}")

Scenario("the API is called to GET non-existing subscription fields") {

Given("the API is called to GET non-existing subscription fields")
val request = createRequest(GET, subscriptionFieldsEndpoint(fakeRawClientId, fakeRawContext, fakeRawVersion))
val request = createRequest(GET, subscriptionFieldsEndpoint(fakeRawClientId, fakeRawContext, fakeRawVersion))
When("a GET request with data is sent to the API")
val result: Option[Future[Result]] = route(app, request)

Expand All @@ -48,7 +48,7 @@ class ApiSubscriptionFieldsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe NOT_FOUND

And("the response body is empty")
contentAsJson(resultFuture) shouldBe JsErrorResponse(NOT_FOUND_CODE, s"Subscription fields not found for ($fakeRawClientId, $fakeRawContext, $fakeRawVersion)")
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.NOT_FOUND, s"Subscription fields not found for ($fakeRawClientId, $fakeRawContext, $fakeRawVersion)")
}

Scenario("the API is called to GET with an unknown fieldsId") {
Expand All @@ -66,7 +66,7 @@ class ApiSubscriptionFieldsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe NOT_FOUND

And("the response body is empty")
contentAsJson(resultFuture) shouldBe JsErrorResponse(NOT_FOUND_CODE, s"FieldsId (${FakeRawFieldsId.toString}) was not found")
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.NOT_FOUND, s"FieldsId (${FakeRawFieldsId.toString}) was not found")
}

Scenario("the API is called to GET an unknown application clientId") {
Expand All @@ -84,7 +84,7 @@ class ApiSubscriptionFieldsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe NOT_FOUND

And("the response body is empty")
contentAsJson(resultFuture) shouldBe JsErrorResponse(NOT_FOUND_CODE, s"ClientId ($fakeRawClientId) was not found")
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.NOT_FOUND, s"ClientId ($fakeRawClientId) was not found")
}

Scenario("the API is called to DELETE an unknown subscription field") {
Expand All @@ -102,7 +102,7 @@ class ApiSubscriptionFieldsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe NOT_FOUND

And("the response body is empty")
contentAsJson(resultFuture) shouldBe JsErrorResponse(NOT_FOUND_CODE, s"Subscription fields not found for ($fakeRawClientId, $fakeRawContext, $fakeRawVersion)")
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.NOT_FOUND, s"Subscription fields not found for ($fakeRawClientId, $fakeRawContext, $fakeRawVersion)")
}

Scenario("the API is called to PUT subscription fields with an invalid JSON payload") {
Expand All @@ -121,13 +121,13 @@ class ApiSubscriptionFieldsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe UNPROCESSABLE_ENTITY

And("the response body contains error message")
contentAsJson(resultFuture) shouldBe JsErrorResponse(INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
}

Scenario("the API is called to PUT subscription fields with an invalid non JSON payload") {

Given("the API is called to PUT subscription fields with an invalid non JSON payload")
val request = createRequest(PUT, subscriptionFieldsEndpoint(fakeRawClientId, fakeRawContext, fakeRawVersion))
val request = createRequest(PUT, subscriptionFieldsEndpoint(fakeRawClientId, fakeRawContext, fakeRawVersion))
.withBody(InvalidNonJsonPayload)

When("a PUT request with data is sent to the API")
Expand All @@ -140,7 +140,7 @@ class ApiSubscriptionFieldsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe UNSUPPORTED_MEDIA_TYPE

And("the response body contains error message")
contentAsJson(resultFuture) shouldBe JsErrorResponse(INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ import play.api.libs.json.Json
import play.api.mvc._
import play.api.mvc.request.RequestTarget
import play.api.test.Helpers._
import uk.gov.hmrc.apisubscriptionfields.model.ErrorCode.{INVALID_REQUEST_PAYLOAD, NOT_FOUND_CODE}
import uk.gov.hmrc.apisubscriptionfields.model.ErrorCode
import uk.gov.hmrc.apisubscriptionfields.model.JsErrorResponse

import scala.concurrent.Future

class SubscriptionFieldDefinitionsUnhappySpec extends AcceptanceTestSpec
with OptionValues
with SubscriptionFieldsTestData {
with OptionValues
with SubscriptionFieldsTestData {

Feature("Fields-Definition") {
Scenario("the API is called to GET an unknown fields definition") {
Expand All @@ -46,7 +46,7 @@ class SubscriptionFieldDefinitionsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe NOT_FOUND

And("the response body contains error message")
contentAsJson(resultFuture) shouldBe JsErrorResponse(NOT_FOUND_CODE, s"Fields definition not found for (${FakeContext.value}, unknown)")
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.NOT_FOUND, s"Fields definition not found for (${FakeContext.value}, unknown)")
}

Scenario("the API is called to PUT a fields definition with an invalid JSON payload") {
Expand All @@ -67,7 +67,7 @@ class SubscriptionFieldDefinitionsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe UNPROCESSABLE_ENTITY

And("the response body contains error message")
contentAsJson(resultFuture) shouldBe JsErrorResponse(INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
}

Scenario("the API is called to PUT a fields definition with an invalid field definition type") {
Expand All @@ -91,7 +91,6 @@ class SubscriptionFieldDefinitionsUnhappySpec extends AcceptanceTestSpec
.withTarget(RequestTarget(uriString = "", path = definitionEndpoint(fakeRawContext, fakeRawVersion), queryString = Map.empty))
.withJsonBody(Json.parse(invalidFieldDefinition))


When("a PUT request with data is sent to the API")
val result: Option[Future[Result]] = route(app, request)

Expand All @@ -102,7 +101,7 @@ class SubscriptionFieldDefinitionsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe UNPROCESSABLE_ENTITY

And("the response body contains error message")
contentAsJson(resultFuture) shouldBe JsErrorResponse(INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
}

Scenario("the API is called to PUT a fields definition with an invalid non JSON payload") {
Expand All @@ -124,7 +123,7 @@ class SubscriptionFieldDefinitionsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe UNSUPPORTED_MEDIA_TYPE

And("the response body contains error message")
contentAsJson(resultFuture) shouldBe JsErrorResponse(INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.INVALID_REQUEST_PAYLOAD, _: Json.JsValueWrapper)
}

Scenario("the API is called to DELETE an unknown fields definition") {
Expand All @@ -135,7 +134,6 @@ class SubscriptionFieldDefinitionsUnhappySpec extends AcceptanceTestSpec
.withMethod(DELETE)
.withTarget(RequestTarget(uriString = "", path = definitionEndpoint(fakeRawContext, "unknown"), queryString = Map.empty))


When("a GET request with data is sent to the API")
val result: Option[Future[Result]] = route(app, request)

Expand All @@ -146,7 +144,7 @@ class SubscriptionFieldDefinitionsUnhappySpec extends AcceptanceTestSpec
status(resultFuture) shouldBe NOT_FOUND

And("the response body is empty")
contentAsJson(resultFuture) shouldBe JsErrorResponse(NOT_FOUND_CODE, s"Fields definition not found for ($fakeRawContext, unknown)")
contentAsJson(resultFuture) shouldBe JsErrorResponse(ErrorCode.NOT_FOUND, s"Fields definition not found for ($fakeRawContext, unknown)")
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class ApiFieldDefinitionsController @Inject() (cc: ControllerComponents, service
}

private def notFoundResponse(apiContext: ApiContext, apiVersion: ApiVersion) =
NotFound(JsErrorResponse(ErrorCode.NOT_FOUND_CODE, s"Fields definition not found for (${apiContext.value}, ${apiVersion.value})"))
NotFound(JsErrorResponse(ErrorCode.NOT_FOUND, s"Fields definition not found for (${apiContext.value}, ${apiVersion.value})"))

def validateFieldsDefinition(): Action[JsValue] = Action(parse.json) { request =>
Try(request.body.validate[FieldDefinitionsRequest]) match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class SubscriptionFieldsController @Inject() (cc: ControllerComponents, service:
import JsonFormatters._

private def notFoundResponse(message: String) = {
NotFound(JsErrorResponse(NOT_FOUND_CODE, message))
NotFound(JsErrorResponse(ErrorCode.NOT_FOUND, message))
}

private def notFoundMessage(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersion): String = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import play.api.libs.functional.syntax._
import play.api.libs.json.Json.JsValueWrapper
import play.api.libs.json._

import uk.gov.hmrc.apisubscriptionfields.model.FieldDefinitionType.FieldDefinitionType
import uk.gov.hmrc.apisubscriptionfields.model.Types._

trait NonEmptyListFormatters {
Expand Down Expand Up @@ -114,8 +113,6 @@ trait JsonFormatters extends NonEmptyListFormatters with AccessRequirementsForma

implicit val ValidationJF: OFormat[ValidationGroup] = Json.format[ValidationGroup]

implicit val FieldDefinitionTypeReads: Reads[FieldDefinitionType] = Reads.enumNameReads(FieldDefinitionType)

implicit val FieldDefinitionReads: Reads[FieldDefinition] = (
(JsPath \ "name").read[FieldName] and
(JsPath \ "description").read[String] and
Expand Down
34 changes: 27 additions & 7 deletions app/uk/gov/hmrc/apisubscriptionfields/model/Model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ package uk.gov.hmrc.apisubscriptionfields.model
import cats.data.{NonEmptyList => NEL}
import org.apache.commons.validator.routines.{DomainValidator, UrlValidator}

import uk.gov.hmrc.apisubscriptionfields.model.FieldDefinitionType.FieldDefinitionType
import play.api.libs.json.Format
import uk.gov.hmrc.apiplatform.modules.common.domain.services.SealedTraitJsonFormatting

import uk.gov.hmrc.apisubscriptionfields.model.Types._

sealed trait ValidationRule {
Expand Down Expand Up @@ -48,14 +50,32 @@ case object UrlValidationRule extends ValidationRule {

case class ValidationGroup(errorMessage: String, rules: NEL[ValidationRule])

object FieldDefinitionType extends Enumeration {
type FieldDefinitionType = Value
sealed trait FieldDefinitionType {
lazy val label = FieldDefinitionType.label(this)
}

object FieldDefinitionType {

@deprecated("We don't use URL type for any validation", since = "0.5x")
val URL = Value("URL")
val SECURE_TOKEN = Value("SecureToken")
val STRING = Value("STRING")
val PPNS_FIELD = Value("PPNSField")
case object URL extends FieldDefinitionType
case object SECURE_TOKEN extends FieldDefinitionType
case object STRING extends FieldDefinitionType
case object PPNS_FIELD extends FieldDefinitionType

val values = Set(URL, SECURE_TOKEN, STRING, PPNS_FIELD)

def apply(text: String): Option[FieldDefinitionType] = FieldDefinitionType.values.find(_.label == text)

def unsafeApply(text: String): FieldDefinitionType = apply(text).getOrElse(throw new RuntimeException(s"$text is not a valid Field Definition Type"))

def label(fdt: FieldDefinitionType): String = fdt match {
case URL => "URL"
case SECURE_TOKEN => "SecureToken"
case STRING => "STRING"
case PPNS_FIELD => "PPNSField"
}
Format
implicit val format: Format[FieldDefinitionType] = SealedTraitJsonFormatting.createFormatFor[FieldDefinitionType]("Field Definition Type", apply, label)
}

case class FieldDefinition(
Expand Down
24 changes: 17 additions & 7 deletions app/uk/gov/hmrc/apisubscriptionfields/model/Responses.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
package uk.gov.hmrc.apisubscriptionfields.model

import play.api.libs.json.Json.JsValueWrapper
import play.api.libs.json.{JsObject, Json}
import play.api.libs.json.{Format, JsObject, Json}
import uk.gov.hmrc.apiplatform.modules.common.domain.services.SealedTraitJsonFormatting

import uk.gov.hmrc.apisubscriptionfields.model.Types._

Expand All @@ -38,17 +39,26 @@ sealed trait PPNSCallBackUrlValidationResponse
case object PPNSCallBackUrlSuccessResponse extends PPNSCallBackUrlValidationResponse
case class PPNSCallBackUrlFailedResponse(errorMsg: String) extends PPNSCallBackUrlValidationResponse

object ErrorCode extends Enumeration {
type ErrorCode = Value
sealed trait ErrorCode

val INVALID_REQUEST_PAYLOAD = Value("INVALID_REQUEST_PAYLOAD")
val UNKNOWN_ERROR = Value("UNKNOWN_ERROR")
val NOT_FOUND_CODE = Value("NOT_FOUND")
object ErrorCode {

case object INVALID_REQUEST_PAYLOAD extends ErrorCode
case object UNKNOWN_ERROR extends ErrorCode
case object NOT_FOUND extends ErrorCode

val values = Set(INVALID_REQUEST_PAYLOAD, UNKNOWN_ERROR, NOT_FOUND)

def apply(text: String): Option[ErrorCode] = ErrorCode.values.find(_.toString() == text.toUpperCase)

def unsafeApply(text: String): ErrorCode = apply(text).getOrElse(throw new RuntimeException(s"$text is not a valid Error Code"))

implicit val format: Format[ErrorCode] = SealedTraitJsonFormatting.createFormatFor[ErrorCode]("Error Code", apply)
}

object JsErrorResponse {

def apply(errorCode: ErrorCode.Value, message: JsValueWrapper): JsObject =
def apply(errorCode: ErrorCode, message: JsValueWrapper): JsObject =
Json.obj(
"code" -> errorCode.toString,
"message" -> message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ import scala.concurrent.{ExecutionContext, Future}

import akka.stream.Materializer
import com.google.inject.ImplementedBy
import org.bson.codecs.configuration.CodecRegistries.{fromCodecs, fromRegistries}
import org.mongodb.scala.model.Filters.{and, equal}
import org.mongodb.scala.model.Indexes.ascending
import org.mongodb.scala.model.{Filters, IndexModel, IndexOptions}
import org.mongodb.scala.{MongoClient, MongoCollection}

import uk.gov.hmrc.mongo.MongoComponent
import uk.gov.hmrc.mongo.play.json.{Codecs, CollectionFactory, PlayMongoRepository}
import uk.gov.hmrc.mongo.play.json.{Codecs, PlayMongoRepository}

import uk.gov.hmrc.apisubscriptionfields.model.Types._
import uk.gov.hmrc.apisubscriptionfields.model._
Expand All @@ -52,6 +50,12 @@ class ApiFieldDefinitionsMongoRepository @Inject() (mongo: MongoComponent)(impli
collectionName = "fieldsDefinitions",
mongoComponent = mongo,
domainFormat = JsonFormatters.ApiFieldDefinitionsJF,
extraCodecs = Seq(
Codecs.playFormatCodec(JsonFormatters.ApiContextJF),
Codecs.playFormatCodec(JsonFormatters.ApiVersionJF),
Codecs.playFormatCodec(JsonFormatters.ApiFieldDefinitionsJF),
Codecs.playFormatCodec(JsonFormatters.ValidationJF)
),
indexes = Seq(
IndexModel(
ascending(List("apiContext", "apiVersion"): _*),
Expand All @@ -65,22 +69,6 @@ class ApiFieldDefinitionsMongoRepository @Inject() (mongo: MongoComponent)(impli
with ApiFieldDefinitionsRepository
with ApplicationLogger {

override lazy val collection: MongoCollection[ApiFieldDefinitions] =
CollectionFactory
.collection(mongo.database, collectionName, domainFormat)
.withCodecRegistry(
fromRegistries(
fromCodecs(
Codecs.playFormatCodec(domainFormat),
Codecs.playFormatCodec(JsonFormatters.ApiContextJF),
Codecs.playFormatCodec(JsonFormatters.ApiVersionJF),
Codecs.playFormatCodec(JsonFormatters.ApiFieldDefinitionsJF),
Codecs.playFormatCodec(JsonFormatters.ValidationJF)
),
MongoClient.DEFAULT_CODEC_REGISTRY
)
)

def save(definitions: ApiFieldDefinitions): Future[(ApiFieldDefinitions, IsInsert)] = {
val query = and(equal("apiContext", Codecs.toBson(definitions.apiContext.value)), equal("apiVersion", Codecs.toBson(definitions.apiVersion.value)))

Expand Down
Loading

0 comments on commit 7cd8e60

Please sign in to comment.