framework icon indicating copy to clipboard operation
framework copied to clipboard

Add helpers to URL rewriting so it's more DSLy

Open dpp opened this issue 13 years ago • 6 comments

Some code that can help us create a better DSL:

import net.liftweb.http._ import net.liftweb.http.LiftRules import com.gu.sport.microapp.Endpoints import org.joda.time.format.DateTimeFormat import net.liftweb.util.Helpers._ import com.gu.management.{Manifest, Management} import net.liftweb.util.NamedPF import net.liftweb.common.Empty import com.gu.sport.microapp.snippet.Scoped import org.joda.time.{DateTimeZone, DateMidnight, DateTime} import com.gu.sport.microapp.repository.{SportMicroappMatchRepository, SportMicroappCompetitionRepository, SportMicroappMatchSearcher} import com.gu.opta.model.match.Match import com.gu.opta.model.competition.{Matches, TeamMatches, Competition}

class Boot { SportMicroappMatchSearcher.start SportMicroappCompetitionRepository.start

def boot = {

DateTimeZone setDefault(DateTimeZone forID ("Europe/London"))

LiftRules.addToPackages("com.gu.sport.microapp")

LiftRules.early.append(_.setCharacterEncoding("UTF-8"))

// Render view templates as HTML5 by default
LiftRules.htmlProperties.default.set((r: Req) => new Html5Properties(r.userAgent))

LiftRules.autoIncludeAjax = _ => false
LiftRules.autoIncludeComet = _ => false
LiftRules.enableContainerSessions = false
LiftRules.getLiftSession = req => new LiftSession(req.contextPath, "dummySession", Empty)
LiftRules.sessionCreator = (i1, i2) => error("no sessions here please")

//all paths are stateless (removes lift_page JS on bottom of page
LiftRules.statelessTest.prepend({
  case _ => true
})

LiftRules.defaultHeaders = {
 case _ =>
    List("Date" -> nowAsInternetDate, "Cache-Control" -> "public, max-age=60")
}

object DatedPath {
  val fmt = DateTimeFormat.forPattern("yyyyMMMdd")
  def unapply(datedPath: List[String]): Option[DateMidnight] = datedPath match {
    case year::month::day::postfix::Nil => tryo(fmt.parseDateTime(year+month+day).toDateMidnight)
    case _ => None
  }
}

object DatedMatch {
  val fmt = DateTimeFormat.forPattern("yyyyMMMdd")
  val IdBased = """(\d+)""".r
  val TeamBased = """([\w|-]+)-v-([\w|-]+)""".r
  def unapply(datedPath: List[String]): Option[Match] = datedPath match {
    case year::month::day::IdBased(matchId)::Nil => tryo {
      val matchDate = fmt.parseDateTime(year+month+day).toDateMidnight
      val theMatch = SportMicroappMatchRepository.getMatch(matchId)
      if (theMatch.dateTime.toDateMidnight != matchDate) throw new IllegalStateException("Url date and match date do not match")
      theMatch
    }
    case year::month::day::TeamBased(homeTeam, awayTeam)::Nil => {
      tryo {
        SportMicroappCompetitionRepository.findMatchSummary(fmt.parseDateTime(year+month+day), homeTeam, awayTeam) match {
          case Some(summary) => SportMicroappMatchRepository.getMatch(summary.id)
          case _ => throw new IllegalStateException("Url date and match date do not match")
        }
      }
    }
    case _ => None
  }
}

object MatchesFromWordsForUrl {
  def unapply(wordsForUrl: String): Option[Matches] = SportMicroappCompetitionRepository.getMatchesFor(wordsForUrl)
}

object MatchId {
  def unapply(matchId: String): Option[Match] = tryo{SportMicroappMatchRepository.getMatch(matchId)}
}

//TODO see if this can sensibly be moved to its own file
LiftRules.statelessRewrite.prepend(NamedPF("resources") {

  // /resource/football/2011/jan/01/matches
  case RewriteRequest(ParsePath("resource" :: "football" :: DatedPath(date), _, _, _), _, _) => {
    Scoped.date.set(date)
    RewriteResponse("resource" :: "football" :: "matches-on-date" :: Nil, Map.empty[String, String])
  }

  // /resource/football/matches
  case RewriteRequest(ParsePath("resource" :: "football" :: "matches" :: Nil, _, _, _), _, _) =>
    RewriteResponse("resource" :: "football" :: "matches-on-date" :: Nil, Map.empty[String, String])

  // /resource/football/match/2011/jan/02/1234/popup
  // /resource/football/match/2011/jan/02/everton-chelsea/popup
  case RewriteRequest(ParsePath("resource" :: "football" :: "match-popup" :: DatedMatch(theMatch), _, _, _), _, _) => {
    Scoped.theMatch.set(theMatch)
    RewriteResponse("resource" :: "football" :: "match-stats-popup" :: Nil, Map.empty[String, String])
  }

  // /resource/football/match/2011/jan/02/1234
  // /resource/football/match/2011/jan/02/everton-v-chelsea
  case RewriteRequest(ParsePath("resource" :: "football" :: "match" :: DatedMatch(theMatch), _, _, _), _, _) => {
    Scoped.theMatch.set(theMatch)
    RewriteResponse("resource" :: "football" :: "match-stats" :: Nil, Map.empty[String, String])
  }

  // /resource/football/premierleague/fixtures
  // /resource/football/everton/fixtures
  case RewriteRequest(ParsePath("resource" :: "football" :: MatchesFromWordsForUrl(matches) :: "fixtures" :: Nil, _, _, _), _, _) => {
    Scoped.matches.set(matches)
    RewriteResponse("resource" :: "football" :: "fixtures" :: Nil, Map.empty[String, String])
  }

  // /resource/football/premierleague/results
  // /resource/football/everton/results
  case RewriteRequest(ParsePath("resource" :: "football" :: MatchesFromWordsForUrl(matches) :: "results" :: Nil, _, _, _), _, _) => {
    Scoped.matches.set(matches)
    RewriteResponse("resource" :: "football" :: "results" :: Nil, Map.empty[String, String])
  }


  //TODO make me work
  // /resource/football/premierleague/tables
  case RewriteRequest(ParsePath("resource" :: "football" :: standings :: "tables" :: Nil, _, _, _), _, _) => {
    RewriteResponse("resource" :: "football" :: "tables" :: Nil, Map("optaId" -> standings))
  }

})


object CompetitionId {
  val CompetitionRegex = """(\d+)/(\d+)""".r
  def unapply(id: List[String]): Option[Competition] = id.mkString("/") match {
    case CompetitionRegex(id, season) => tryo{SportMicroappCompetitionRepository.getCompetition(id, season)}
    case _ => None
  }
}

object TeamId {
  val TeamRegex = """(\d+)""".r
  def unapply(id: String): Option[TeamMatches] = id match {
    case TeamRegex(id) => tryo{
      val fromDate = new DateTime().minusMonths(6)
      SportMicroappCompetitionRepository.getMatchesForTeam(id, Some(fromDate), None)
    }
    case _ => None
  }
}

LiftRules.statelessRewrite.prepend(NamedPF("components") {

  // /component/football/tournament-fixtures/1234
  case RewriteRequest(ParsePath("component" :: "football" :: "competition-summary" ::CompetitionId(competition), _, _, _), _, _) =>
    Scoped.competition.set(competition)
    RewriteResponse("component" :: "football" :: "competition-summary" :: Nil, Map.empty[String, String])

  case RewriteRequest(ParsePath("component" :: "football" :: "team-summary" ::TeamId(team):: Nil, _, _, _), _, _) =>
    Scoped.team.set(team)
    RewriteResponse("component" :: "football" :: "team-summary" :: Nil, Map.empty[String, String])

  // /component/football/tabs-and-score/1234
  case RewriteRequest(ParsePath("component" :: "football" :: "tabs-and-score" :: MatchId(theMatch) :: Nil, _, _, _), _, _) => {
    Scoped.theMatch.set(theMatch)
    RewriteResponse("component" :: "football" :: "tabs-and-score" :: Nil, Map.empty[String, String])
  }
  // /component/football/calendar
  //probably does not need a rewrite
})

LiftRules.statelessDispatchTable
  .append(Endpoints)
  .append(Management.publishWithIndex(Manifest))

} }

dpp avatar Apr 16 '11 06:04 dpp

Updating tickets (#919, #938, #950, #956, #976, #980, #982, #999, #1008, #1024, #1025, #1032, #1034, #1051)

indrajitr avatar Jul 21 '11 00:07 indrajitr

Updating tickets (#950, #956, #976, #980, #982, #999, #1008, #1053, #1078, #1092, #1097)

Pushed pending tickets to 2.4-M5

indrajitr avatar Sep 09 '11 01:09 indrajitr

Updating tickets (#956, #976, #980, #982, #1008, #1053, #1078, #1092, #1097, #1128)

indrajitr avatar Nov 11 '11 05:11 indrajitr

Updating tickets (#906, #950, #956, #960, #976, #980, #982, #997, #999, #1008, #1053, #1078, #1090, #1092, #1097, #1128, #1134, #1155, #1168)

indrajitr avatar Dec 22 '11 19:12 indrajitr

Imported from Assembla: http://www.assembla.com/spaces/liftweb/tickets/976

github-importer avatar Feb 19 '12 21:02 github-importer

At this point we suggest folks avoid using RewriteRequests; should we close this ticket accordingly?

Shadowfiend avatar May 11 '14 22:05 Shadowfiend