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

Euro 2024 atom header #27220

Merged
merged 15 commits into from
Jun 13, 2024
11 changes: 11 additions & 0 deletions common/app/conf/switches/JournalismSwitches.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package conf.switches

import conf.switches.Expiry.never
import java.time.LocalDate

trait JournalismSwitches {

Expand Down Expand Up @@ -73,4 +74,14 @@ trait JournalismSwitches {
sellByDate = never,
exposeClientSide = true,
)

val Euro2024Header = Switch(
SwitchGroup.Journalism,
name = "euro-2024-header",
description = "Show the Euro 2024 interactive atom header on football pages",
owners = Seq(Owner.withEmail("[email protected]")),
safeState = Off,
sellByDate = LocalDate.of(2024, 7, 15),
exposeClientSide = true,
)
}
2 changes: 1 addition & 1 deletion common/app/views/fragments/atoms/interactive.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
@if(shouldFence) {
<iframe class="interactive-atom-fence" srcdoc="@iframeBody.toString"></iframe>
} else {
<figure class="interactive interactive-atom">
<figure class="interactive interactive-atom" style="margin: 0;">
<style>
@HtmlFormat.raw(interactive.css)
</style>
Expand Down
35 changes: 25 additions & 10 deletions sport/app/football/controllers/FixturesController.scala
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
package football.controllers

import common.Edition
import common.ImplicitControllerExecutionContext
import feed.CompetitionsService
import football.model._
import model._
import model.content.InteractiveAtom
import contentapi.ContentApiClient
import java.time.LocalDate
import pa.FootballTeam
import play.api.mvc.{Action, AnyContent, ControllerComponents}
import scala.concurrent.Future
import conf.switches.Switches

class FixturesController(
val competitionsService: CompetitionsService,
val controllerComponents: ControllerComponents,
val contentApiClient: ContentApiClient,
)(implicit context: ApplicationContext)
extends MatchListController
with CompetitionFixtureFilters {
with CompetitionFixtureFilters
with ImplicitControllerExecutionContext {

private def fixtures(date: LocalDate): FixturesList = FixturesList(date, competitionsService.competitions)
private val page = new FootballPage("football/fixtures", "football", "All fixtures")
Expand Down Expand Up @@ -80,14 +87,22 @@ class FixturesController(

private def renderTagFixtures(date: LocalDate, tag: String): Action[AnyContent] =
getTagFixtures(date, tag)
.map(result =>
Action { implicit request =>
renderMatchList(
result._1,
result._2,
filters,
)
},
)
.map {
case (page, fixtures) =>
Action.async { implicit request =>
tag match {
case "euro-2024" if Switches.Euro2024Header.isSwitchedOn =>
val id = "/atom/interactive/interactives/2023/01/euros-2024/tables-euros-2024-header"
val edition = Edition(request)
contentApiClient
.getResponse(contentApiClient.item(id, edition))
.map(_.interactive.map(InteractiveAtom.make(_)))
.recover { case _ => None }
.map(renderMatchList(page, fixtures, filters, _))
case _ =>
Future.successful(renderMatchList(page, fixtures, filters, None))
}
}
}
.getOrElse(Action(NotFound))
}
55 changes: 42 additions & 13 deletions sport/app/football/controllers/LeagueTableController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,25 @@ import conf.switches.Switches
import feed.CompetitionsService
import model._
import play.api.mvc.{Action, AnyContent, BaseController, ControllerComponents}
import model.content.InteractiveAtom
import contentapi.ContentApiClient
import scala.concurrent.Future

case class TablesPage(
page: Page,
tables: Seq[Table],
urlBase: String,
filters: Map[String, Seq[CompetitionFilter]] = Map.empty,
comp: Option[Competition],
atom: Option[InteractiveAtom] = None,
) {
lazy val singleCompetition = tables.size == 1
}

class LeagueTableController(
val competitionsService: CompetitionsService,
val controllerComponents: ControllerComponents,
val contentApiClient: ContentApiClient,
)(implicit context: ApplicationContext)
extends BaseController
with GuLogging
Expand Down Expand Up @@ -80,10 +85,12 @@ class LeagueTableController(

val htmlResponse =
() =>
football.views.html.tablesList.tablesPage(TablesPage(page, groups, "/football", filters(tableOrder), None))
football.views.html.tablesList
.tablesPage(TablesPage(page, groups, "/football", filters(tableOrder), None))
val jsonResponse =
() =>
football.views.html.tablesList.tablesPage(TablesPage(page, groups, "/football", filters(tableOrder), None))
football.views.html.tablesList
.tablesPage(TablesPage(page, groups, "/football", filters(tableOrder), None))
renderFormat(htmlResponse, jsonResponse, page, Switches.all)

}
Expand Down Expand Up @@ -115,7 +122,7 @@ class LeagueTableController(

def renderCompetitionJson(competition: String): Action[AnyContent] = renderCompetition(competition)
def renderCompetition(competition: String): Action[AnyContent] =
Action { implicit request =>
Action.async { implicit request =>
val table = loadTables
.find(_.competition.url.endsWith(s"/$competition"))
.orElse(loadTables.find(_.competition.id == competition))
Expand All @@ -127,13 +134,30 @@ class LeagueTableController(
s"${table.competition.fullName} table",
)

val futureAtom = if (Switches.Euro2024Header.isSwitchedOn && competition == "euro-2024") {
val id = "/atom/interactive/interactives/2023/01/euros-2024/tables-euros-2024-header"
val edition = Edition(request)
contentApiClient
.getResponse(contentApiClient.item(id, edition))
.map(_.interactive.map(InteractiveAtom.make(_)))
.recover { case _ => None }
} else Future.successful(None)

val smallTableGroup =
table.copy(groups = table.groups.map { group => group.copy(entries = group.entries.take(10)) }).groups(0)
val htmlResponse = () =>
football.views.html.tablesList
.tablesPage(
TablesPage(page, Seq(table), table.competition.url, filters(tableOrder), Some(table.competition)),
)
val htmlResponse = (atom: Option[InteractiveAtom]) =>
() =>
football.views.html.tablesList
.tablesPage(
TablesPage(
page,
Seq(table),
table.competition.url,
filters(tableOrder),
Some(table.competition),
atom,
),
)
val jsonResponse = () =>
football.views.html.tablesList.tablesComponent(
table.competition,
Expand All @@ -142,14 +166,13 @@ class LeagueTableController(
multiGroup = table.multiGroup,
)

renderFormat(htmlResponse, jsonResponse, page)

futureAtom.map(maybeAtom => renderFormat(htmlResponse(maybeAtom), jsonResponse, page))
}
.getOrElse(
if (request.isJson) {
Cached(60)(JsonNotFound())
Future.successful(Cached(60)(JsonNotFound()))
} else {
Redirect("/football/tables")
Future.successful(Redirect("/football/tables"))
},
)
}
Expand Down Expand Up @@ -181,7 +204,13 @@ class LeagueTableController(
val htmlResponse = () =>
football.views.html.tablesList
.tablesPage(
TablesPage(page, Seq(groupTable), table.competition.url, filters(tableOrder), Some(table.competition)),
TablesPage(
page,
Seq(groupTable),
table.competition.url,
filters(tableOrder),
Some(table.competition),
),
)
val jsonResponse = () =>
football.views.html.tablesList.tablesComponent(
Expand Down
23 changes: 19 additions & 4 deletions sport/app/football/controllers/MatchDayController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ import java.time.LocalDate
import model._
import football.model._
import common.{Edition, JsonComponent}
import contentapi.ContentApiClient
import model.content.InteractiveAtom
import common.ImplicitControllerExecutionContext
import scala.concurrent.Future
import conf.switches.Switches

class MatchDayController(
val competitionsService: CompetitionsService,
val controllerComponents: ControllerComponents,
val contentApiClient: ContentApiClient,
)(implicit context: ApplicationContext)
extends MatchListController
with CompetitionLiveFilters {
with CompetitionLiveFilters
with ImplicitControllerExecutionContext {

def liveMatchesJson(): Action[AnyContent] = liveMatches()
def liveMatches(): Action[AnyContent] =
Expand Down Expand Up @@ -41,18 +48,26 @@ class MatchDayController(
competitionMatchesFor(competitionTag, year, month, day)

private def renderCompetitionMatches(competitionTag: String, date: LocalDate): Action[AnyContent] =
Action { implicit request =>
Action.async { implicit request =>
lookupCompetition(competitionTag)
.map { competition =>
val webTitle =
if (date == LocalDate.now(Edition.defaultEdition.timezoneId)) s"Today's ${competition.fullName} matches"
else s" ${competition.fullName} matches"
val page = new FootballPage(s"football/$competitionTag/live", "football", webTitle)
val matches = CompetitionMatchDayList(competitionsService.competitions, competition.id, date)
renderMatchList(page, matches, filters)
if (Switches.Euro2024Header.isSwitchedOn) {
val id = "/atom/interactive/interactives/2023/01/euros-2024/match-centre-euros-2024-header"
val edition = Edition(request)
contentApiClient
.getResponse(contentApiClient.item(id, edition))
.map(_.interactive.map(InteractiveAtom.make(_)))
.recover { case _ => None }
.map(renderMatchList(page, matches, filters, _))
} else Future.successful(renderMatchList(page, matches, filters))
}
.getOrElse {
NotFound
Future.successful(NotFound)
}
}

Expand Down
8 changes: 6 additions & 2 deletions sport/app/football/controllers/MatchListController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import play.api.mvc.{BaseController, RequestHeader}
import play.twirl.api.Html

import java.time.format.DateTimeFormatter
import model.content.InteractiveAtom

trait MatchListController extends BaseController with Requests {
def competitionsService: Competitions
Expand All @@ -25,23 +26,26 @@ trait MatchListController extends BaseController with Requests {
page: FootballPage,
matchesList: MatchesList,
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))
RevalidatableResult.Ok(football.views.html.matchList.matchesPage(page, matchesList, filters, atom))
}
}

protected def renderMoreMatches(
page: FootballPage,
matchesList: MatchesList,
filters: Map[String, Seq[CompetitionFilter]],
atom: Option[InteractiveAtom] = None,
)(implicit request: RequestHeader, context: ApplicationContext) = {
Cached(10) {
if (request.isJson)
Expand All @@ -51,7 +55,7 @@ trait MatchListController extends BaseController with Requests {
"previous" -> Html(matchesList.previousPage.getOrElse("")),
)
else
RevalidatableResult.Ok(football.views.html.matchList.matchesPage(page, matchesList, filters))
RevalidatableResult.Ok(football.views.html.matchList.matchesPage(page, matchesList, filters, atom))
}
}

Expand Down
5 changes: 3 additions & 2 deletions sport/app/football/controllers/ResultsController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import model._
import football.model._
import pa.FootballTeam
import model.Competition
import model.content.InteractiveAtom

class ResultsController(
val competitionsService: CompetitionsService,
Expand Down Expand Up @@ -54,13 +55,13 @@ class ResultsController(
}

private def renderWith(
renderFunction: (FootballPage, Results, Map[String, Seq[CompetitionFilter]]) => Result,
renderFunction: (FootballPage, Results, Map[String, Seq[CompetitionFilter]], Option[InteractiveAtom]) => Result,
)(date: LocalDate, tag: Option[String] = None): Result = {
val result = for {
p <- page(tag)
r <- results(date, tag)
} yield {
renderFunction(p, r, filters)
renderFunction(p, r, filters, None)
}
result.getOrElse(NotFound("No results"))
}
Expand Down
40 changes: 29 additions & 11 deletions sport/app/football/controllers/WallchartController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ import football.model.{CompetitionStage, Groups, KnockoutSpider}
import pa.{FootballMatch}

import java.time.ZonedDateTime
import scala.concurrent.Future
import contentapi.ContentApiClient
import conf.switches.Switches
import common.Edition
import model.content.InteractiveAtom

class WallchartController(
competitionsService: CompetitionsService,
val controllerComponents: ControllerComponents,
val contentApiClient: ContentApiClient,
)(implicit context: ApplicationContext)
extends BaseController
with GuLogging
Expand All @@ -28,7 +34,7 @@ class WallchartController(
def renderWallchartEmbed(competitionTag: String): Action[AnyContent] = renderWallchart(competitionTag, true)

def renderWallchart(competitionTag: String, embed: Boolean = false): Action[AnyContent] =
Action { implicit request =>
Action.async { implicit request =>
competitionsService
.competitionsWithTag(competitionTag)
.map { competition =>
Expand All @@ -40,18 +46,30 @@ class WallchartController(
val competitionStages = new CompetitionStage(competitionsService.competitions)
.stagesFromCompetition(competition, KnockoutSpider.orderings)
val nextMatch = WallchartController.nextMatch(competition.matches, ZonedDateTime.now())
Cached(60) {
if (embed)
RevalidatableResult.Ok(
football.views.html.wallchart.embed(page, competition, competitionStages, nextMatch),
)
else
RevalidatableResult.Ok(
football.views.html.wallchart.page(page, competition, competitionStages, nextMatch),
)
val futureAtom = if (Switches.Euro2024Header.isSwitchedOn && competitionTag == "euro-2024") {
val id = "/atom/interactive/interactives/2023/01/euros-2024/tables-euros-2024-header"
val edition = Edition(request)
contentApiClient
.getResponse(contentApiClient.item(id, edition))
.map(_.interactive.map(InteractiveAtom.make(_)))
.recover { case _ => None }
} else Future.successful(None)

futureAtom.map { maybeAtom =>
Cached(60) {
if (embed)
RevalidatableResult.Ok(
football.views.html.wallchart.embed(page, competition, competitionStages, nextMatch),
)
else
RevalidatableResult.Ok(
football.views.html.wallchart.page(page, competition, competitionStages, nextMatch, maybeAtom),
)
}
}

}
.getOrElse(NotFound)
.getOrElse(Future.successful(NotFound))
}

def renderGroupTablesEmbed(competitionTag: String): Action[AnyContent] =
Expand Down
Loading