Skip to content

Commit

Permalink
Merge pull request #1557 from guardian/jsh/recipe-edition
Browse files Browse the repository at this point in the history
Add initial support for Feast curation
  • Loading branch information
jonathonherbert authored Apr 23, 2024
2 parents 3acfc6b + 0a14146 commit 6c132f1
Show file tree
Hide file tree
Showing 20 changed files with 427 additions and 99 deletions.
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ Useful things to know:

### The Editions creator

The Editions interface is used to curate content on the Editions app (currently known as The Daily on iOS and Android). Editions also uses the fronts-client front end, and can be accessed from the Manage Editions menu on the [homepage](https://fronts.code.dev-gutools.co.uk/v2).
The Editions creator is used to curate content on both the Editions app (currently known as The Daily on iOS and Android),
and the Feast recipes app.
Editions creator also uses the fronts-client front end, and can be accessed from the Manage Editions menu on the [homepage](https://fronts.code.dev-gutools.co.uk/v2).

Curation works in the same way as the main fronts tool. But there are these differences:

Expand All @@ -92,10 +94,13 @@ Curation works in the same way as the main fronts tool. But there are these diff

* The publication process for Editions is different to the main fronts. We push the json we produce to a lambda - the [backend of the Editions app](https://github.com/guardian/editions), and this combines fronts data with CAPI calls etc to produce the Edition.

Full [Editions codebase and documentation here](https://github.com/guardian/editions).

For the specific, technical, definitions of the terms `Edition`, `CuratedPlatform` etc. please
refer to the [Glossary](docs/Glossary.md).

For more information about how specific Editions are built from Templates, see the technical
docs at [docs/EditionsTemplating.md](docs/EditionsTemplating.md)

Full [Editions codebase and documentation here](https://github.com/guardian/editions).

### The Config Tool

Expand Down
7 changes: 3 additions & 4 deletions app/Components.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import com.amazonaws.auth.AWSCredentialsProvider
import software.amazon.awssdk.regions.{Region => WeirdRegion}
import com.amazonaws.regions.Region
import software.amazon.awssdk.auth.credentials.{AwsCredentials, AwsCredentialsProvider, AwsCredentialsProviderChain, DefaultCredentialsProvider, ProfileCredentialsProvider}
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider
import conf.ApplicationConfiguration
import config.{CustomGzipFilter, UpdateManager}
import controllers._
Expand All @@ -15,7 +14,7 @@ import play.api.routing.Router
import play.filters.cors.CORSConfig
import play.filters.cors.CORSConfig.Origins
import filters._
import model.editions.EditionsTemplates
import model.editions.{EditionsAppTemplates, FeastAppTemplates}
import router.Routes
import services._
import services.editions.EditionsTemplating
Expand Down Expand Up @@ -59,7 +58,7 @@ class AppComponents(context: Context, val config: ApplicationConfiguration)

// Editions services
val editionsDb = new EditionsDB(config.postgres.url, config.postgres.user, config.postgres.password)
val templating = new EditionsTemplating(EditionsTemplates.templates, capi, ophan)
val templating = new EditionsTemplating(EditionsAppTemplates.templates ++ FeastAppTemplates.templates, capi, ophan)
val publishingBucket = new EditionsBucket(s3Client, config.aws.publishedEditionsIssuesBucket)
val previewBucket = new EditionsBucket(s3Client, config.aws.previewEditionsIssuesBucket)
val editionsPublishing = new EditionsPublishing(publishingBucket, previewBucket, editionsDb)
Expand Down
12 changes: 6 additions & 6 deletions app/controllers/DefaultsController.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package controllers

import com.gu.facia.client.models.{Metadata, TargetedTerritory, Trail}
import model.editions.EditionsTemplates
import model.editions.templates.EditionDefinition
import model.{Cached, FeatureSwitch, UserDataForDefaults}
import com.gu.facia.client.models.{Metadata, TargetedTerritory}
import model.editions.{EditionsAppTemplates, FeastAppTemplates}
import model.editions.templates.CuratedPlatformDefinition
import model.{Cached, UserDataForDefaults}
import permissions.Permissions
import play.api.libs.json.{JsValue, Json}
import switchboard.SwitchManager
Expand Down Expand Up @@ -34,7 +34,7 @@ case class Defaults(
capiLiveUrl: String = "",
capiPreviewUrl: String = "",
availableTerritories: Iterable[TargetedTerritory] = Nil,
availableEditions: List[EditionDefinition]
availableTemplates: List[CuratedPlatformDefinition]
)

class DefaultsController(val acl: Acl, val isDev: Boolean, val deps: BaseFaciaControllerComponents) extends BaseFaciaController(deps) {
Expand Down Expand Up @@ -71,7 +71,7 @@ class DefaultsController(val acl: Acl, val isDev: Boolean, val deps: BaseFaciaCo
},
None,
availableTerritories = TargetedTerritory.allTerritories,
availableEditions = EditionsTemplates.getAvailableEditions
availableTemplates = EditionsAppTemplates.getAvailableTemplates ++ FeastAppTemplates.getAvailableTemplates
)))
}
}
Expand Down
32 changes: 19 additions & 13 deletions app/controllers/EditionsController.scala
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package controllers

import java.time.{LocalDate, OffsetDateTime}

import cats.syntax.either._
import com.gu.contentapi.json.CirceEncoders._
import io.circe.syntax._
import logging.Logging
import logic.EditionsChecker
import model.editions._
import model.editions.templates.EditionType
import model.editions.templates.{CuratedPlatformDefinition, CuratedPlatformWithTemplate, EditionType}
import model.forms._
import net.logstash.logback.marker.Markers
import play.api.libs.json.{JsObject, Json, JsValue}
import play.api.libs.json.{JsObject, Json}
import play.api.mvc.Result
import services.Capi
import services.editions.EditionsTemplating
Expand All @@ -23,7 +22,7 @@ import util.ContentUpgrade.rewriteBody
import util.{SearchResponseUtil, UserUtil}

import scala.jdk.CollectionConverters._
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.ExecutionContext
import scala.util.Try

class EditionsController(db: EditionsDB,
Expand Down Expand Up @@ -85,9 +84,9 @@ class EditionsController(db: EditionsDB,
.getOrElse(NotFound(s"Issue $id not found"))
}

def republishEditions = EditEditionsAuthAction { _ => {
def republishEditionsAppEditionsList = EditEditionsAuthAction { _ => {
try {
val raw = Json.toJson(Map("action" -> "editionList")).as[JsObject] + ("content", Json.toJson(getAvailableEditionsJson))
val raw = Json.toJson(Map("action" -> "editionList")).as[JsObject] + ("content", Json.toJson(getAvailableEditionsAppEditions))
publishing.putEditionsList(raw.toString())
Ok("Published. Please check processing has succeeded.")
} catch {
Expand All @@ -96,7 +95,7 @@ class EditionsController(db: EditionsDB,
}}

def getAvailableEditions = EditEditionsAuthAction { _ => {
Ok(Json.toJson(getAvailableEditionsJson))
Ok(Json.toJson(getAvailableCuratedPlatformEditions))
}}

def checkIssue(id: String) = EditEditionsAuthAction { _ =>
Expand Down Expand Up @@ -205,7 +204,7 @@ class EditionsController(db: EditionsDB,
db.getCollectionPrefill(id).map { prefillUpdate =>
logger.info(s"getPrefillForCollection id=$id, prefillUpdate")
import prefillUpdate._
val capiDateQueryParam = EditionsTemplates.templates(edition).template.capiDateQueryParam
val capiDateQueryParam = EditionsAppTemplates.templates(edition).template.capiDateQueryParam
val capiPrefillTimeParams = CapiPrefillTimeParams(capiQueryTimeWindow, capiDateQueryParam)
// TODO
// when we click (suggest articles) for collection we are not using ophan metrics and we are not sorting on them
Expand Down Expand Up @@ -251,17 +250,24 @@ class EditionsController(db: EditionsDB,
} getOrElse NotFound(s"Front $id not found")
}

private def getAvailableEditionsJson = {
val allEditions = EditionsTemplates.getAvailableEditions
private def getAvailableCuratedPlatformEditions: Map[String, List[CuratedPlatformDefinition]] = {
val feastAppEditions = FeastAppTemplates.getAvailableTemplates

getAvailableEditionsAppEditions ++ Map(
"feastEditions" -> feastAppEditions,
)
}

private def getAvailableEditionsAppEditions: Map[String, List[CuratedPlatformDefinition]] = {
val allEditions = EditionsAppTemplates.getAvailableTemplates
val regionalEditions = allEditions.filter(e => e.editionType == EditionType.Regional)
val specialEditions = allEditions.filter(e => e.editionType == EditionType.Special)
val trainingEditions = allEditions.filter(e => e.editionType == EditionType.Training)

Map(
"regionalEditions" -> regionalEditions,
"specialEditions" -> specialEditions,
"trainingEditions" -> trainingEditions
"trainingEditions" -> trainingEditions,
)
}


}
4 changes: 2 additions & 2 deletions app/controllers/V2App.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import model.{FeatureSwitch, UserData, UserDataForDefaults}

import scala.concurrent.ExecutionContext
import com.gu.facia.client.models.{Metadata, TargetedTerritory}
import model.editions.EditionsTemplates
import model.editions.{EditionsAppTemplates, FeastAppTemplates}
import permissions.Permissions
import play.api.libs.json.Json
import software.amazon.awssdk.services.dynamodb.DynamoDbClient
Expand Down Expand Up @@ -80,7 +80,7 @@ class V2App(isDev: Boolean, val acl: Acl, dynamoClient: DynamoDbClient, val deps
routes.FaciaContentApiProxy.capiLive("").absoluteURL(true),
routes.FaciaContentApiProxy.capiPreview("").absoluteURL(true),
TargetedTerritory.allTerritories,
EditionsTemplates.getAvailableEditions
EditionsAppTemplates.getAvailableTemplates ++ FeastAppTemplates.getAvailableTemplates
)

Ok(views.html.V2App.app(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ package model.editions

import java.time.temporal.ChronoField
import java.time.{LocalDate, ZoneId, ZoneOffset}

import enumeratum.EnumEntry.{Hyphencase, Uncapitalised}
import enumeratum.{EnumEntry, PlayEnum}
import model.editions.PathType.{PrintSent, Search}
import model.editions.templates.TemplateHelpers.Defaults
import model.editions.templates._
import model.editions.templates.feast.{FeastNorthernHemisphere, FeastSouthernHemisphere}
import org.postgresql.util.PGobject
import play.api.libs.json.Json
import services.editions.prefills.CapiQueryTimeWindow

object EditionsTemplates {
val templates: Map[Edition, EditionDefinitionWithTemplate] = Map(


object EditionsAppTemplates {
val templates: Map[Edition, EditionsAppDefinitionWithTemplate] = Map(
Edition.DailyEdition -> DailyEdition,
Edition.AustralianEdition -> AustralianEdition,
Edition.TrainingEdition -> TrainingEdition,
Expand All @@ -27,7 +29,26 @@ object EditionsTemplates {
Edition.EditionWellbeing -> EditionWellbeing
)

val getAvailableEditions: List[EditionDefinition] = templates.values.toList
val getAvailableTemplates: List[EditionsAppDefinitionWithTemplate] = templates.values.toList
}

object FeastAppTemplates {
val templates: Map[Edition, CuratedPlatformWithTemplate] = Map(
Edition.FeastNorthernHemisphere -> FeastNorthernHemisphere,
Edition.FeastSouthernHemisphere -> FeastSouthernHemisphere
)

val getAvailableTemplates: List[CuratedPlatformWithTemplate] = templates.values.toList
}

sealed trait CuratedPlatform extends EnumEntry with Uncapitalised

object CuratedPlatform extends PlayEnum[CuratedPlatform] {
case object Editions extends CuratedPlatform

case object Feast extends CuratedPlatform

override def values = findValues
}

case object WeekDay extends Enumeration(1) {
Expand Down Expand Up @@ -75,20 +96,32 @@ object Edition extends PlayEnum[Edition] {
case object EditionEarth extends Edition

case object EditionBooks extends Edition

case object EditionWeWereThere extends Edition

case object EditionEurosSpecial extends Edition

case object EditionOlympicLegends extends Edition

case object EditionEndOfYear extends Edition

case object EditionWellbeing extends Edition


case object FeastSouthernHemisphere extends Edition

case object FeastNorthernHemisphere extends Edition

override def values = findValues
}

sealed abstract class FeastEditions extends EnumEntry with Hyphencase

object FeastEditions extends PlayEnum[FeastEditions] {
case object FeastNorthernHemisphere extends FeastEditions
case object FeastSouthernHemisphere extends FeastEditions

override def values = findValues
}

case class FrontPresentation(swatch: Swatch) {
implicit def frontPresentationFormat = Json.format[FrontPresentation]
Expand Down
8 changes: 4 additions & 4 deletions app/model/editions/EditionsIssue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ case class EditionsIssue(
edition,
issueDate,
version,
if (action == PublishAction.publish)
if (action == PublishAction.publish)
// publish does not need or want config because by definition we are publishing
// only the previously provided version. We do not want to be able to change content.
List()
List()
else fronts
.filterNot(_.isHidden) // drop hidden fronts
.map(_.toPublishedFront) // convert
.filterNot(_.collections.isEmpty), // drop fronts that contain no collections
EditionsTemplates.templates.get(edition).map(_.notificationUTCOffset).getOrElse(defaultOffset),
EditionsTemplates.templates.get(edition).map(_.topic)
EditionsAppTemplates.templates.get(edition).map(_.notificationUTCOffset).getOrElse(defaultOffset),
EditionsAppTemplates.templates.get(edition).map(_.topic)
)
}

Expand Down
Loading

0 comments on commit 6c132f1

Please sign in to comment.