From cc9494368972e55c7c14ef57251537e3ac5dedf1 Mon Sep 17 00:00:00 2001 From: Marjan Kalanaki Date: Fri, 6 Dec 2024 19:17:18 +0000 Subject: [PATCH] add dcr json endpoint for football/live --- .../controllers/MatchListController.scala | 38 +++++--- sport/app/football/model/LiveScores.scala | 90 +++++++++++++++++++ 2 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 sport/app/football/model/LiveScores.scala diff --git a/sport/app/football/controllers/MatchListController.scala b/sport/app/football/controllers/MatchListController.scala index 38f5f714a50e..4ef86441361a 100644 --- a/sport/app/football/controllers/MatchListController.scala +++ b/sport/app/football/controllers/MatchListController.scala @@ -2,10 +2,10 @@ package football.controllers import common.{Edition, JsonComponent} import feed.Competitions -import football.model.MatchesList +import football.model.{CompetitionMatches, DateCompetitionMatches, MatchesList, LiveScores} import implicits.Requests import model.Cached.RevalidatableResult -import model.{ApplicationContext, Cached, Competition, TeamMap} +import model.{ApplicationContext, CacheTime, Cached, Competition, TeamMap} import java.time.LocalDate import pa.FootballTeam @@ -28,17 +28,31 @@ trait MatchListController extends BaseController with Requests { filters: Map[String, Seq[CompetitionFilter]], atom: Option[InteractiveAtom] = None, )(implicit request: RequestHeader, context: ApplicationContext) = { - Cached(10) { - if (request.isJson) - JsonComponent( - "html" -> football.views.html.matchList.matchesComponent(matchesList), - "next" -> Html(matchesList.nextPage.getOrElse("")), - "previous" -> Html(matchesList.previousPage.getOrElse("")), - "atom" -> atom.isDefined, - ) - else - RevalidatableResult.Ok(football.views.html.matchList.matchesPage(page, matchesList, filters, atom)) + + if (request.isJson && request.forceDCR) { + val model = LiveScores( + pageTitle = matchesList.getPageTitle(Edition(request)), + pageType = matchesList.pageType, + matchesGroupedByDateAndCompetition = matchesList.matchesGroupedByDateAndCompetition.map { item => + DateCompetitionMatches(date = item._1, competitions = item._2.map(a => CompetitionMatches(a._1, a._2))) + }, + nextPage = None, + ) + Cached(CacheTime.Default)(RevalidatableResult.Ok(LiveScores.toJson(model))).as("application/json") + } else { + Cached(10) { + if (request.isJson) + JsonComponent( + "html" -> football.views.html.matchList.matchesComponent(matchesList), + "next" -> Html(matchesList.nextPage.getOrElse("")), + "previous" -> Html(matchesList.previousPage.getOrElse("")), + "atom" -> atom.isDefined, + ) + else + RevalidatableResult.Ok(football.views.html.matchList.matchesPage(page, matchesList, filters, atom)) + } } + } protected def renderMoreMatches( diff --git a/sport/app/football/model/LiveScores.scala b/sport/app/football/model/LiveScores.scala new file mode 100644 index 000000000000..38f344366b96 --- /dev/null +++ b/sport/app/football/model/LiveScores.scala @@ -0,0 +1,90 @@ +package football.model + +import model.Competition +import model.dotcomrendering.DotcomRenderingUtils.withoutNull +import pa.{ + Fixture, + FootballMatch, + LeagueStats, + LeagueTableEntry, + LeagueTeam, + LiveMatch, + MatchDay, + MatchDayTeam, + Official, + Result, + Round, + Stage, + Venue, + Competition => PaCompetition, +} +import play.api.libs.json.{JsObject, JsString, Json, Writes} + +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +case class CompetitionMatches(competition: Competition, matches: List[FootballMatch]) +case class DateCompetitionMatches(date: LocalDate, competitions: List[CompetitionMatches]) + +case class LiveScores( + pageTitle: String, + pageType: String, + matchesGroupedByDateAndCompetition: Seq[DateCompetitionMatches], + nextPage: Option[String], +) + +object LiveScores { + 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[Competition] = Json.writes[Competition] + implicit val competitionMatchesFormat: Writes[CompetitionMatches] = Json.writes[CompetitionMatches] + implicit val dateCompetitionMatchesFormat: Writes[DateCompetitionMatches] = Json.writes[DateCompetitionMatches] + implicit val SportsFormat: Writes[LiveScores] = Json.writes[LiveScores] + + def toJson(model: LiveScores): String = { + val jsValue = Json.toJson(model) + Json.stringify(withoutNull(jsValue)) + } +}