diff --git a/app/connectors/addresslookup/AddressLookupClient.scala b/app/connectors/addresslookup/AddressLookupClient.scala new file mode 100644 index 0000000..83e29de --- /dev/null +++ b/app/connectors/addresslookup/AddressLookupClient.scala @@ -0,0 +1,71 @@ +/* + * Copyright 2016 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 connectors.addresslookup + +import java.net.URLEncoder + +import config.CSRHttp +import uk.gov.hmrc.play.http.{ HeaderCarrier, _ } + +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.Future + +/** + * The following client has been take from taken from https://github.com/hmrc/address-reputation-store. The project has + * not been added as a dependency, as it brings in many transitive dependencies that are not needed, + * as well as data cleansing/ingestion and backward compatibility logic that is not needed for this project. + * If the version 2 api gets deprecated, then these DTOs will have to change. + * There have been some minor changes made to the code to ensure that it compiles and passes scalastyle, + * but there is some copied code that is not idiomatic Scala and should be changed at some point in the future + */ + +trait AddressLookupClient { + + def addressLookupEndpoint: String + val http: CSRHttp + + private def url = s"$addressLookupEndpoint/v2/uk/addresses" + + def findById(id: String)(implicit hc: HeaderCarrier): Future[Option[AddressRecord]] = { + assert(id.length <= 100, "Postcodes cannot be larger than 100 characters") + val uq = "/" + enc(id) + http.GET[Option[AddressRecord]](url + uq).recover { + case _: NotFoundException => None + } + } + + def findByUprn(uprn: Long)(implicit hc: HeaderCarrier): Future[List[AddressRecord]] = { + val uq = "?uprn=" + uprn.toString + http.GET[List[AddressRecord]](url + uq) + } + + def findByPostcode(postcode: String, filter: Option[String])(implicit hc: HeaderCarrier): Future[List[AddressRecord]] = { + val safePostcode = postcode.replaceAll("[^A-Za-z0-9]", "") + assert(safePostcode.length <= 10, "Postcodes cannot be larger than 10 characters") + val pq = "?postcode=" + enc(safePostcode) + val fq = filter.map(fi => "&filter=" + enc(fi)).getOrElse("") + http.GET[List[AddressRecord]](url + pq + fq) + } + + def findByOutcode(outcode: Outcode, filter: String)(implicit hc: HeaderCarrier): Future[List[AddressRecord]] = { + val pq = "?outcode=" + outcode.toString + val fq = "&filter=" + enc(filter) + http.GET[List[AddressRecord]](url + pq + fq) + } + + private def enc(s: String) = URLEncoder.encode(s, "UTF-8") +} diff --git a/app/connectors/AddressLookup.scala b/app/connectors/addresslookup/AddressRecord.scala similarity index 63% rename from app/connectors/AddressLookup.scala rename to app/connectors/addresslookup/AddressRecord.scala index 152fc08..755ef3c 100644 --- a/app/connectors/AddressLookup.scala +++ b/app/connectors/addresslookup/AddressRecord.scala @@ -16,17 +16,8 @@ package connectors.addresslookup -import java.net.URLEncoder - -import config.CSRHttp import play.api.libs.json.Json -import uk.gov.hmrc.play.http.HeaderCarrier -import uk.gov.hmrc.play.http._ - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.Future -import java.util.regex.Pattern /** * The following DTOs are taken from https://github.com/hmrc/address-reputation-store. The project has @@ -100,8 +91,6 @@ case class Address(lines: List[String], subdivision: Option[Country], country: Country) { - import Address._ - def nonEmptyFields: List[String] = lines ::: town.toList ::: county.toList ::: List(postcode) /** Gets a conjoined representation, excluding the country. */ @@ -110,40 +99,17 @@ case class Address(lines: List[String], /** Gets a single-line representation, excluding the country. */ def printable: String = printable(", ") - def line1: String = if (lines.nonEmpty) lines.head else "" - - def line2: String = if (lines.size > 1) lines(1) else "" - - def line3: String = if (lines.size > 2) lines(2) else "" + def line1: String = lines.lift(0).getOrElse("") - def line4: String = if (lines.size > 3) lines(3) else "" + def line2: String = lines.lift(1).getOrElse("") - def longestLineLength: Int = nonEmptyFields.map(_.length).max - - def truncatedAddress(maxLen: Int = maxLineLength): Address = - Address(lines.map(limit(_, maxLen)), town.map(limit(_, maxLen)), county.map(limit(_, maxLen)), postcode, subdivision, country) + def line3: String = lines.lift(2).getOrElse("") + def line4: String = lines.lift(3).getOrElse("") } object Address { - val maxLineLength = 35 - val danglingLetter: Pattern = Pattern.compile(".* [A-Z0-9]$") implicit val addressFormat = Json.reads[Address] - - private[addresslookup] def limit(str: String, max: Int): String = { - var s = str - while (s.length > max && s.indexOf(", ") > 0) { - s = s.replaceFirst(", ", ",") - } - if (s.length > max) { - s = s.substring(0, max).trim - if (Address.danglingLetter.matcher(s).matches()) { - s = s.substring(0, s.length - 2) - } - s - } - else { s } - } } case class LatLong(lat: Double, long: Double) { @@ -162,53 +128,13 @@ case class AddressRecord( logicalState: Option[String], streetClassification: Option[String]) { - import Address._ - def truncatedAddress(maxLen: Int = Address.maxLineLength): AddressRecord = - if (address.longestLineLength <= maxLen) { this } - else { copy(address = address.truncatedAddress(maxLen)) } - def withoutMetadata: AddressRecord = copy(blpuState = None, logicalState = None, streetClassification = None) - def geoLocation: LatLong = ??? + // TODO put in the real lat/lng once the address lookup service supports it + // Hardcoded to Coventry for the time being + val geoLocation: LatLong = LatLong(52.40656, -1.51217) } object AddressRecord { implicit val addressRecordFormat = Json.reads[AddressRecord] } - -trait AddressLookupClient{ - - def addressLookupEndpoint: String - val http: CSRHttp - - private def url = s"$addressLookupEndpoint/v2/uk/addresses" - - def findById(id: String)(implicit hc: HeaderCarrier): Future[Option[AddressRecord]] = { - assert(id.length <= 100, "Postcodes cannot be larger than 100 characters") - val uq = "/" + enc(id) - http.GET[Option[AddressRecord]](url + uq).recover { - case _: NotFoundException => None - } - } - - def findByUprn(uprn: Long)(implicit hc: HeaderCarrier): Future[List[AddressRecord]] = { - val uq = "?uprn=" + uprn.toString - http.GET[List[AddressRecord]](url + uq) - } - - def findByPostcode(postcode: String, filter: Option[String])(implicit hc: HeaderCarrier): Future[List[AddressRecord]] = { - val safePostcode = postcode.replaceAll("[^A-Za-z0-9]", "") - assert(safePostcode.length <= 10, "Postcodes cannot be larger than 10 characters") - val pq = "?postcode=" + enc(safePostcode) - val fq = filter.map(fi => "&filter=" + enc(fi)).getOrElse("") - http.GET[List[AddressRecord]](url + pq + fq) - } - - def findByOutcode(outcode: Outcode, filter: String)(implicit hc: HeaderCarrier): Future[List[AddressRecord]] = { - val pq = "?outcode=" + outcode.toString - val fq = "&filter=" + enc(filter) - http.GET[List[AddressRecord]](url + pq + fq) - } - - private def enc(s: String) = URLEncoder.encode(s, "UTF-8") -}