{"action":"created","comment":{"url":"https://api.github.com/repos/guardian/frontend/pulls/comments/44772531","id":44772531,"diff_hunk":"@@ -0,0 +1,100 @@\n+package controllers\n+\n+import common.ExecutionContexts\n+import conf.Configuration\n+import model._\n+import play.api.Play.current\n+import play.api.data._\n+import play.api.data.validation.Constraints.emailAddress\n+import play.api.data.Forms._\n+import play.api.libs.ws.{WSResponse, WS}\n+import play.api.libs.json._\n+import play.api.mvc.{Result, Action, Controller}\n+import model.MetaData\n+\n+import scala.concurrent.Future\n+\n+object emailLandingPage extends MetaData {\n+  lazy val id: String = \"email-landing-page\"\n+  lazy val section: String = \"\"\n+  lazy val analyticsName: String = id\n+  lazy val webTitle: String = \"Email Landing Page\"\n+}\n+\n+case class EmailPage(interactive: Interactive, related: RelatedContent)\n+\n+case class EmailForm(email: String)\n+\n+object EmailForm {\n+  val listTriggers = Map(\n+    3485 -> 2529\n+  )\n+\n+  def submit(form: EmailForm, listId: Int): Option[Future[WSResponse]] = {\n+    listTriggers.get(listId).map { triggerId =>\n+      WS.url(Configuration.emailSignup.url).post(Json.obj(\n+        \"email\" -> form.email,\n+        \"listId\" -> listId,\n+        \"triggerId\" -> triggerId\n+      ))\n+    }\n+  }\n+}\n+\n+object EmailController extends Controller with ExecutionContexts {\n+  val emailForm: Form[EmailForm] = Form(\n+    mapping(\n+      \"email\" -> nonEmptyText.verifying(emailAddress)\n+    )(EmailForm.apply)(EmailForm.unapply)\n+  )\n+\n+  def renderPage() = Action { implicit request =>\n+    Ok(views.html.emailLanding(emailLandingPage))\n+  }\n+\n+  def renderForm() = Action { implicit request =>\n+    Ok(views.html.emailFragment(emailLandingPage))\n+  }\n+\n+  def submit() = Action.async { implicit request =>\n+    val listId = 3485\n+\n+    emailForm.bindFromRequest.fold(\n+      formWithErrors => {\n+        val result = FailedToSubscribe(\"Invalid email address\")\n+\n+        Future(render {\n+          case Accepts.Html() => BadRequest(views.html.emailLanding(emailLandingPage, Some(result)))\n+          case Accepts.Json() => BadRequest(result.message)\n+        })\n+      },\n+\n+      form => EmailForm.submit(form, listId) match {\n+        case Some(future) => future.map(_.status match {\n+          case 200 | 201 => render {\n+            case Accepts.Html() => Created(views.html.emailLanding(emailLandingPage, Some(Subscribed)))\n+            case Accepts.Json() => Created(Json.obj(\"email\" -> form.email))\n+          }\n+\n+          case _ => {","path":"applications/app/controllers/EmailController.scala","position":79,"original_position":79,"commit_id":"a9da1f58a3eaa7d51396dfc139e4ebfc37dac787","original_commit_id":"a9da1f58a3eaa7d51396dfc139e4ebfc37dac787","user":{"login":"janua","id":445472,"avatar_url":"https://avatars.githubusercontent.com/u/445472?v=3","gravatar_id":"","url":"https://api.github.com/users/janua","html_url":"https://github.com/janua","followers_url":"https://api.github.com/users/janua/followers","following_url":"https://api.github.com/users/janua/following{/other_user}","gists_url":"https://api.github.com/users/janua/gists{/gist_id}","starred_url":"https://api.github.com/users/janua/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/janua/subscriptions","organizations_url":"https://api.github.com/users/janua/orgs","repos_url":"https://api.github.com/users/janua/repos","events_url":"https://api.github.com/users/janua/events{/privacy}","received_events_url":"https://api.github.com/users/janua/received_events","type":"User","site_admin":false},"body":"Why underscore? This should be `None`.","created_at":"2015-11-13T11:17:41Z","updated_at":"2015-11-13T11:17:41Z","html_url":"https://github.com/guardian/frontend/pull/11114#discussion_r44772531","pull_request_url":"https://api.github.com/repos/guardian/frontend/pulls/11114","_links":{"self":{"href":"https://api.github.com/repos/guardian/frontend/pulls/comments/44772531"},"html":{"href":"https://github.com/guardian/frontend/pull/11114#discussion_r44772531"},"pull_request":{"href":"https://api.github.com/repos/guardian/frontend/pulls/11114"}}},"pull_request":{"url":"https://api.github.com/repos/guardian/frontend/pulls/11114","id":50549089,"html_url":"https://github.com/guardian/frontend/pull/11114","diff_url":"https://github.com/guardian/frontend/pull/11114.diff","patch_url":"https://github.com/guardian/frontend/pull/11114.patch","issue_url":"https://api.github.com/repos/guardian/frontend/issues/11114","number":11114,"state":"open","locked":false,"title":"Email sign-up - Inline form, routes and iFrame fragment. ","user":{"login":"gtrufitt","id":638051,"avatar_url":"https://avatars.githubusercontent.com/u/638051?v=3","gravatar_id":"","url":"https://api.github.com/users/gtrufitt","html_url":"https://github.com/gtrufitt","followers_url":"https://api.github.com/users/gtrufitt/followers","following_url":"https://api.github.com/users/gtrufitt/following{/other_user}","gists_url":"https://api.github.com/users/gtrufitt/gists{/gist_id}","starred_url":"https://api.github.com/users/gtrufitt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gtrufitt/subscriptions","organizations_url":"https://api.github.com/users/gtrufitt/orgs","repos_url":"https://api.github.com/users/gtrufitt/repos","events_url":"https://api.github.com/users/gtrufitt/events{/privacy}","received_events_url":"https://api.github.com/users/gtrufitt/received_events","type":"User","site_admin":false},"body":"# Right Thing, Right Time: Inline email sign-up\r\n\r\n*Note:* This is a biggun.. It's a counterpart to @janua and @desbo's work on hooking into the email provider API. Please shout if there is anything that look remotely strange or not to code style or architecturally weird. @desbo also wrote most of the scala on this one :dancers: \r\n\r\n## SHOW ME PICTURES\r\n\r\n![image](https://cloud.githubusercontent.com/assets/638051/11127332/c3f9799c-896b-11e5-9f00-3e8fe23f7f7f.png)\r\n\r\n## Security & iframe\r\n\r\nWe use an iframe to protect against third party scripts from listening to `keydown` and leaking those key presses to a malicious script (say an sneaky ad with a frame buster). The email-form will be delivered over https to prevent man in the middle attacks on the actual form, as well as `POST`ing to an https endpoint.\r\n\r\n## Endpoints\r\n\r\nWe have three new endpoints:\r\n\r\n- `GET /email` - This returns our new email landing page. Initially we won't be linking to this from anywhere so it's slightly sparse, but will become the *place to be* for signing up to the **best** emails news has to offer.\r\n- `POST /email` - This is where our new endpoint posts to. It is a proxy for @janua's endpoint and currently just forwards on the request and, depending on the response, returns us the relevant result.\r\n- `GET /email-form` - This endpoint returns a page that contains only our form html and the css required to style it (CSS doesn't leak through iframes, even on the same domain). See below for more about the new `mainFragment.scala.html`.\r\n\r\n## CSS\r\n\r\nThe form CSS currently has two modifiers - `--landing` and `--footer`. In future, we'll probably have further modifiers for our email module (or, probably, these modifications will become more generic to ensure consistency). Eg: 'in-article' inline email sign-up, which requires further style mods.\r\n\r\n## Fragments and Templates\r\n\r\n### Email Fragments\r\n\r\nThe email fragments are split into email and heading, allowing these to be included together or individually where required. Initially there is HTML5 form validation using the email input, it's possible that we'll need js validation for IE9.\r\n\r\n### MainFragment\r\n\r\nThere is a new main container that contains nothing but html, head and body. And, at the moment, the email styles inline - if it is likely that this will be used elsewhere (to include other small snippets of mark-up inside of iframes), then it probably makes sense to make this generic (and probably include the current `projectName`'s css file into the iframe to make use of the cache).\r\n\r\n## A/B Test\r\n\r\nWe're going to be A/B/C/D/Etc testing this - the initial A/B test has functionality to swap out the headline and remove the 'comforter' message ('no spam. one click unsubscribe')\r\n\r\nIt is currently set at 0% of users to allow the team to opt-in and test before rolling out to users.\r\n\r\n## TODO\r\n\r\nThis is the current TODO list before merge:\r\n\r\n- [ ] Understand and update email routes in Fastly to allow https\r\n- [ ] Tidy up the landing page and remove placeholder image\r\n- [ ] Fix footer in IE9 (IE9 doesn't support cols so currently collapses)\r\n- [ ] Add 'Submit onclick' and 'Thank-you page shown' tracking within the iframe\r\n\r\n:sparkles:","created_at":"2015-11-12T18:33:54Z","updated_at":"2015-11-13T11:17:41Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/guardian/frontend/pulls/11114/commits","review_comments_url":"https://api.github.com/repos/guardian/frontend/pulls/11114/comments","review_comment_url":"https://api.github.com/repos/guardian/frontend/pulls/comments{/number}","comments_url":"https://api.github.com/repos/guardian/frontend/issues/11114/comments","statuses_url":"https://api.github.com/repos/guardian/frontend/statuses/a9da1f58a3eaa7d51396dfc139e4ebfc37dac787","head":{"label":"guardian:RTRT_Email-Sign-up","ref":"RTRT_Email-Sign-up","sha":"a9da1f58a3eaa7d51396dfc139e4ebfc37dac787","user":{"login":"guardian","id":164318,"avatar_url":"https://avatars.githubusercontent.com/u/164318?v=3","gravatar_id":"","url":"https://api.github.com/users/guardian","html_url":"https://github.com/guardian","followers_url":"https://api.github.com/users/guardian/followers","following_url":"https://api.github.com/users/guardian/following{/other_user}","gists_url":"https://api.github.com/users/guardian/gists{/gist_id}","starred_url":"https://api.github.com/users/guardian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guardian/subscriptions","organizations_url":"https://api.github.com/users/guardian/orgs","repos_url":"https://api.github.com/users/guardian/repos","events_url":"https://api.github.com/users/guardian/events{/privacy}","received_events_url":"https://api.github.com/users/guardian/received_events","type":"Organization","site_admin":false},"repo":{"id":4370755,"name":"frontend","full_name":"guardian/frontend","owner":{"login":"guardian","id":164318,"avatar_url":"https://avatars.githubusercontent.com/u/164318?v=3","gravatar_id":"","url":"https://api.github.com/users/guardian","html_url":"https://github.com/guardian","followers_url":"https://api.github.com/users/guardian/followers","following_url":"https://api.github.com/users/guardian/following{/other_user}","gists_url":"https://api.github.com/users/guardian/gists{/gist_id}","starred_url":"https://api.github.com/users/guardian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guardian/subscriptions","organizations_url":"https://api.github.com/users/guardian/orgs","repos_url":"https://api.github.com/users/guardian/repos","events_url":"https://api.github.com/users/guardian/events{/privacy}","received_events_url":"https://api.github.com/users/guardian/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/guardian/frontend","description":"Source for theguardian.com","fork":false,"url":"https://api.github.com/repos/guardian/frontend","forks_url":"https://api.github.com/repos/guardian/frontend/forks","keys_url":"https://api.github.com/repos/guardian/frontend/keys{/key_id}","collaborators_url":"https://api.github.com/repos/guardian/frontend/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/guardian/frontend/teams","hooks_url":"https://api.github.com/repos/guardian/frontend/hooks","issue_events_url":"https://api.github.com/repos/guardian/frontend/issues/events{/number}","events_url":"https://api.github.com/repos/guardian/frontend/events","assignees_url":"https://api.github.com/repos/guardian/frontend/assignees{/user}","branches_url":"https://api.github.com/repos/guardian/frontend/branches{/branch}","tags_url":"https://api.github.com/repos/guardian/frontend/tags","blobs_url":"https://api.github.com/repos/guardian/frontend/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/guardian/frontend/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/guardian/frontend/git/refs{/sha}","trees_url":"https://api.github.com/repos/guardian/frontend/git/trees{/sha}","statuses_url":"https://api.github.com/repos/guardian/frontend/statuses/{sha}","languages_url":"https://api.github.com/repos/guardian/frontend/languages","stargazers_url":"https://api.github.com/repos/guardian/frontend/stargazers","contributors_url":"https://api.github.com/repos/guardian/frontend/contributors","subscribers_url":"https://api.github.com/repos/guardian/frontend/subscribers","subscription_url":"https://api.github.com/repos/guardian/frontend/subscription","commits_url":"https://api.github.com/repos/guardian/frontend/commits{/sha}","git_commits_url":"https://api.github.com/repos/guardian/frontend/git/commits{/sha}","comments_url":"https://api.github.com/repos/guardian/frontend/comments{/number}","issue_comment_url":"https://api.github.com/repos/guardian/frontend/issues/comments{/number}","contents_url":"https://api.github.com/repos/guardian/frontend/contents/{+path}","compare_url":"https://api.github.com/repos/guardian/frontend/compare/{base}...{head}","merges_url":"https://api.github.com/repos/guardian/frontend/merges","archive_url":"https://api.github.com/repos/guardian/frontend/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/guardian/frontend/downloads","issues_url":"https://api.github.com/repos/guardian/frontend/issues{/number}","pulls_url":"https://api.github.com/repos/guardian/frontend/pulls{/number}","milestones_url":"https://api.github.com/repos/guardian/frontend/milestones{/number}","notifications_url":"https://api.github.com/repos/guardian/frontend/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/guardian/frontend/labels{/name}","releases_url":"https://api.github.com/repos/guardian/frontend/releases{/id}","created_at":"2012-05-18T15:39:15Z","updated_at":"2015-11-12T12:05:34Z","pushed_at":"2015-11-13T11:16:54Z","git_url":"git://github.com/guardian/frontend.git","ssh_url":"git@github.com:guardian/frontend.git","clone_url":"https://github.com/guardian/frontend.git","svn_url":"https://github.com/guardian/frontend","homepage":"http://www.theguardian.com","size":519781,"stargazers_count":3018,"watchers_count":3018,"language":"HTML","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":299,"mirror_url":null,"open_issues_count":45,"forks":299,"open_issues":45,"watchers":3018,"default_branch":"master"}},"base":{"label":"guardian:master","ref":"master","sha":"70937d887024b0cfc0d287d6d8702128bff7b262","user":{"login":"guardian","id":164318,"avatar_url":"https://avatars.githubusercontent.com/u/164318?v=3","gravatar_id":"","url":"https://api.github.com/users/guardian","html_url":"https://github.com/guardian","followers_url":"https://api.github.com/users/guardian/followers","following_url":"https://api.github.com/users/guardian/following{/other_user}","gists_url":"https://api.github.com/users/guardian/gists{/gist_id}","starred_url":"https://api.github.com/users/guardian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guardian/subscriptions","organizations_url":"https://api.github.com/users/guardian/orgs","repos_url":"https://api.github.com/users/guardian/repos","events_url":"https://api.github.com/users/guardian/events{/privacy}","received_events_url":"https://api.github.com/users/guardian/received_events","type":"Organization","site_admin":false},"repo":{"id":4370755,"name":"frontend","full_name":"guardian/frontend","owner":{"login":"guardian","id":164318,"avatar_url":"https://avatars.githubusercontent.com/u/164318?v=3","gravatar_id":"","url":"https://api.github.com/users/guardian","html_url":"https://github.com/guardian","followers_url":"https://api.github.com/users/guardian/followers","following_url":"https://api.github.com/users/guardian/following{/other_user}","gists_url":"https://api.github.com/users/guardian/gists{/gist_id}","starred_url":"https://api.github.com/users/guardian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guardian/subscriptions","organizations_url":"https://api.github.com/users/guardian/orgs","repos_url":"https://api.github.com/users/guardian/repos","events_url":"https://api.github.com/users/guardian/events{/privacy}","received_events_url":"https://api.github.com/users/guardian/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/guardian/frontend","description":"Source for theguardian.com","fork":false,"url":"https://api.github.com/repos/guardian/frontend","forks_url":"https://api.github.com/repos/guardian/frontend/forks","keys_url":"https://api.github.com/repos/guardian/frontend/keys{/key_id}","collaborators_url":"https://api.github.com/repos/guardian/frontend/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/guardian/frontend/teams","hooks_url":"https://api.github.com/repos/guardian/frontend/hooks","issue_events_url":"https://api.github.com/repos/guardian/frontend/issues/events{/number}","events_url":"https://api.github.com/repos/guardian/frontend/events","assignees_url":"https://api.github.com/repos/guardian/frontend/assignees{/user}","branches_url":"https://api.github.com/repos/guardian/frontend/branches{/branch}","tags_url":"https://api.github.com/repos/guardian/frontend/tags","blobs_url":"https://api.github.com/repos/guardian/frontend/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/guardian/frontend/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/guardian/frontend/git/refs{/sha}","trees_url":"https://api.github.com/repos/guardian/frontend/git/trees{/sha}","statuses_url":"https://api.github.com/repos/guardian/frontend/statuses/{sha}","languages_url":"https://api.github.com/repos/guardian/frontend/languages","stargazers_url":"https://api.github.com/repos/guardian/frontend/stargazers","contributors_url":"https://api.github.com/repos/guardian/frontend/contributors","subscribers_url":"https://api.github.com/repos/guardian/frontend/subscribers","subscription_url":"https://api.github.com/repos/guardian/frontend/subscription","commits_url":"https://api.github.com/repos/guardian/frontend/commits{/sha}","git_commits_url":"https://api.github.com/repos/guardian/frontend/git/commits{/sha}","comments_url":"https://api.github.com/repos/guardian/frontend/comments{/number}","issue_comment_url":"https://api.github.com/repos/guardian/frontend/issues/comments{/number}","contents_url":"https://api.github.com/repos/guardian/frontend/contents/{+path}","compare_url":"https://api.github.com/repos/guardian/frontend/compare/{base}...{head}","merges_url":"https://api.github.com/repos/guardian/frontend/merges","archive_url":"https://api.github.com/repos/guardian/frontend/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/guardian/frontend/downloads","issues_url":"https://api.github.com/repos/guardian/frontend/issues{/number}","pulls_url":"https://api.github.com/repos/guardian/frontend/pulls{/number}","milestones_url":"https://api.github.com/repos/guardian/frontend/milestones{/number}","notifications_url":"https://api.github.com/repos/guardian/frontend/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/guardian/frontend/labels{/name}","releases_url":"https://api.github.com/repos/guardian/frontend/releases{/id}","created_at":"2012-05-18T15:39:15Z","updated_at":"2015-11-12T12:05:34Z","pushed_at":"2015-11-13T11:16:54Z","git_url":"git://github.com/guardian/frontend.git","ssh_url":"git@github.com:guardian/frontend.git","clone_url":"https://github.com/guardian/frontend.git","svn_url":"https://github.com/guardian/frontend","homepage":"http://www.theguardian.com","size":519781,"stargazers_count":3018,"watchers_count":3018,"language":"HTML","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":299,"mirror_url":null,"open_issues_count":45,"forks":299,"open_issues":45,"watchers":3018,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/guardian/frontend/pulls/11114"},"html":{"href":"https://github.com/guardian/frontend/pull/11114"},"issue":{"href":"https://api.github.com/repos/guardian/frontend/issues/11114"},"comments":{"href":"https://api.github.com/repos/guardian/frontend/issues/11114/comments"},"review_comments":{"href":"https://api.github.com/repos/guardian/frontend/pulls/11114/comments"},"review_comment":{"href":"https://api.github.com/repos/guardian/frontend/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/guardian/frontend/pulls/11114/commits"},"statuses":{"href":"https://api.github.com/repos/guardian/frontend/statuses/a9da1f58a3eaa7d51396dfc139e4ebfc37dac787"}}}}