Add helpers to URL rewriting so it's more DSLy #976

Open
dpp opened this Issue Apr 16, 2011 · 6 comments

Projects

None yet

4 participants

@dpp
Lift Web Framework member

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))

}
}

@indrajitr
Lift Web Framework member

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

@indrajitr
Lift Web Framework member

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

Pushed pending tickets to 2.4-M5

@indrajitr
Lift Web Framework member

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

@indrajitr
Lift Web Framework member
@dpp dpp was assigned Mar 1, 2012
This was referenced Mar 1, 2012
@Shadowfiend
Lift Web Framework member

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment