Skip to content

Commit

Permalink
Split the DTOs and the address client
Browse files Browse the repository at this point in the history
  • Loading branch information
ollyw committed Dec 30, 2016
1 parent e2bdd42 commit f08b6fe
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 81 deletions.
71 changes: 71 additions & 0 deletions app/connectors/addresslookup/AddressLookupClient.scala
Original file line number Diff line number Diff line change
@@ -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")
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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. */
Expand All @@ -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) {
Expand All @@ -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")
}

0 comments on commit f08b6fe

Please sign in to comment.