common/app/model/Tag.scala (167 lines of code) (raw):

package model import com.gu.contentapi.client.model.v1.{Podcast => ApiPodcast, Reference => ApiReference, Tag => ApiTag} import common.commercial.CommercialProperties import common.{Pagination, RelativePathEscaper} import conf.Configuration import contentapi.SectionTagLookUp import play.api.libs.json._ import views.support.{Contributor, ImgSrc, Item140, StripHtmlTagsAndUnescapeEntities} import navigation.GuardianFoundationHelper object Tag { def makeMetadata(tag: TagProperties, pagination: Option[Pagination]): MetaData = { val javascriptConfigOverrides: Map[String, JsValue] = Map( ("keywords", JsString(tag.webTitle)), ("keywordIds", JsString(tag.id)), ("references", JsArray(tag.references.map(ref => Reference.toJavaScript(ref.id)))), ) def optionalMapEntry(key: String, o: Option[String]): Map[String, String] = o.map(value => Map(key -> value)).getOrElse(Map()) val openGraphDescription: Option[String] = tag.bio.orElse(tag.description).map(StripHtmlTagsAndUnescapeEntities(_)) val openGraphImage = tag.bylineImageUrl .map(ImgSrc(_, Item140)) .map { s: String => if (s.startsWith("//")) s"http:$s" else s } .orElse(tag.footballBadgeUrl) val openGraphPropertiesOverrides: Map[String, String] = optionalMapEntry("og:description", openGraphDescription) ++ optionalMapEntry("og:image", openGraphImage) MetaData( id = tag.id, webUrl = tag.webUrl, webTitle = tag.webTitle, url = tag.url, section = Some(SectionId.fromId(tag.sectionId)), pillar = None, format = None, designType = None, adUnitSuffix = AdSuffixHandlingForFronts.extractAdUnitSuffixFrom(tag.id, tag.sectionId), description = tag.description, pagination = pagination, contentType = Some(DotcomContentType.Tag), isFront = true, rssPath = Some(s"/${tag.id}/rss"), iosType = tag.sectionId match { case "crosswords" => None case _ => Some("list") }, javascriptConfigOverrides = javascriptConfigOverrides, opengraphPropertiesOverrides = openGraphPropertiesOverrides, twitterPropertiesOverrides = Map("twitter:card" -> "summary"), commercial = tag.commercial, isFoundation = GuardianFoundationHelper.sectionIdIsGuardianFoundation(tag.sectionId), ) } def make(tag: ApiTag, pagination: Option[Pagination] = None): Tag = { val richLinkId = tag.references .find(_.`type` == "rich-link") .map(_.id.stripPrefix("rich-link/")) .filter(_.matches("""https?://www\.theguardian\.com/.*""")) .map(_.stripPrefix("https://www.theguardian.com")) Tag( properties = TagProperties.make(tag), pagination = pagination, richLinkId = richLinkId, ) } implicit val tagWrites: Writes[Tag] = Json.writes[Tag] } object Podcast { def make(podcast: ApiPodcast): Podcast = { Podcast(podcast.subscriptionUrl, podcast.spotifyUrl, podcast.image) } implicit val podcastWrites: Writes[Podcast] = Json.writes[Podcast] } case class Podcast( subscriptionUrl: Option[String], spotifyUrl: Option[String], image: Option[String], ) object Reference { def make(reference: ApiReference): Reference = { Reference( id = reference.id, `type` = reference.`type`, ) } def split(s: String): (String, String) = { val parts = s.split("/") parts(0) -> parts.drop(1).mkString("/") } def toJavaScript(s: String): JsObject = { val (k, v) = split(s) /** Yeah ... so ... in the JavaScript references are represented like this: * * "references":[{"esaFootballTeam":"/football/team/48"},{"optaFootballTournament":"5/2012"}57"} ... ] * * See for example the source of * http://www.theguardian.com/football/live/2014/aug/20/maribor-v-celtic-champions-league-play-off-live-report * * Seems pretty STRANGE. * * TODO: figure out if this is actually being used. If so, refactor it. */ JsObject(Seq(k -> JsString(RelativePathEscaper.escapeLeadingSlashFootballPaths(v)))) } implicit val referenceWrites: Writes[Reference] = Json.writes[Reference] } case class Reference( id: String, `type`: String, ) object TagProperties { def make(tag: ApiTag): TagProperties = { TagProperties( id = tag.id, url = SupportedUrl(tag), tagType = tag.`type`.name, sectionId = tag.sectionId.getOrElse("global"), sectionName = tag.sectionName.getOrElse("global"), webTitle = tag.webTitle, webUrl = tag.webUrl, twitterHandle = tag.twitterHandle, bio = tag.bio, description = tag.description, emailAddress = tag.emailAddress, contributorLargeImagePath = tag.bylineLargeImageUrl, bylineImageUrl = tag.bylineImageUrl, podcast = tag.podcast.map(Podcast.make), references = tag.references.map(Reference.make).toSeq, paidContentType = tag.paidContentType, commercial = Some(CommercialProperties.fromTag(tag)), ) } implicit val tagPropertiesWrites: Writes[TagProperties] = Json.writes[TagProperties] } case class TagProperties( id: String, url: String, tagType: String, sectionId: String, sectionName: String, webTitle: String, webUrl: String, twitterHandle: Option[String], bio: Option[String], description: Option[String], emailAddress: Option[String], contributorLargeImagePath: Option[String], bylineImageUrl: Option[String], podcast: Option[Podcast], references: Seq[Reference], paidContentType: Option[String], commercial: Option[CommercialProperties], ) { val footballBadgeUrl = references .find(_.`type` == "pa-football-team") .map(_.id.split("/").drop(1).mkString("/")) .map(teamId => s"${Configuration.staticSport.path}/football/crests/120/$teamId.png") } case class Tag( properties: TagProperties, pagination: Option[Pagination], richLinkId: Option[String], ) extends StandalonePage { override val metadata: MetaData = Tag.makeMetadata(properties, pagination) def isOfType(typeName: String): Boolean = properties.tagType == typeName || isOfPaidType(typeName) def isOfPaidType(typeName: String): Boolean = properties.paidContentType.contains(typeName) val isContributor: Boolean = metadata.id.startsWith("profile/") val id: String = metadata.id val name: String = metadata.webTitle val isSeries: Boolean = isOfType("Series") val isBlog: Boolean = isOfType("Blog") val isSectionTag: Boolean = SectionTagLookUp.sectionId(metadata.id).contains(metadata.sectionId) val showSeriesInMeta = metadata.id != "childrens-books-site/childrens-books-site" val isKeyword = isOfType("Keyword") || isOfPaidType("Topic") val isFootballTeam = properties.references.exists(_.`type` == "pa-football-team") val isFootballCompetition = properties.references.exists(_.`type` == "pa-football-competition") val contributorImagePath = properties.bylineImageUrl.map(ImgSrc(_, Contributor)) implicit val tagWrites: Writes[Tag] = Json.writes[Tag] }