Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to ping members-data-api to update user details #97

Merged
merged 3 commits into from
Apr 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package controllers
import play.api.libs.concurrent.Execution.Implicits._
import services.{IdentityAuthService, AuthenticationService}
import com.gu.memsub._
import json.PaymentCardUpdateResultWriters._
import com.gu.services.model.PaymentDetails
import configuration.Config
import models.ApiErrors._
import play.api.data.Form
import play.api.data.Forms._
import play.api.libs.json.Json
import play.api.mvc.Results._
import play.filters.cors.CORSActionBuilder
import scalaz.std.scalaFuture._
import scala.concurrent.Future
import models.AccountDetails._
import scalaz.OptionT
import actions._


class AccountController {

lazy val authenticationService: AuthenticationService = IdentityAuthService
lazy val corsCardFilter = CORSActionBuilder(Config.mmaCardCorsConfig)
lazy val mmaCorsFilter = CORSActionBuilder(Config.mmaCorsConfig)
lazy val mmaAction = mmaCorsFilter andThen BackendFromCookieAction
lazy val mmaCardAction = corsCardFilter andThen BackendFromCookieAction

def updateCard(implicit product: ProductFamily) = mmaCardAction.async { implicit request =>
val updateForm = Form { single("stripeToken" -> nonEmptyText) }
val tp = request.touchpoint

(for {
user <- OptionT(Future.successful(authenticationService.userId))
sfUser <- OptionT(tp.contactRepo.get(user))
subscription <- OptionT(tp.subService.get(sfUser))
stripeCardToken <- OptionT(Future.successful(updateForm.bindFromRequest().value))
updateResult <- OptionT(tp.paymentService.setPaymentCardWithStripeToken(subscription.accountId, stripeCardToken))
} yield updateResult match {
case success: CardUpdateSuccess => Ok(Json.toJson(success))
case failure: CardUpdateFailure => Forbidden(Json.toJson(failure))
}).run.map(_.getOrElse(notFound))
}

def paymentDetails(implicit product: ProductFamily) = mmaAction.async { implicit request =>
(for {
user <- OptionT(Future.successful(authenticationService.userId))
contact <- OptionT(request.touchpoint.contactRepo.get(user))
sub <- OptionT(request.touchpoint.subService.getEither(contact))
details <- OptionT(request.touchpoint.paymentService.paymentDetails(sub).map[Option[PaymentDetails]](Some(_)))
} yield (contact, details).toResult).run.map(_ getOrElse Ok(Json.obj()))
}

def membershipUpdateCard = updateCard(Membership)
def digitalPackUpdateCard = updateCard(Digipack)

def membershipDetails = paymentDetails(Membership)
def digitalPackDetails = paymentDetails(Digipack)
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,53 @@
package controllers

import com.gu.memsub._
import com.gu.services.model.PaymentDetails
import com.typesafe.scalalogging.LazyLogging
import configuration.Config
import models.ApiError._
import models.ApiErrors._
import models.Features._
import actions._
import models._
import monitoring.CloudWatch
import play.api.data.Form
import play.api.data.Forms._
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.json.Json
import play.api.mvc.Result
import play.filters.cors.CORSActionBuilder
import play.api.mvc.{Controller, Result}
import _root_.services.{AuthenticationService, IdentityAuthService}
import models.AccountDetails._
import play.filters.cors.CORSActionBuilder
import scala.concurrent.Future
import scalaz.OptionT
import scalaz.{\/, EitherT}
import scalaz.std.scalaFuture._
import play.api.mvc.Results.{Ok, Forbidden}
import json.PaymentCardUpdateResultWriters._
import scalaz.syntax.std.option._

class AttributeController {

lazy val authenticationService: AuthenticationService = IdentityAuthService
lazy val mmaCorsFilter = CORSActionBuilder(Config.mmaCorsConfig)

class AttributeController extends Controller with LazyLogging {

lazy val corsFilter = CORSActionBuilder(Config.corsConfig)
lazy val corsCardFilter = CORSActionBuilder(Config.mmaCardCorsConfig)
lazy val backendAction = corsFilter andThen BackendFromCookieAction
lazy val mmaAction = mmaCorsFilter andThen BackendFromCookieAction
lazy val mmaCardAction = corsCardFilter andThen BackendFromCookieAction
lazy val authenticationService: AuthenticationService = IdentityAuthService
lazy val metrics = CloudWatch("AttributesController")

def update = BackendFromCookieAction.async { implicit request =>

val result: EitherT[Future, String, Attributes] = for {
id <- EitherT(Future.successful(authenticationService.userId \/> "No user"))
contact <- EitherT(request.touchpoint.contactRepo.get(id).map(_ \/> s"No contact for $id"))
sub <- EitherT(request.touchpoint.membershipSubscriptionService.get(contact)(Membership).map(_ \/> s"No sub for $id"))
attributes = Attributes(id, sub.plan.tier.name, contact.regNumber)
res <- EitherT(request.touchpoint.attrService.set(attributes).map(\/.right))
} yield attributes

result.run.map(_.fold(
error => {
logger.error(s"Failed to update attributes - $error")
ApiErrors.badRequest(error)
},
attributes => {
logger.info(s"${attributes.userId} -> ${attributes.tier}")
Ok(Json.obj("updated" -> true))
}
))
}

private def lookup(endpointDescription: String, onSuccess: Attributes => Result, onNotFound: Result = notFound) = backendAction.async { request =>
authenticationService.userId(request).map[Future[Result]] { id =>
request.touchpoint.attrService.get(id).map {
Expand All @@ -52,41 +65,5 @@ class AttributeController {
}

def membership = lookup("membership", identity[Attributes])

def features = lookup("features",
onSuccess = Features.fromAttributes,
onNotFound = Features.unauthenticated
)

def membershipUpdateCard = updateCard(Membership)
def digitalPackUpdateCard = updateCard(Digipack)

def updateCard(implicit product: ProductFamily) = mmaCardAction.async { implicit request =>
val updateForm = Form { single("stripeToken" -> nonEmptyText) }
val tp = request.touchpoint

(for {
user <- OptionT(Future.successful(authenticationService.userId))
sfUser <- OptionT(tp.contactRepo.get(user))
subscription <- OptionT(tp.subService.get(sfUser))
stripeCardToken <- OptionT(Future.successful(updateForm.bindFromRequest().value))
updateResult <- OptionT(tp.paymentService.setPaymentCardWithStripeToken(subscription.accountId, stripeCardToken))
} yield updateResult match {
case success: CardUpdateSuccess => Ok(Json.toJson(success))
case failure: CardUpdateFailure => Forbidden(Json.toJson(failure))
}).run.map(_.getOrElse(notFound))
}

def membershipDetails = paymentDetails(Membership)
def digitalPackDetails = paymentDetails(Digipack)

def paymentDetails(implicit product: ProductFamily) = mmaAction.async { implicit request =>
(for {
user <- OptionT(Future.successful(authenticationService.userId))
contact <- OptionT(request.touchpoint.contactRepo.get(user))
sub <- OptionT(request.touchpoint.subService.getEither(contact))
details <- OptionT(request.touchpoint.paymentService.paymentDetails(sub).map[Option[PaymentDetails]](Some(_)))

} yield (contact, details).toResult).run.map(_ getOrElse Ok(Json.obj()))
}
def features = lookup("features", onSuccess = Features.fromAttributes, onNotFound = Features.unauthenticated)
}
13 changes: 7 additions & 6 deletions membership-attribute-service/conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ GET /healthcheck controllers.HealthCh

GET /user-attributes/me/membership controllers.AttributeController.membership
GET /user-attributes/me/features controllers.AttributeController.features
POST /user-attributes/me/update controllers.AttributeController.update

GET /user-attributes/me/mma-digitalpack controllers.AttributeController.digitalPackDetails
GET /user-attributes/me/mma-membership controllers.AttributeController.membershipDetails
GET /user-attributes/me/mma-digitalpack controllers.AccountController.digitalPackDetails
GET /user-attributes/me/mma-membership controllers.AccountController.membershipDetails

POST /user-attributes/me/membership-update-card controllers.AttributeController.membershipUpdateCard
OPTIONS /user-attributes/me/membership-update-card controllers.AttributeController.membershipUpdateCard
POST /user-attributes/me/membership-update-card controllers.AccountController.membershipUpdateCard
OPTIONS /user-attributes/me/membership-update-card controllers.AccountController.membershipUpdateCard

POST /user-attributes/me/digitalpack-update-card controllers.AttributeController.digitalPackUpdateCard
OPTIONS /user-attributes/me/digitalpack-update-card controllers.AttributeController.digitalPackUpdateCard
POST /user-attributes/me/digitalpack-update-card controllers.AccountController.digitalPackUpdateCard
OPTIONS /user-attributes/me/digitalpack-update-card controllers.AccountController.digitalPackUpdateCard

POST /salesforce-hook controllers.SalesforceHookController.createAttributes
POST /stripe-hook controllers.StripeHookController.process