Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: add dcr json endpoint for football/live #27655

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions sport/app/football/controllers/MatchListController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package football.controllers

import common.{Edition, JsonComponent}
import feed.Competitions
import football.model.MatchesList
import football.model.{DotcomRenderingFootballDataModel, MatchesList}
import football.model.DotcomRenderingFootballDataModelImplicits._
import implicits.Requests
import model.Cached.RevalidatableResult
import model.{ApplicationContext, Cached, Competition, TeamMap}
Expand All @@ -29,7 +30,17 @@ trait MatchListController extends BaseController with Requests {
atom: Option[InteractiveAtom] = None,
)(implicit request: RequestHeader, context: ApplicationContext) = {
Cached(10) {
if (request.isJson)
if (request.isJson && request.forceDCR) {
val model = DotcomRenderingFootballDataModel(
pageTitle = matchesList.getPageTitle(Edition(request)),
pageType = matchesList.pageType,
matchesList = DotcomRenderingFootballDataModel.getMatchesList(matchesList.matchesGroupedByDateAndCompetition),
nextPage = matchesList.nextPage,
previousPage = matchesList.previousPage,
)

JsonComponent.fromWritable(model)
} else if (request.isJson)
JsonComponent(
"html" -> football.views.html.matchList.matchesComponent(matchesList),
"next" -> Html(matchesList.nextPage.getOrElse("")),
Expand Down
118 changes: 118 additions & 0 deletions sport/app/football/model/DotcomRenderingFootballDataModel.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package football.model

import model.dotcomrendering.DotcomRenderingUtils.withoutNull
import model.{Competition, CompetitionSummary}
import pa.{
Fixture,
FootballMatch,
LeagueStats,
LeagueTableEntry,
LeagueTeam,
LiveMatch,
MatchDay,
MatchDayTeam,
Official,
Result,
Round,
Stage,
Venue,
Competition => PaCompetition,
}
import play.api.libs.json._

import java.time.LocalDate
import java.time.format.DateTimeFormatter

case class CompetitionMatches(competitionSummary: CompetitionSummary, matches: List[FootballMatch])
case class MatchesByDateAndCompetition(date: LocalDate, competitionMatches: List[CompetitionMatches])

case class DotcomRenderingFootballDataModel(
pageTitle: String,
pageType: String,
matchesList: Seq[MatchesByDateAndCompetition],
nextPage: Option[String],
previousPage: Option[String],
)

object DotcomRenderingFootballDataModel {
def getMatchesList(
matches: Seq[(LocalDate, List[(Competition, List[FootballMatch])])],
): Seq[MatchesByDateAndCompetition] = {
matches.map { case (date, competitionMatches) =>
MatchesByDateAndCompetition(
date = date,
competitionMatches = competitionMatches.map { case (competition, matches) =>
CompetitionMatches(
competitionSummary = competition,
matches = matches,
)
},
)
}
}
}

object DotcomRenderingFootballDataModelImplicits {
implicit val localDateWrites: Writes[LocalDate] = Writes[LocalDate] { date =>
JsString(date.format(DateTimeFormatter.ISO_LOCAL_DATE))
}

implicit val stageFormat: Writes[Stage] = Json.writes[Stage]
implicit val roundFormat: Writes[Round] = Json.writes[Round]
implicit val matchDayTeamFormat: Writes[MatchDayTeam] = Json.writes[MatchDayTeam]
implicit val venueFormat: Writes[Venue] = Json.writes[Venue]
implicit val paCompetitionFormat: Writes[PaCompetition] = Json.writes[PaCompetition]
implicit val officialFormat: Writes[Official] = Json.writes[Official]

// Writes for Fixture with a type discriminator
implicit val fixtureWrites: Writes[Fixture] = Writes { fixture =>
Json.writes[Fixture].writes(fixture).as[JsObject] + ("type" -> JsString("Fixture"))
}

// Writes for MatchDay with a type discriminator
implicit val matchDayWrites: Writes[MatchDay] = Writes { matchDay =>
Json.writes[MatchDay].writes(matchDay).as[JsObject] + ("type" -> JsString("MatchDay"))
}

// Writes for Result with a type discriminator
implicit val resultWrites: Writes[Result] = Writes { result =>
Json.writes[Result].writes(result).as[JsObject] + ("type" -> JsString("Result"))
}

// Writes for LiveMatch with a type discriminator
implicit val liveMatchWrites: Writes[LiveMatch] = Writes { liveMatch =>
Json.writes[LiveMatch].writes(liveMatch).as[JsObject] + ("type" -> JsString("LiveMatch"))
}

implicit val footballMatchWrites: Writes[FootballMatch] = Writes { matchInstance =>
matchInstance match {
case f: Fixture => Json.toJson(f)(fixtureWrites)
case m: MatchDay => Json.toJson(m)(matchDayWrites)
case r: Result => Json.toJson(r)(resultWrites)
case l: LiveMatch => Json.toJson(l)(liveMatchWrites)
}
}

implicit val leagueStatsWrites: Writes[LeagueStats] = Json.writes[LeagueStats]
implicit val leagueTeamWrites: Writes[LeagueTeam] = Json.writes[LeagueTeam]
implicit val leagueTableEntryWrites: Writes[LeagueTableEntry] = Json.writes[LeagueTableEntry]

implicit val competitionFormat: Writes[CompetitionSummary] = (competition: CompetitionSummary) =>
Json.obj(
"id" -> competition.id,
"url" -> competition.url,
"fullName" -> competition.fullName,
"shortName" -> competition.shortName,
"nation" -> competition.nation,
)
implicit val competitionMatchesFormat: Writes[CompetitionMatches] = Json.writes[CompetitionMatches]
implicit val dateCompetitionMatchesFormat: Writes[MatchesByDateAndCompetition] =
Json.writes[MatchesByDateAndCompetition]

implicit val SportsFormat: Writes[DotcomRenderingFootballDataModel] = Json.writes[DotcomRenderingFootballDataModel]

def toJson(model: DotcomRenderingFootballDataModel): String = {
val jsValue = Json.toJson(model)
Json.stringify(withoutNull(jsValue))
}
}
11 changes: 10 additions & 1 deletion sport/app/football/model/model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ import pa.MatchDayTeam
import java.awt.Color
import java.time.LocalDate

trait CompetitionSummary {
def id: String
def url: String
def fullName: String
def shortName: String
def nation: String
}

/** @param tableDividers
* divides the league table into zones for promotion/relegation, or for qualification to another competition. Only
* add a table divider where the boundaries for progression are clear, e.g do not add a divider in Euro group stages
Expand All @@ -23,7 +31,8 @@ case class Competition(
showInTeamsList: Boolean = false,
tableDividers: List[Int] = Nil,
finalMatchSVG: Option[String] = None,
) extends implicits.Football {
) extends implicits.Football
with CompetitionSummary {

lazy val hasMatches = matches.nonEmpty
lazy val hasLiveMatches = matches.exists(_.isLive)
Expand Down
Loading