common/app/views/support/Commercial.scala (249 lines of code) (raw):

package views.support import com.gu.commercial.branding._ import common.Edition import common.commercial._ import layout.{ColumnAndCards, ContentCard, FaciaContainer, PaidCard} import model.DotcomContentType.Signup import model.{ContentType, Page, PressedPage} import org.apache.commons.lang.StringEscapeUtils._ import play.api.libs.json.JsBoolean import play.api.mvc.RequestHeader import play.twirl.api.Html object Commercial { // some users get an ad-free experience def isAdFree(request: RequestHeader): Boolean = { try { request.headers.get("X-GU-Commercial-Ad-Free").exists(_.toLowerCase == "true") || request.cookies.get("GU_AF1").exists(_.value.toLong > 0) } catch { case e: Exception => false // in case the cookie value can't be converted toInt } } def isOnDarkBackground(content: ContentType, isPaidContent: Boolean): Boolean = { content.tags.isGallery || (!isPaidContent && (content.tags.isAudio || content.tags.isVideo)) } // sometimes we don't _want_ to show ads (e.g. on sensitive content) def shouldShowAds(page: Page)(implicit request: RequestHeader): Boolean = { if (request.queryString.get("forceads").isDefined) { true } else { page match { case c: model.ContentPage if c.item.content.shouldHideAdverts => false case p: model.Page if p.metadata.sectionId == "identity" => false case s: model.SimplePage if s.metadata.contentType.contains(Signup) => false case e: model.ContentPage if e.item.content.seriesName.contains("Newsletter sign-ups") => false case _: model.CommercialExpiryPage => false case _ => true } } } def articleAsideOptionalSizes(isShowcase: Boolean)(implicit request: RequestHeader): Seq[String] = { (isShowcase, Edition(request).id) match { case (true, _) => Seq.empty case (false, "US") => Seq("300,600", "fluid", "300,1050") case (false, _) => Seq("300,600", "fluid") } } def glabsLink(request: RequestHeader): String = { val glabsUrlSuffix = Edition(request).id match { case "AU" => "-australia" case "US" => "-us" case _ => "" } s"/guardian-labs$glabsUrlSuffix" } def isPaidContent(page: Page): Boolean = page.metadata.commercial.exists(_.isPaidContent) def isSponsoredContent(page: Page)(implicit request: RequestHeader): Boolean = page.metadata.commercial.exists(_.isSponsored(Edition(request))) def isFoundationFundedContent(page: Page): Boolean = page.metadata.commercial.exists(_.isFoundationFunded) object topAboveNavSlot { // The sizesOverride parameter is for testing only. def cssClasses(metadata: model.MetaData): String = { val topBannerDisableSticky = metadata.javascriptConfigOverrides.get("disableStickyTopBanner") match { case Some(JsBoolean(true)) => Some("top-banner-ad-container--not-sticky") case _ => None } val classes = Seq( "top-banner-ad-container", "js-top-banner", ) ++ topBannerDisableSticky classes mkString " " } val slotCssClasses = Seq("top-banner-ad", "top-banner-ad-desktop") } object container { def shouldRenderAsPaidContainer(isPaidFront: Boolean, optContainerModel: Option[ContainerModel]): Boolean = { def isPaid(containerModel: ContainerModel): Boolean = containerModel.branding exists { case PaidMultiSponsorBranding => true case b: Branding => b.isPaid } !isPaidFront && optContainerModel.exists(isPaid) } def numberOfItems(container: FaciaContainer): Int = container.containerLayout .map { _.slices .flatMap { _.columns.flatMap { case ColumnAndCards(_, cards) => cards.flatMap { _.item match { case card: ContentCard => Some(card) case _ => None } } } } .length } .getOrElse(0) def isFirstNonThrasherContainer(containerIndex: Int, containers: Seq[FaciaContainer]): Boolean = (containers filterNot (_.isThrasher) map (_.index)).min == containerIndex } object CssClassBuilder { private def cardLink( cardContent: PaidCard, adClasses: Option[Seq[String]], sizeClass: Option[String], useCardBranding: Boolean, ): String = { val classes: Seq[String] = Seq( "vergadain", sizeClass getOrElse "", "vergadain--capi", cardContent.icon map (_ => "vergadain--media") getOrElse "vergadain--text", adClasses.map(_.map(c => s"vergadain--$c").mkString(" ")).getOrElse(""), if (useCardBranding) "vergadain--branded" else "", ) classes mkString " " } def linkFromStandardCard( cardContent: PaidCard, adClasses: Option[Seq[String]], useCardBranding: Boolean, ): String = { cardLink(cardContent, adClasses, sizeClass = None, useCardBranding) } def linkFromSmallCard( cardContent: PaidCard, adClasses: Option[Seq[String]], useCardBranding: Boolean, ): String = { cardLink(cardContent, adClasses, sizeClass = Some("vergadain--small"), useCardBranding) } def linkFromLargeCard( cardContent: PaidCard, adClasses: Option[Seq[String]], useCardBranding: Boolean, ): String = { cardLink(cardContent, adClasses, sizeClass = Some("vergadain--large"), useCardBranding) } def paidForContainer(otherClasses: Option[Seq[String]]): String = "paidfor-container " + otherClasses.map(_.mkString(" ")).getOrElse("") } object TrackingCodeBuilder extends implicits.Requests { private def mkString( containerType: String, editionId: String, frontId: String, containerIndex: Int, containerTitle: String, sponsorName: String, cardIndex: Int, cardTitle: String, ) = Seq( containerType, editionId, frontId, s"container-${containerIndex + 1}", containerTitle, sponsorName, s"card-${cardIndex + 1}", cardTitle, ) mkString " | " def mkInteractionTrackingCode( frontId: String, containerIndex: Int, container: ContainerModel, )(implicit request: RequestHeader): String = mkString( containerType = "Labs front container", editionId = Edition(request).id, frontId = frontId, containerIndex = containerIndex, containerTitle = container.content.title, sponsorName = { val containerSponsorName = container.branding collect { case b: Branding => b.sponsorName } containerSponsorName getOrElse "" }, cardIndex = -1, cardTitle = container.content.title, ) def mkInteractionTrackingCode( frontId: String, containerIndex: Int, container: ContainerModel, card: PaidCard, )(implicit request: RequestHeader): String = mkString( containerType = "Labs front container", editionId = Edition(request).id, frontId = frontId, containerIndex = containerIndex, containerTitle = container.content.title, sponsorName = { val containerSponsorName = container.branding collect { case b: Branding => b.sponsorName } containerSponsorName orElse card.branding.map(_.sponsorName) getOrElse "" }, cardIndex = (container.content.initialCards ++ container.content.showMoreCards) .indexWhere(_.headline == card.headline), cardTitle = card.headline, ) def mkInteractionTrackingCode( containerIndex: Int, cardIndex: Int, card: ContentCard, containerDisplayName: Option[String], frontId: Option[String], )(implicit request: RequestHeader): String = { val isContentPage = containerDisplayName.contains("More on this story") || containerDisplayName.contains("Related content") mkString( containerType = if (isContentPage) "Onward container" else "Front container", editionId = Edition(request).id, frontId = frontId.filter(_.nonEmpty).getOrElse("unknown front id"), containerIndex = containerIndex, containerTitle = containerDisplayName.getOrElse("unknown container"), sponsorName = card.branding.map(_.sponsorName) getOrElse "unknown", cardIndex = cardIndex, cardTitle = card.header.headline, ) } def mkCapiCardTrackingCode( multiplicity: String, optSection: Option[String], optContainerTitle: Option[String], omnitureId: String, card: PaidCard, )(implicit request: RequestHeader): String = { Seq( "merchandising", "capi", multiplicity, optSection.getOrElse(""), optContainerTitle.getOrElse(""), omnitureId, card.branding.map(_.sponsorName).getOrElse(""), card.headline, ) mkString " | " } def paidCard(articleTitle: String)(implicit request: RequestHeader): String = { def param(name: String) = request.getParameter(name) getOrElse "unknown" val section = param("s") val sponsor = param("brand") s"GLabs-native-traffic-card | ${Edition(request).id} | $section | $articleTitle | $sponsor" } } }