Skip to content

Commit

Permalink
NOJIRA: Cleanup AddressSearchController to split the code in to more …
Browse files Browse the repository at this point in the history
…logical units.

WIP
  • Loading branch information
ssaleem-ee committed May 7, 2024
1 parent 4f4a5ed commit f1ea220
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 272 deletions.
32 changes: 16 additions & 16 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@

logs
project/project
**/.bloop/
**/.metals/
**/.vscode/
**/target/
lib_managed
tmp
.history
dist
/.idea
/.bsp/
/.idea/
logs/
project/project/
/*.iml
/*.ipr
/out
/.idea_modules
/.classpath
/.idea_modules
/.project
/RUNNING_PID
/.settings
*.iws
/.bsp
/null
**/.bloop/
**/.metals/
**/.vscode/
/out
/RUNNING_PID
*.iws
.history
dist
lib_managed
tmp
/project/metals.sbt
47 changes: 0 additions & 47 deletions app/controllers/AddressController.scala

This file was deleted.

170 changes: 12 additions & 158 deletions app/controllers/AddressSearchController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,25 @@ package controllers

import access.AccessChecker
import config.ConfigHelper
import model._
import model.address.{AddressRecord, Postcode}
import model.internal.NonUKAddress
import model.request.{LookupByCountryRequest, LookupByPostTownRequest, LookupByPostcodeRequest, LookupByUprnRequest}
import model.response.{ErrorResponse, SupportedCountryCodes}
import play.api.Logging
import play.api.libs.json.{JsError, JsSuccess, Json}
import play.api.mvc._
import repositories.{ABPAddressRepository, NonABPAddressRepository}
import services.{CheckAddressDataScheduler, ResponseProcessor}
import services.{AddressSearchService, CheckAddressDataScheduler}
import uk.gov.hmrc.http.HeaderCarrier
import uk.gov.hmrc.play.audit.http.connector.AuditConnector
import uk.gov.hmrc.play.http.HeaderCarrierConverter

import javax.inject.Inject
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success, Try}

class AddressSearchController @Inject()(addressSearch: ABPAddressRepository, nonABPAddressSearcher: NonABPAddressRepository,
responseProcessor: ResponseProcessor, auditConnector: AuditConnector,
cc: ControllerComponents, supportedCountryCodes: SupportedCountryCodes,
scheduler: CheckAddressDataScheduler, val configHelper: ConfigHelper)(
implicit ec: ExecutionContext)
extends AddressController(cc) with AccessChecker {
class AddressSearchController @Inject()(addressSearchService: AddressSearchService,
val controllerComponents: ControllerComponents,
supportedCountryCodes: SupportedCountryCodes,
scheduler: CheckAddressDataScheduler,
val configHelper: ConfigHelper)(ec: ExecutionContext)
extends BaseController with AccessChecker with Logging {
import ErrorResponse.Implicits._

scheduler.enable()
Expand All @@ -52,7 +48,7 @@ class AddressSearchController @Inject()(addressSearch: ABPAddressRepository, non
case Success(json) =>
json.validate[LookupByPostcodeRequest](LookupByPostcodeRequest.reads) match {
case JsSuccess(lookupByPostcodeRequest, _) =>
searchByPostcode(request, lookupByPostcodeRequest.postcode, lookupByPostcodeRequest.filter)
addressSearchService.searchByPostcode(request, lookupByPostcodeRequest.postcode, lookupByPostcodeRequest.filter)
case JsError(errors) =>
Future.successful(BadRequest(JsError.toJson(errors)))
}
Expand All @@ -66,7 +62,7 @@ class AddressSearchController @Inject()(addressSearch: ABPAddressRepository, non
maybeJson match {
case Success(json) => json.validate[LookupByUprnRequest] match {
case JsSuccess(lookupByUprnRequest, _) =>
searchByUprn(request, lookupByUprnRequest.uprn)
addressSearchService.searchByUprn(request, lookupByUprnRequest.uprn)
case JsError(errors) =>
Future.successful(BadRequest(JsError.toJson(errors)))
}
Expand All @@ -80,7 +76,7 @@ class AddressSearchController @Inject()(addressSearch: ABPAddressRepository, non
maybeJson match {
case Success(json) => json.validate[LookupByPostTownRequest] match {
case JsSuccess(lookupByTownRequest, _) =>
searchByTown(request, lookupByTownRequest.posttown, lookupByTownRequest.filter)
addressSearchService.searchByTown(request, lookupByTownRequest.posttown, lookupByTownRequest.filter)
case JsError(errors) =>
Future.successful(BadRequest(JsError.toJson(errors)))
}
Expand All @@ -102,153 +98,11 @@ class AddressSearchController @Inject()(addressSearch: ABPAddressRepository, non
case Success(json) => json.validate[LookupByCountryRequest] match {
case JsSuccess(lookupByCountryRequest, _) =>
val userAgent = request.headers.get("User-Agent")
searchByCountry(userAgent, countryCode.toLowerCase(), lookupByCountryRequest.filter)
addressSearchService.searchByCountry(userAgent, countryCode.toLowerCase(), lookupByCountryRequest.filter)
case JsError(errors) =>
Future.successful(BadRequest(JsError.toJson(errors)))
}
case Failure(_) => Future.successful(BadRequest(Json.toJson(ErrorResponse.invalidJson)))
}
}

private[controllers] def searchByUprn[A](request: Request[A], uprn: String): Future[Result] = {
if (Try(uprn.toLong).isFailure) {
Future.successful {
badRequest("BAD-UPRN", "uprn" -> uprn, "error" -> s"uprn must only consist of digits")
}
} else {
import model.address.AddressRecord.formats._

addressSearch.findUprn(uprn).map {
a =>
val a2 = responseProcessor.convertAddressList(a)
logEvent("LOOKUP", "uprn" -> uprn, "matches" -> a2.size.toString)
Ok(Json.toJson(a2))
}
}
}

private[controllers] def searchByPostcode[A](request: Request[A], postcode: Postcode, filter: Option[String]): Future[Result] = {
implicit val hc: HeaderCarrier = HeaderCarrierConverter.fromRequest(request)

if (postcode.toString.isEmpty) {
Future.successful {
badRequest("BAD-POSTCODE", "error" -> s"missing or badly-formed $postcode parameter")
}
} else {
import model.address.AddressRecord.formats._
addressSearch.findPostcode(postcode, filter).map {
a =>
val userAgent = request.headers.get("User-Agent")
val a2 = responseProcessor.convertAddressList(a)

if (a2.nonEmpty) {
auditAddressSearch(userAgent, a2, postcode = Some(postcode), filter = filter)
}

logEvent("LOOKUP", a2.size, List(Some("postcode" -> postcode.toString), filter.map(f => "filter" -> f)).flatten)
Ok(Json.toJson(a2))
}
}
}

private[controllers] def searchByTown[A](request: Request[A], posttown: String, filter: Option[String]): Future[Result] = {
implicit val hc: HeaderCarrier = HeaderCarrierConverter.fromRequest(request)

if (posttown.isEmpty) {
Future.successful {
badRequest("BAD-POSTTOWN", "error" -> s"missing or badly-formed $posttown parameter")
}
} else {
import model.address.AddressRecord.formats._
val casedPosttown = posttown.toUpperCase

addressSearch.findTown(casedPosttown, filter).map {
a =>
val userAgent = request.headers.get("User-Agent")
val a2 = responseProcessor.convertAddressList(a)

if (a2.nonEmpty) {
auditAddressSearch(userAgent, a2, postTown = Some(casedPosttown), filter = filter)
}

logEvent("LOOKUP", a2.size, List(Some("posttown" -> posttown), filter.map(f => "filter" -> f)).flatten)
Ok(Json.toJson(a2))
}
}
}

private[controllers] def searchByCountry[A](userAgent: Option[String], countryCode: String, filter: String)(implicit hc: HeaderCarrier): Future[Result] = {

if (countryCode.isEmpty || "[a-zA-Z]{2}".r.unapplySeq(countryCode).isEmpty) {
Future.successful {
badRequest("BAD-COUNTRYCODE", "error" -> s"missing or badly-formed country code")
}
} else if (supportedCountryCodes.abp.contains(countryCode)) {
Future.successful {
badRequest("ABP-COUNTRYCODE", "error" -> s"country code is abp.")
}
} else if (!supportedCountryCodes.nonAbp.contains(countryCode)) {
Future.successful {
notFound("UNSUPPORTED-COUNTRYCODE", "error" -> s"country code unsupported")
}
} else {
import model.internal.NonUKAddress._

nonABPAddressSearcher.findInCountry(countryCode, filter).map {
a =>
auditNonUKAddressSearch(userAgent, a, countryCode, Option(filter))
logEvent("LOOKUP", a.size, List("countryCode" -> countryCode, "filter" -> filter))
Ok(Json.toJson(a))
}.recover {
case e: Throwable => logEvent("LOOKUP-NONUK-ERROR", "errorMessage" -> e.getMessage)
ExpectationFailed
}
}
}

private def auditAddressSearch[A](userAgent: Option[String], a2: List[AddressRecord], postcode: Option[Postcode] = None,
postTown: Option[String] = None, filter: Option[String] = None)(implicit hc: HeaderCarrier): Unit = {

auditConnector.sendExplicitAudit("AddressSearch",
AddressSearchAuditEvent(userAgent,
AddressSearchAuditEventRequestDetails(postcode.map(_.toString), postTown, filter),
a2.length,
a2.map { ma =>
AddressSearchAuditEventMatchedAddress(
ma.uprn.map(_.toString).getOrElse("").toString,
ma.parentUprn,
ma.usrn,
ma.organisation,
ma.address.lines,
ma.address.town,
ma.localCustodian,
ma.location,
ma.administrativeArea,
ma.poBox,
ma.address.postcode,
ma.address.subdivision,
ma.address.country)
}))
}

private def auditNonUKAddressSearch[A](userAgent: Option[String], a2: List[NonUKAddress], country: String,
filter: Option[String] = None)(implicit hc: HeaderCarrier): Unit = {

auditConnector.sendExplicitAudit("NonUKAddressSearch",
NonUKAddressSearchAuditEvent(userAgent,
NonUKAddressSearchAuditEventRequestDetails(filter),
a2.length,
a2.map { ma =>
NonUKAddressSearchAuditEventMatchedAddress(
ma.id,
ma.number,
ma.street,
ma.unit,
ma.city,
ma.district,
ma.region,
ma.postcode,
country)
}))
}
}
Loading

0 comments on commit f1ea220

Please sign in to comment.