All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gu.facia.api.utils.ItemKicker.scala Maven / Gradle / Ivy

The newest version!
package com.gu.facia.api.utils

import com.gu.contentapi.client.model.v1.{TagType, Content, Tag}
import com.gu.facia.api.models.CollectionConfig
import com.gu.facia.client.models.MetaDataCommonFields

object ItemKicker {
  def fromContentAndTrail(
      maybeContent: Option[Content],
      trailMeta: MetaDataCommonFields,
      metaDefaults: ResolvedMetaData,
      config: Option[CollectionConfig]): Option[ItemKicker] = {

    lazy val maybeTag = maybeContent.flatMap(_.tags.headOption)
    lazy val tagKicker = maybeTag.map(TagKicker.fromTag)
    lazy val sectionKicker = for {
      content <- maybeContent
      name <- content.sectionName
      id <- content.sectionId
    } yield SectionKicker(name.capitalize, "/" + id)

    trailMeta.customKicker match {
      case Some(kicker)
        if trailMeta.snapType.exists(_.contains("latest")) &&
          metaDefaults.showKickerCustom &&
          trailMeta.snapUri.isDefined => Some(FreeHtmlKickerWithLink(kicker, s"/${trailMeta.snapUri.get}"))
      case Some(kicker) if metaDefaults.showKickerCustom => Some(FreeHtmlKicker(kicker))
      case _ => if (trailMeta.isBreaking.exists(identity)) {
        Some(BreakingNewsKicker)
      } else  if (metaDefaults.showKickerTag && maybeTag.isDefined) {
        tagKicker
      } else if (metaDefaults.showKickerSection) {
        sectionKicker
      } else if (config.exists(_.showTags) && maybeTag.isDefined) {
        tagKicker
      } else if (config.exists(_.showSections)) {
        sectionKicker
      } else if (!config.exists(_.hideKickers) && maybeContent.isDefined) {
        tonalKicker(maybeContent.get, trailMeta)
      } else {
        None
      }
    }
  }

  def fromTrailMetaData(trailMeta: MetaDataCommonFields): Option[ItemKicker] = fromContentAndTrail(None, trailMeta, ResolvedMetaData.fromTrailMetaData(trailMeta), None)

  def fromMaybeContentTrailMetaAndResolvedMetaData(maybeContent: Option[Content], trailMeta: MetaDataCommonFields, resolvedMetaData: ResolvedMetaData) =
    fromContentAndTrail(maybeContent, trailMeta, resolvedMetaData, None)

  def fromContentTrailMetaResolvedMetaAndConfig(content: Content, trailMeta: MetaDataCommonFields, resolvedMetaData: ResolvedMetaData, config: Option[CollectionConfig]): Option[ItemKicker] =
    fromContentAndTrail(Option(content), trailMeta, resolvedMetaData, config)

  private[utils] def tonalKicker(content: Content, trailMeta: MetaDataCommonFields): Option[ItemKicker] = {
    def tagsOfType(tagType: String): Seq[Tag] = content.tags.toSeq.filter(_.`type`.name == tagType)
    val types: Seq[Tag] = tagsOfType("type")
    val tones: Seq[Tag] = tagsOfType("tone")

    lazy val isReview = tones.exists(t => Tags.reviewMappings.contains(t.id))
    lazy val isAnalysis = tones.exists(_.id == Tags.Analysis)
    lazy val isPodcast = types.exists(_.id == Tags.Podcast) || content.tags.exists(_.podcast.isDefined)
    lazy val isCartoon = types.exists(_.id == Tags.Cartoon)

    if (content.fields.flatMap(_.liveBloggingNow).exists(identity)) {
      Some(LiveKicker)
    } else if (isPodcast) {
      val series = content.tags.find(_.`type` == TagType.Series) map { seriesTag =>
        Series(seriesTag.webTitle, seriesTag.webUrl)
      }
      Some(PodcastKicker(series))
    } else if (isAnalysis) {
      Some(AnalysisKicker)
    } else if (isReview) {
      Some(ReviewKicker)
    } else if (isCartoon) {
      Some(CartoonKicker)
    } else {
      None
    }
  }

  val TagsThatDoNotAutoKicker = Set(
    "commentisfree/commentisfree"
  )

  def seriesOrBlogKicker(item: Content) =
    item.tags.find({ tag =>
      Set[TagType](TagType.Series, TagType.Blog).contains(tag.`type`) && !TagsThatDoNotAutoKicker.contains(tag.id)
    }).map(TagKicker.fromTag)

  /** Used for de-duping bylines */
  def kickerContents(itemKicker: ItemKicker): Option[String] = itemKicker match {
    case PodcastKicker(Some(series)) => Some(series.name)
    case TagKicker(name, _, _) => Some(name)
    case SectionKicker(name, _) => Some(name)
    case FreeHtmlKicker(body) => Some(body)
    case FreeHtmlKickerWithLink(body, _) => Some(body)
    case _ => None
  }

  def stringIfPlainText(string: String) : Option[String] = {
    val StringWithHtml = "<\\w+.*>".r.unanchored
    string match {
      case StringWithHtml() => None
      case _ => Some(string)
    }
  }

  /** Return a plain-text representation of a kicker */
  def kickerText(itemKicker: ItemKicker): Option[String] = itemKicker match {
    case BreakingNewsKicker => Some("Breaking news")
    case AnalysisKicker => Some("Analysis")
    case ReviewKicker => Some("Review")
    case CartoonKicker => Some("Cartoon")
    case FreeHtmlKicker(text) => stringIfPlainText(text)
    case FreeHtmlKickerWithLink(text, _) => stringIfPlainText(text)
    case _ => kickerContents(itemKicker)
  }
}

case class Series(name: String, url: String)

sealed trait ItemKicker

case object BreakingNewsKicker extends ItemKicker
case object LiveKicker extends ItemKicker
case object AnalysisKicker extends ItemKicker
case object ReviewKicker extends ItemKicker
case object CartoonKicker extends ItemKicker
case class PodcastKicker(series: Option[Series]) extends ItemKicker

object TagKicker {
  def fromTag(tag: Tag) = TagKicker(tag.webTitle, tag.webUrl, tag.id)
}

case class TagKicker(name: String, url: String, id: String) extends ItemKicker

case class SectionKicker(name: String, url: String) extends ItemKicker
case class FreeHtmlKicker(body: String) extends ItemKicker
case class FreeHtmlKickerWithLink(body: String, url: String) extends ItemKicker


object Tags {
  val Analysis = "tone/analysis"
  val Crossword = "type/crossword"
  val Podcast = "type/podcast"
  val Editorial = "tone/editorials"
  val Cartoon = "type/cartoon"
  val Letters = "tone/letters"
  val Audio = "type/audio"

  val Article = "type/article"
  val Gallery = "type/gallery"
  val Video = "type/video"
  val Poll = "type/poll"
  val Interactive = "type/interactive"
  val Sudoku = "type/sudoku"

  object VisualTone {
    val Live = "live"
    val Comment = "comment"
    val Feature = "feature"
    val News = "news"
  }

  val liveMappings = Seq(
    "tone/minutebyminute"
  )

  val commentMappings = Seq (
    "tone/comment"
  )

  val mediaTypes = Seq(
    "type/video",
    "type/audio",
    "type/gallery",
    "type/picture"
  )

  val featureMappings = Seq(
    "tone/features",
    "tone/recipes",
    "tone/interview",
    "tone/performances",
    "tone/extract",
    "tone/reviews",
    "tone/albumreview",
    "tone/livereview",
    "tone/childrens-user-reviews"
  )

  val reviewMappings = Seq(
    "tone/reviews"
  )
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy