play.api.mvc.PathBindable Scala Examples

The following examples show how to use play.api.mvc.PathBindable. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: Binders.scala    From vat-api   with Apache License 2.0 5 votes vote down vote up
package uk.gov.hmrc.vatapi.resources

import org.joda.time.LocalDate
import org.joda.time.format.DateTimeFormat
import play.api.mvc.{PathBindable, QueryStringBindable}
import uk.gov.hmrc.domain.Vrn
import uk.gov.hmrc.vatapi.models.{FinancialDataQueryParams, ObligationsQueryParams, OptEither}

import scala.util.{Failure, Success, Try}

object Binders {

  implicit def vrnBinder(implicit stringBinder: PathBindable[String]) = new PathBindable[Vrn] {
    val vrnRegex = """^\d{9}$"""

    def unbind(key: String, vrn: Vrn): String = stringBinder.unbind(key, vrn.value)

    def bind(key: String, value: String): Either[String, Vrn] = {
      if (value.matches(vrnRegex)) {
        Right(Vrn(value))
      } else {
        Left("ERROR_VRN_INVALID")
      }
    }
  }

  implicit def obligationsQueryParamsBinder(implicit stringBinder: QueryStringBindable[String]) = new QueryStringBindable[ObligationsQueryParams] {

    override def bind(key: String, params: Map[String, Seq[String]]): OptEither[ObligationsQueryParams] = {
      val from = stringBinder.bind("from", params)
      val to = stringBinder.bind("to", params)
      val status = stringBinder.bind("status", params)

      val query = ObligationsQueryParams.from(from, to, status)
      if (query.isRight)
        Some(Right(query.right.get))
      else
        Some(Left(query.left.get))
    }

    override def unbind(key: String, value: ObligationsQueryParams): String = stringBinder.unbind(key, value.map(key).toString)

  }

  implicit def financialDataQueryParamsBinder(implicit stringBinder: QueryStringBindable[String]) = new QueryStringBindable[FinancialDataQueryParams] {
    override def bind(key: String, params: Map[String, Seq[String]]): OptEither[FinancialDataQueryParams] = {
      val from = stringBinder.bind("from", params)
      val to = stringBinder.bind("to", params)

      val query = FinancialDataQueryParams.from(from, to)
      if (query.isRight)
        Some(Right(query.right.get))
      else
        Some(Left(query.left.get))
    }

    override def unbind(key: String, value: FinancialDataQueryParams): String = stringBinder.unbind(key, value.map(key).toString)
  }

  val format: String = "yyy-MM-dd"

  implicit val dateQueryParamsBinder = new QueryStringBindable[LocalDate] {

    override def unbind(key: String, date: LocalDate): String = date.toString

    override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, LocalDate]] =
      for {
        dates <- params.get(key)
      } yield
        Try {
          DateTimeFormat.forPattern(format).parseLocalDate(dates(0))
        } match {
          case Success(v) => Right(v)
          case Failure(_) => Left("ERROR_INVALID_DATE")
        }

  }
} 
Example 2
Source File: SimpleObjectBinder.scala    From play-ui   with Apache License 2.0 5 votes vote down vote up
package uk.gov.hmrc.play.binders

import play.api.mvc.PathBindable

class SimpleObjectBinder[T](bind: String => T, unbind: T => String)(implicit m: Manifest[T]) extends PathBindable[T] {
  override def bind(key: String, value: String): Either[String, T] =
    try {
      Right(bind(value))
    } catch {
      case e: Throwable =>
        Left(s"Cannot parse parameter '$key' with value '$value' as '${m.runtimeClass.getSimpleName}'")
    }

  def unbind(key: String, value: T): String = unbind(value)
} 
Example 3
Source File: PathBinders.scala    From cluster-broccoli   with Apache License 2.0 5 votes vote down vote up
package de.frosner.broccoli.routes

import cats.syntax.either._
import de.frosner.broccoli.nomad.models.LogStreamKind
import play.api.mvc.PathBindable
import squants.information.Information


  implicit def informationPathBindable(implicit stringBinder: PathBindable[String]): PathBindable[Information] =
    new PathBindable[Information] {
      override def bind(key: String, value: String): Either[String, Information] =
        for {
          boundValue <- stringBinder.bind(key, value)
          information <- Either
            .fromTry(Information(boundValue))
            .leftMap(_.getMessage)
        } yield information

      override def unbind(key: String, value: Information): String = stringBinder.unbind(key, value.toString)
    }
}

object PathBinders extends PathBinders 
Example 4
Source File: Binders.scala    From metronome   with Apache License 2.0 5 votes vote down vote up
package dcos.metronome
package api

import dcos.metronome.jobinfo.JobInfo.Embed
import dcos.metronome.model.JobId
import play.api.mvc.{QueryStringBindable, PathBindable}
import mesosphere.marathon.api.v2.Validation.validateOrThrow

import scala.util.control.NonFatal

object Binders {

  //Define types here to use them in routes file without full classified name
  type JobId = dcos.metronome.model.JobId
  type Embed = dcos.metronome.jobinfo.JobInfo.Embed

  
  implicit val pathQueryBinder: QueryStringBindable[JobId] = new QueryStringBindable[JobId] {
    override def bind(key: String, params: Map[String, scala.collection.Seq[String]]): Option[Either[String, JobId]] = {
      val jobId = params.get(key).flatMap(_.headOption)
      try {
        jobId.map(value => Right(validateOrThrow(JobId(value))))
      } catch {
        case NonFatal(_) => Some(Left(s"Not a valid id: $jobId"))
      }
    }
    override def unbind(key: String, value: JobId): String = value.toString
  }

  implicit val embedQueryBinder: QueryStringBindable[Set[Embed]] = new QueryStringBindable[Set[Embed]] {
    override def bind(
        key: String,
        params: Map[String, scala.collection.Seq[String]]
    ): Option[Either[String, Set[Embed]]] = {
      val embeds = params.getOrElse(key, Seq.empty).flatMap(_.split(","))
      val valid = embeds.flatMap(Embed.names.get)
      if (valid.size != embeds.size)
        Some(Left(s"Unknown embed options. Valid options are: ${Embed.names.keys.mkString(", ")}"))
      else Some(Right(valid.toSet))
    }
    override def unbind(key: String, value: Set[Embed]): String = value.map(_.toString).mkString(",")
  }
} 
Example 5
Source File: uber_api_yaml.scala    From api-first-hand   with MIT License 5 votes vote down vote up
package uber.api


    import java.util.UUID
    import scala.math.BigDecimal

    import de.zalando.play.controllers.PlayPathBindables


//noinspection ScalaStyle
package yaml {


    case class Activity(uuid: ProfilePicture) 
    case class PriceEstimate(low_estimate: PriceEstimateHigh_estimate, display_name: ProfilePicture, estimate: ProfilePicture, high_estimate: PriceEstimateHigh_estimate, product_id: ProfilePicture, currency_code: ProfilePicture, surge_multiplier: PriceEstimateHigh_estimate) 
    case class Product(image: ProfilePicture, description: ProfilePicture, display_name: ProfilePicture, product_id: ProfilePicture, capacity: ProfilePicture) 
    case class Profile(first_name: ProfilePicture, email: ProfilePicture, promo_code: ProfilePicture, last_name: ProfilePicture, picture: ProfilePicture) 
    case class Activities(offset: ErrorCode, limit: ErrorCode, count: ErrorCode, history: ActivitiesHistory) 
    case class Error(code: ErrorCode, message: ProfilePicture, fields: ProfilePicture) 


    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    import de.zalando.play.controllers.MissingDefaultWrites
    object ResponseWrites extends MissingDefaultWrites {
    implicit val ActivityWrites: Writes[Activity] = new Writes[Activity] {
        def writes(ss: Activity) =
          Json.obj(
            "uuid" -> ss.uuid
          )
        }
    implicit val ActivitiesWrites: Writes[Activities] = new Writes[Activities] {
        def writes(ss: Activities) =
          Json.obj(
            "offset" -> ss.offset, 
            "limit" -> ss.limit, 
            "count" -> ss.count, 
            "history" -> ss.history
          )
        }
    implicit val PriceEstimateWrites: Writes[PriceEstimate] = new Writes[PriceEstimate] {
        def writes(ss: PriceEstimate) =
          Json.obj(
            "low_estimate" -> ss.low_estimate, 
            "display_name" -> ss.display_name, 
            "estimate" -> ss.estimate, 
            "high_estimate" -> ss.high_estimate, 
            "product_id" -> ss.product_id, 
            "currency_code" -> ss.currency_code, 
            "surge_multiplier" -> ss.surge_multiplier
          )
        }
    implicit val ProductWrites: Writes[Product] = new Writes[Product] {
        def writes(ss: Product) =
          Json.obj(
            "image" -> ss.image, 
            "description" -> ss.description, 
            "display_name" -> ss.display_name, 
            "product_id" -> ss.product_id, 
            "capacity" -> ss.capacity
          )
        }
    implicit val ProfileWrites: Writes[Profile] = new Writes[Profile] {
        def writes(ss: Profile) =
          Json.obj(
            "first_name" -> ss.first_name, 
            "email" -> ss.email, 
            "promo_code" -> ss.promo_code, 
            "last_name" -> ss.last_name, 
            "picture" -> ss.picture
          )
        }
    }
}

// should be defined after the package because of the https://issues.scala-lang.org/browse/SI-9922

//noinspection ScalaStyle
package object yaml {

    type ActivitiesHistory = Option[ActivitiesHistoryOpt]
    type ProfilePicture = Option[String]
    type ErrorCode = Option[Int]
    type EstimatesTimeGetCustomer_uuid = Option[UUID]
    type ProductsGetResponses200 = Seq[Product]
    type PriceEstimateHigh_estimate = Option[BigDecimal]
    type EstimatesPriceGetResponses200 = Seq[PriceEstimate]
    type ActivitiesHistoryOpt = Seq[Activity]


import play.api.mvc.{QueryStringBindable, PathBindable}

    implicit val bindable_UUIDQuery = PlayPathBindables.queryBindableUUID
    implicit val bindable_OptionIntQuery: QueryStringBindable[Option[Int]] = PlayPathBindables.createOptionQueryBindable[Int]
    implicit val bindable_OptionStringQuery: QueryStringBindable[Option[String]] = PlayPathBindables.createOptionQueryBindable[String]
    implicit val bindable_OptionUUIDQuery: QueryStringBindable[Option[UUID]] = PlayPathBindables.createOptionQueryBindable[UUID]

} 
Example 6
Source File: expanded_polymorphism_yaml.scala    From api-first-hand   with MIT License 5 votes vote down vote up
import de.zalando.play.controllers.ArrayWrapper

    import de.zalando.play.controllers.PlayPathBindables


//noinspection ScalaStyle
package expanded {


    case class NewPet(name: String, tag: NewPetTag) 
    case class Pet(name: String, tag: NewPetTag, id: Long) 
    case class Error(code: Int, message: String) 


    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    import de.zalando.play.controllers.MissingDefaultReads
    object BodyReads extends MissingDefaultReads {
        implicit val NewPetReads: Reads[NewPet] = (
            (JsPath \ "name").read[String] and (JsPath \ "tag").readNullable[String]
        )(NewPet.apply _)
    }

    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    import de.zalando.play.controllers.MissingDefaultWrites
    object ResponseWrites extends MissingDefaultWrites {
    implicit val PetWrites: Writes[Pet] = new Writes[Pet] {
        def writes(ss: Pet) =
          Json.obj(
            "name" -> ss.name, 
            "tag" -> ss.tag, 
            "id" -> ss.id
          )
        }
    implicit val NewPetWrites: Writes[NewPet] = new Writes[NewPet] {
        def writes(ss: NewPet) =
          Json.obj(
            "name" -> ss.name, 
            "tag" -> ss.tag
          )
        }
    }
}

// should be defined after the package because of the https://issues.scala-lang.org/browse/SI-9922

//noinspection ScalaStyle
package object expanded {

    type PetsIdDeleteResponses204 = Null
    type PetsGetLimit = Option[Int]
    type PetsGetTagsOpt = ArrayWrapper[String]
    type NewPetTag = Option[String]
    type PetsGetResponses200 = Seq[Pet]
    type PetsGetTags = Option[PetsGetTagsOpt]


import play.api.mvc.{QueryStringBindable, PathBindable}

    implicit val bindable_OptionIntQuery: QueryStringBindable[Option[Int]] = PlayPathBindables.createOptionQueryBindable[Int]
    implicit val bindable_ArrayWrapperStringQuery: QueryStringBindable[ArrayWrapper[String]] = PlayPathBindables.createArrayWrapperQueryBindable[String]("csv")
    implicit val bindable_OptionPetsGetTagsOptQuery: QueryStringBindable[Option[PetsGetTagsOpt]] = PlayPathBindables.createOptionQueryBindable[PetsGetTagsOpt]

} 
Example 7
Source File: wrong_field_name_yaml.scala    From api-first-hand   with MIT License 5 votes vote down vote up
package wrong_field_name



    import de.zalando.play.controllers.PlayPathBindables


//noinspection ScalaStyle
package yaml {


    case class StatusAndCode(message: String, Status: Status) 

    case class GetCodes(override val value: String) extends AnyVal with de.zalando.play.controllers.StringAnyVal
    case class GetOptCodesOpt(override val value: String) extends AnyVal with de.zalando.play.controllers.StringAnyVal
    case class Status(override val value: String) extends AnyVal with de.zalando.play.controllers.StringAnyVal

    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    import de.zalando.play.controllers.MissingDefaultWrites
    object ResponseWrites extends MissingDefaultWrites {
    implicit val StatusAndCodeWrites: Writes[StatusAndCode] = new Writes[StatusAndCode] {
        def writes(ss: StatusAndCode) =
          Json.obj(
            "message" -> ss.message, 
            "Status" -> ss.Status
          )
        }
    }
}

// should be defined after the package because of the https://issues.scala-lang.org/browse/SI-9922

//noinspection ScalaStyle
package object yaml {

    type GetOptCodes = Option[GetOptCodesOpt]

    object GetCodes {
        
        val Get = new GetCodes("Get")
        val GET = new GetCodes("GET")
        val Get = new GetCodes("get")

        implicit def stringToGetCodes: String => GetCodes = {
            case "Get" => Get
            case "GET" => GET
            case "get" => Get
            case other =>
                throw new IllegalArgumentException("Couldn't parse parameter " + other)
        }
    }
    object GetOptCodesOpt {
        
        val Put = new GetOptCodesOpt("put")
        val PUT = new GetOptCodesOpt("PUT")
        val Put = new GetOptCodesOpt("Put")

        implicit def stringToGetOptCodesOpt: String => GetOptCodesOpt = {
            case "put" => Put
            case "PUT" => PUT
            case "Put" => Put
            case other =>
                throw new IllegalArgumentException("Couldn't parse parameter " + other)
        }
    }
    object Status {
        
        val OK = new Status("OK")
        val WARNING = new Status("WARNING")
        val ERROR = new Status("ERROR")

        implicit def stringToStatus: String => Status = {
            case "OK" => OK
            case "WARNING" => WARNING
            case "ERROR" => ERROR
            case other =>
                throw new IllegalArgumentException("Couldn't parse parameter " + other)
        }
    }

import play.api.mvc.{QueryStringBindable, PathBindable}

    implicit val bindable_QueryGetOptCodesOpt: QueryStringBindable[GetOptCodesOpt] = new PlayPathBindables.createEnumQueryBindable(GetOptCodesOpt.stringToGetOptCodesOpt)
    implicit val bindable_OptionGetOptCodesOptQuery: QueryStringBindable[Option[GetOptCodesOpt]] = PlayPathBindables.createOptionQueryBindable[GetOptCodesOpt]
    implicit val bindable_QueryGetCodes: QueryStringBindable[GetCodes] = new PlayPathBindables.createEnumQueryBindable(GetCodes.stringToGetCodes)

} 
Example 8
Source File: simple_petstore_api_yaml.scala    From api-first-hand   with MIT License 5 votes vote down vote up
import de.zalando.play.controllers.ArrayWrapper

    import de.zalando.play.controllers.PlayPathBindables


//noinspection ScalaStyle
package simple_petstore_api_yaml {


    case class ErrorModel(code: Int, message: String) 
    case class Pet(id: Long, name: String, tag: NewPetTag) 
    case class NewPet(name: String, id: NewPetId, tag: NewPetTag) 


    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    import de.zalando.play.controllers.MissingDefaultReads
    object BodyReads extends MissingDefaultReads {
        implicit val NewPetReads: Reads[NewPet] = (
            (JsPath \ "name").read[String] and (JsPath \ "id").readNullable[Long] and (JsPath \ "tag").readNullable[String]
        )(NewPet.apply _)
    }

    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    import de.zalando.play.controllers.MissingDefaultWrites
    object ResponseWrites extends MissingDefaultWrites {
    implicit val PetWrites: Writes[Pet] = new Writes[Pet] {
        def writes(ss: Pet) =
          Json.obj(
            "id" -> ss.id, 
            "name" -> ss.name, 
            "tag" -> ss.tag
          )
        }
    }
}

// should be defined after the package because of the https://issues.scala-lang.org/browse/SI-9922

//noinspection ScalaStyle
package object simple_petstore_api_yaml {

    type PetsIdDeleteResponses204 = Null
    type NewPetTag = Option[String]
    type PetsGetLimit = Option[Int]
    type NewPetId = Option[Long]
    type PetsGetTagsOpt = ArrayWrapper[String]
    type PetsGetResponses200 = Seq[Pet]
    type PetsGetTags = Option[PetsGetTagsOpt]


import play.api.mvc.{QueryStringBindable, PathBindable}

    implicit val bindable_OptionIntQuery: QueryStringBindable[Option[Int]] = PlayPathBindables.createOptionQueryBindable[Int]
    implicit val bindable_ArrayWrapperStringQuery: QueryStringBindable[ArrayWrapper[String]] = PlayPathBindables.createArrayWrapperQueryBindable[String]("csv")
    implicit val bindable_OptionPetsGetTagsOptQuery: QueryStringBindable[Option[PetsGetTagsOpt]] = PlayPathBindables.createOptionQueryBindable[PetsGetTagsOpt]

} 
Example 9
Source File: i041_no_json_deserialiser_yaml.scala    From api-first-hand   with MIT License 5 votes vote down vote up
package i041_no_json_deserialiser


    import java.time.ZonedDateTime
    import scala.math.BigDecimal
    import scala.math.BigInt

    import de.zalando.play.controllers.PlayPathBindables


//noinspection ScalaStyle
package yaml {


    case class Money(id: UserId, userId: UserId, amount: MoneyAmount, createDate: MoneyCreateDate) 
    case class User(id: UserId, name: UserName, money: UserMoney) 
    case class UserMoney(id: UserId, userId: UserId, amount: MoneyAmount, createDate: MoneyCreateDate) 
    case class Error(code: Int, message: String) 


    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    import de.zalando.play.controllers.MissingDefaultReads
    object BodyReads extends MissingDefaultReads {
        implicit val MoneyReads: Reads[Money] = (
            (JsPath \ "id").readNullable[Long] and (JsPath \ "userId").readNullable[Long] and (JsPath \ "amount").readNullable[BigDecimal] and (JsPath \ "createDate").readNullable[ZonedDateTime]
        )(Money.apply _)
        implicit val UserMoneyReads: Reads[UserMoney] = (
            (JsPath \ "id").readNullable[Long] and (JsPath \ "userId").readNullable[Long] and (JsPath \ "amount").readNullable[BigDecimal] and (JsPath \ "createDate").readNullable[ZonedDateTime]
        )(UserMoney.apply _)
        implicit val UserReads: Reads[User] = (
            (JsPath \ "id").readNullable[Long] and (JsPath \ "name").readNullable[String] and (JsPath \ "money").read[UserMoney]
        )(User.apply _)
    }

    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    import de.zalando.play.controllers.MissingDefaultWrites
    object ResponseWrites extends MissingDefaultWrites {
    implicit val MoneyWrites: Writes[Money] = new Writes[Money] {
        def writes(ss: Money) =
          Json.obj(
            "id" -> ss.id, 
            "userId" -> ss.userId, 
            "amount" -> ss.amount, 
            "createDate" -> ss.createDate
          )
        }
    implicit val UserMoneyWrites: Writes[UserMoney] = new Writes[UserMoney] {
        def writes(ss: UserMoney) =
          Json.obj(
            "id" -> ss.id, 
            "userId" -> ss.userId, 
            "amount" -> ss.amount, 
            "createDate" -> ss.createDate
          )
        }
    implicit val UserWrites: Writes[User] = new Writes[User] {
        def writes(ss: User) =
          Json.obj(
            "id" -> ss.id, 
            "name" -> ss.name, 
            "money" -> ss.money
          )
        }
    }
}

// should be defined after the package because of the https://issues.scala-lang.org/browse/SI-9922

//noinspection ScalaStyle
package object yaml {

    type MoneyCreateDate = Option[ZonedDateTime]
    type UserId = Option[Long]
    type MoneyAmount = Option[BigDecimal]
    type UserName = Option[String]
    type UserGetResponses200 = Seq[User]


import play.api.mvc.{QueryStringBindable, PathBindable}

    implicit val bindable_BigIntPath = PlayPathBindables.pathBindableBigInt

} 
Example 10
Source File: form_data_yaml.scala    From api-first-hand   with MIT License 5 votes vote down vote up
package form_data


    import java.io.File
    import scala.math.BigInt

    import de.zalando.play.controllers.PlayPathBindables


//noinspection ScalaStyle
package yaml {


    case class MultipartPostResponses200(name: BothPostResponses200Name, year: BothPostYear, fileSize: BothPostYear, fileName: BothPostResponses200Name) 
    case class BothPostResponses200(name: BothPostResponses200Name, year: BothPostYear, avatarSize: BothPostYear, ringtoneSize: BothPostYear) 


    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    import de.zalando.play.controllers.MissingDefaultWrites
    object ResponseWrites extends MissingDefaultWrites {
    implicit val BothPostResponses200Writes: Writes[BothPostResponses200] = new Writes[BothPostResponses200] {
        def writes(ss: BothPostResponses200) =
          Json.obj(
            "name" -> ss.name, 
            "year" -> ss.year, 
            "avatarSize" -> ss.avatarSize, 
            "ringtoneSize" -> ss.ringtoneSize
          )
        }
    implicit val MultipartPostResponses200Writes: Writes[MultipartPostResponses200] = new Writes[MultipartPostResponses200] {
        def writes(ss: MultipartPostResponses200) =
          Json.obj(
            "name" -> ss.name, 
            "year" -> ss.year, 
            "fileSize" -> ss.fileSize, 
            "fileName" -> ss.fileName
          )
        }
    }
}

// should be defined after the package because of the https://issues.scala-lang.org/browse/SI-9922

//noinspection ScalaStyle
package object yaml {

    type MultipartPostAvatar = Option[File]
    type BothPostResponses200Name = Option[String]
    type BothPostYear = Option[BigInt]


import play.api.mvc.{QueryStringBindable, PathBindable}

    implicit val bindable_FileQuery = PlayPathBindables.queryBindableFile
    implicit val bindable_BigIntQuery = PlayPathBindables.queryBindableBigInt
    implicit val bindable_OptionFileQuery: QueryStringBindable[Option[File]] = PlayPathBindables.createOptionQueryBindable[File]
    implicit val bindable_OptionBigIntQuery: QueryStringBindable[Option[BigInt]] = PlayPathBindables.createOptionQueryBindable[BigInt]

} 
Example 11
Source File: SlackTeamInfo.scala    From slack-client   with MIT License 5 votes vote down vote up
package com.kifi.slack.models

import play.api.libs.functional.syntax._
import play.api.libs.json._
import play.api.mvc.{PathBindable, QueryStringBindable}

case class SlackTeamId(value: String)
object SlackTeamId {
  implicit val format: Format[SlackTeamId] = Format(Reads(_.validate[String].map(SlackTeamId(_))), Writes(x => JsString(x.value)))
  implicit val pathBinder = new PathBindable[SlackTeamId] {
    override def bind(key: String, value: String): Either[String, SlackTeamId] = Right(SlackTeamId(value))
    override def unbind(key: String, obj: SlackTeamId): String = obj.value
  }

  implicit def queryStringBinder(implicit stringBinder: QueryStringBindable[String]) = new QueryStringBindable[SlackTeamId] {
    override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, SlackTeamId]] = {
      stringBinder.bind(key, params) map {
        case Right(value) => Right(SlackTeamId(value))
        case _ => Left("Unable to bind a SlackTeamId")
      }
    }
    override def unbind(key: String, teamId: SlackTeamId): String = {
      stringBinder.unbind(key, teamId.value)
    }
  }
}
case class SlackTeamName(value: String)
object SlackTeamName {
  implicit val format: Format[SlackTeamName] = Format(Reads(_.validate[String].map(SlackTeamName(_))), Writes(x => JsString(x.value)))
}
case class SlackTeamEmailDomain(value: String)

case class SlackTeamDomain(value: String)
object SlackTeamDomain {
  implicit val format = Format[SlackTeamDomain](
    Reads { value =>
      value.validate[String].map {
        domainStr => if (domainStr.endsWith(".slack.com")) SlackTeamDomain(domainStr) else SlackTeamDomain(domainStr + ".slack.com")
      }
    },
    Writes(domain => JsString(domain.value))
  )
}

object SlackTeamIconReads extends Reads[Map[Int, String]] {
  private val sizePattern = """^image_(\d+)$""".r
  def reads(value: JsValue) = value.validate[JsObject].map { obj =>
    val isDefaultImage = (obj \ "image_default").asOpt[Boolean].getOrElse(false)
    if (isDefaultImage) Map.empty[Int, String] else obj.value.collect { case (sizePattern(size), JsString(imageUrl)) => size.toInt -> imageUrl }.toMap
  }
}

sealed trait SlackTeamInfo {
  def id: SlackTeamId
  def name: SlackTeamName
}

object SlackTeamInfo {
  implicit val slackReads = Reads[SlackTeamInfo] { jsValue =>
    FullSlackTeamInfo.slackReads.reads(jsValue) orElse
      PartialSlackTeamInfo.slackReads.reads(jsValue)
  }
}

case class FullSlackTeamInfo(
  id: SlackTeamId,
  name: SlackTeamName,
  domain: SlackTeamDomain,
  emailDomains: Seq[SlackTeamEmailDomain],
  icon: Map[Int, String]) extends SlackTeamInfo

object FullSlackTeamInfo {
  implicit val slackReads: Reads[FullSlackTeamInfo] = (
    (__ \ 'id).read[SlackTeamId] and
    (__ \ 'name).read[SlackTeamName] and
    (__ \ 'domain).read[SlackTeamDomain] and
    (__ \ 'email_domain).read[String].map(domains => domains.split(',').toList.map(_.trim).collect { case domain if domain.nonEmpty => SlackTeamEmailDomain(domain) }) and
    (__ \ 'icon).read(SlackTeamIconReads)
  )(FullSlackTeamInfo.apply _)
}

case class PartialSlackTeamInfo(id: SlackTeamId, name: SlackTeamName, domain: SlackTeamDomain, icon: Map[Int, String]) extends SlackTeamInfo
object PartialSlackTeamInfo {
  implicit val slackReads: Reads[PartialSlackTeamInfo] = (
    (__ \ 'id).read[SlackTeamId] and
    (__ \ 'name).read[SlackTeamName] and
    (__ \ 'domain).read[SlackTeamDomain] and
    SlackTeamIconReads
  )(PartialSlackTeamInfo.apply _)
}

case class BasicSlackTeamInfo(id: SlackTeamId, name: SlackTeamName) extends SlackTeamInfo 
Example 12
Source File: Bindables.scala    From cave   with MIT License 5 votes vote down vote up
package com.gilt.cavellc.models

object Bindables {

  import org.joda.time.format.ISODateTimeFormat
  import org.joda.time.{DateTime, LocalDate}
  import play.api.mvc.{PathBindable, QueryStringBindable}

  // Type: date-time-iso8601
  implicit val pathBindableTypeDateTimeIso8601 = new PathBindable.Parsing[DateTime](
    ISODateTimeFormat.dateTimeParser.parseDateTime(_), _.toString, (key: String, e: Exception) => s"Error parsing date time $key. Example: 2014-04-29T11:56:52Z"
  )

  // Type: date-time-iso8601
  implicit val queryStringBindableTypeDateTimeIso8601 = new QueryStringBindable.Parsing[DateTime](
    ISODateTimeFormat.dateTimeParser.parseDateTime(_), _.toString, (key: String, e: Exception) => s"Error parsing date time $key. Example: 2014-04-29T11:56:52Z"
  )

  // Type: date-iso8601
  implicit val pathBindableTypeDateIso8601 = new PathBindable.Parsing[LocalDate](
    ISODateTimeFormat.yearMonthDay.parseLocalDate(_), _.toString, (key: String, e: Exception) => s"Error parsing date time $key. Example: 2014-04-29"
  )

  // Enum: Role
  private val enumRoleNotFound = (key: String, e: Exception) => s"Unrecognized $key, should be one of ${Role.all.mkString(", ")}"

  private val enumAggregatorNotFound = (key: String, e: Exception) => s"Unrecognized $key, should be one of ${Aggregator.all.mkString(", ")}"

  implicit val pathBindableEnumRole = new PathBindable.Parsing[Role](
    Role.fromString(_).get, _.toString, enumRoleNotFound
  )

  implicit val queryStringBindableEnumRole = new QueryStringBindable.Parsing[Role](
    Role.fromString(_).get, _.toString, enumRoleNotFound
  )

  implicit val queryStringBindableAggregator = new QueryStringBindable.Parsing[Aggregator](
    Aggregator.fromString(_).get, _.toString, enumAggregatorNotFound
  )

}