Skip to content

Commit

Permalink
Merge pull request #2639 from guardian/stop-stripe-fraud-detection
Browse files Browse the repository at this point in the history
A/B test disabling Stripe's fraud detection
  • Loading branch information
paulbrown1982 committed Aug 4, 2020
2 parents db25a19 + 2894193 commit b28d95e
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 64 deletions.
28 changes: 18 additions & 10 deletions support-frontend/app/admin/ServersideAbTest.scala
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
package admin
import cookies.ServersideAbTestCookie
import play.api.mvc.RequestHeader
import admin.ServersideAbTest.Participation
import io.circe.Encoder

import scala.util.Random

object ServersideAbTest {
// Serverside A/B tests currently only support a single concurrent test
// running to 100% audience with a 50%/50% split
def getParticipation(implicit request: RequestHeader): Participation = {
ServersideAbTestCookie.get.flatMap(_.value match {
case "Control" => Some(Control)
case "Variant" => Some(Variant)
case _ => None
}).getOrElse(computeParticipation)
}

private def computeParticipation: Participation = if (Random.nextBoolean) Control else Variant
def generateParticipations(testNames: List[String]): Map[String, Participation] =
testNames.map(_ -> computeParticipation).toMap

def computeParticipation: Participation = if (Random.nextBoolean) Control else Variant

sealed trait Participation
case object Control extends Participation
case object Variant extends Participation

object Participation {
implicit val encoder = Encoder.encodeString.contramap[Participation] {
case Control => "Control"
case Variant => "Variant"
}
}

import io.circe.syntax._
implicit val encoder = Encoder[Map[String,Participation]]

val asJsonString: Map[String,Participation] => String = _.asJson.noSpaces
}
15 changes: 9 additions & 6 deletions support-frontend/app/controllers/Application.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controllers

import actions.CustomActionBuilders
import admin.ServersideAbTest.generateParticipations
import admin.settings.{AllSettings, AllSettingsProvider, SettingsSurrogateKeySyntax}
import assets.{AssetsResolver, RefPath, StyleContent}
import cats.data.EitherT
Expand All @@ -14,7 +15,6 @@ import com.gu.support.config._
import com.typesafe.scalalogging.StrictLogging
import config.Configuration.GuardianDomain
import config.{RecaptchaConfigProvider, StringsConfig}
import cookies.ServersideAbTestCookie
import lib.RedirectWithEncodedQueryString
import models.GeoData
import play.api.mvc._
Expand Down Expand Up @@ -54,7 +54,7 @@ class Application(
val supportUrl: String,
fontLoaderBundle: Either[RefPath, StyleContent]
)(implicit val ec: ExecutionContext) extends AbstractController(components)
with SettingsSurrogateKeySyntax with CanonicalLinks with StrictLogging with ServersideAbTestCookie {
with SettingsSurrogateKeySyntax with CanonicalLinks with StrictLogging {

import actionRefiners._

Expand Down Expand Up @@ -136,9 +136,9 @@ class Application(

implicit val settings: AllSettings = settingsProvider.getAllSettings()
request.user.traverse[Attempt, IdUser](user => identityService.getUser(user.minimalUser)).fold(
_ => Ok(contributionsHtml(countryCode, geoData, None, campaignCodeOption, guestAccountCreationToken)),
user => Ok(contributionsHtml(countryCode, geoData, user, campaignCodeOption, guestAccountCreationToken))
).map(_.withSettingsSurrogateKey)
_ => Ok(contributionsHtml(countryCode, geoData, None, campaignCodeOption, guestAccountCreationToken)),
user => Ok(contributionsHtml(countryCode, geoData, user, campaignCodeOption, guestAccountCreationToken))
).map(_.withSettingsSurrogateKey)
}

private def shareImageUrl(settings: AllSettings): String = {
Expand Down Expand Up @@ -173,6 +173,8 @@ class Application(
classes = Some(classes)
)

val serversideTests = generateParticipations(List("stripeFraudDetection"))

views.html.contributions(
title = "Support the Guardian | Make a Contribution",
id = s"contributions-landing-page-$countryCode",
Expand All @@ -199,7 +201,8 @@ class Application(
geoData = geoData,
shareImageUrl = shareImageUrl(settings),
shareUrl = "https://support.theguardian.com/contribute",
v2recaptchaConfigPublicKey = recaptchaConfigProvider.v2PublicKey
v2recaptchaConfigPublicKey = recaptchaConfigProvider.v2PublicKey,
serversideTests = serversideTests
)
}

Expand Down
44 changes: 0 additions & 44 deletions support-frontend/app/cookies/ServersideAbTestCookie.scala

This file was deleted.

8 changes: 5 additions & 3 deletions support-frontend/app/views/contributions.scala.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import admin.settings.AllSettings
@import admin.ServersideAbTest.{Participation, Variant}
@import assets.{AssetsResolver, RefPath, StyleContent}
@import com.gu.i18n.Country
@import com.gu.identity.model.{User => IdUser}
Expand Down Expand Up @@ -26,9 +27,10 @@
shareImageUrl: String,
shareUrl: String,
v2recaptchaConfigPublicKey: String,
serversideTests: Map[String, Participation] = Map()
)(implicit assets: AssetsResolver, request: RequestHeader, settings: AllSettings)

@main(title = title, mainJsBundle = js, fontLoaderBundle = fontLoaderBundle, description = description, mainElement = mainElement, mainStyleBundle = css, shareImageUrl = Some(shareImageUrl), shareUrl = Some(shareUrl)) {
@main(title = title, mainJsBundle = js, fontLoaderBundle = fontLoaderBundle, description = description, mainElement = mainElement, mainStyleBundle = css, shareImageUrl = Some(shareImageUrl), shareUrl = Some(shareUrl), serversideTests = serversideTests) {
<script type="text/javascript">
window.guardian = window.guardian || {};
@idUser.map { user =>
Expand Down Expand Up @@ -113,7 +115,7 @@
window.guardian.ausMomentEnabled = @settings.switches.experiments.get("ausMomentEnabled").exists(_.isOn)

window.guardian.recaptchaEnabled = @settings.switches.enableRecaptchaFrontend.isOn
window.guardian.v2recaptchaPublicKey = "@v2recaptchaConfigPublicKey"
window.guardian.v2recaptchaPublicKey = "@v2recaptchaConfigPublicKey";
</script>
<script defer id="stripe-js" src="https://js.stripe.com/v3/"></script>
<script defer id="stripe-js" src=@{s"https://js.stripe.com/v3/${if (serversideTests.get("stripeFraudDetection").contains(Variant)) "?advancedFraudSignals=false" else ""}"}></script>"
}
4 changes: 4 additions & 0 deletions support-frontend/app/views/main.scala.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import admin.settings.AllSettings
@import admin.ServersideAbTest.{Participation, asJsonString}
@import assets.{AssetsResolver, RefPath, StyleContent}
@import views.{EmptyDiv, Preload, ReactDiv, SSRContent}
@import scala.util.Random
Expand All @@ -14,6 +15,7 @@
csrf: Option[String] = None,
shareImageUrl: Option[String] = None,
shareUrl: Option[String] = None,
serversideTests: Map[String,Participation] = Map()
)(body: Html = Html(""))(implicit assets: AssetsResolver, request: RequestHeader, settings: AllSettings)

<!DOCTYPE html>
Expand Down Expand Up @@ -62,6 +64,8 @@

@settingsScript(settings)

<script>window.guardian.serversideTests = @Html(asJsonString(serversideTests))</script>

<title>@title</title>
<meta property="og:title" content="@title"/>

Expand Down
14 changes: 13 additions & 1 deletion support-frontend/assets/helpers/abTests/abtest.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ function getParticipationsFromUrl(): ?Participations {
return null;
}

function getServerSideParticipations(): ?Participations {
if (window && window.guardian && window.guardian.serversideTests) {
return window.guardian.serversideTests;
}
return null;
}

function getIsRemoteFromAcquisitionData(): boolean {
const queryString = getQueryParameter('acquisitionData');

Expand Down Expand Up @@ -336,7 +343,12 @@ const init = (
const mvt: number = getMvtId();
const participations: Participations = getParticipations(abTests, mvt, country, countryGroupId);
const urlParticipations: ?Participations = getParticipationsFromUrl();
const combinedParticipations: Participations = { ...participations, ...urlParticipations };
const serverSideParticipations: ?Participations = getServerSideParticipations();
const combinedParticipations: Participations = {
...participations,
...urlParticipations,
...serverSideParticipations
};
setLocalStorageParticipations(combinedParticipations);

return combinedParticipations;
Expand Down

0 comments on commit b28d95e

Please sign in to comment.