secure stripe webhooks and handle unsub
parent
c4dff1cc1e
commit
f57864a5db
|
@ -33,7 +33,8 @@ final class StripeApi(
|
|||
case Some(cus) if cus.canLevelUp =>
|
||||
UserRepo byId cus.userId.value flatten s"Missing user for $cus" flatMap { user =>
|
||||
customerColl.updateField($id(cus.id), "lastLevelUp", DateTime.now) >>
|
||||
UserRepo.setPlan(user, user.plan.fold(lila.user.Plan.init)(_.incMonths))
|
||||
UserRepo.setPlan(user, user.plan.fold(lila.user.Plan.init)(_.incMonths)) >>-
|
||||
logger.info(s"Charged ${charge} ${cus}")
|
||||
}
|
||||
case Some(cus) => fufail(s"Too early to level up $charge $cus")
|
||||
}
|
||||
|
@ -43,10 +44,13 @@ final class StripeApi(
|
|||
case None => fufail(s"Deleted subscription of unknown customer $sub")
|
||||
case Some(cus) =>
|
||||
UserRepo byId cus.userId.value flatten s"Missing user for $cus" flatMap { user =>
|
||||
UserRepo.setPlan(user, user.plan.|(lila.user.Plan.init).disable)
|
||||
UserRepo.setPlan(user, user.plan.|(lila.user.Plan.init).disable) >>-
|
||||
logger.info(s"Unsubed ${user.id} ${sub}")
|
||||
}
|
||||
}
|
||||
|
||||
def getEvent = client.getEvent _
|
||||
|
||||
private def setUserPlan(user: User, plan: StripePlan, source: Source): Fu[StripeSubscription] =
|
||||
userCustomer(user) flatMap {
|
||||
case None => createCustomer(user, plan, source) map { customer =>
|
||||
|
@ -61,7 +65,8 @@ final class StripeApi(
|
|||
_id = Customer.Id(customer.id),
|
||||
userId = Customer.UserId(user.id),
|
||||
lastLevelUp = DateTime.now)) >>
|
||||
UserRepo.setPlan(user, lila.user.Plan.init) inject customer
|
||||
UserRepo.setPlan(user, lila.user.Plan.init) >>-
|
||||
logger.info(s"Subed ${user.id} ${plan}") inject customer
|
||||
}
|
||||
|
||||
private def setCustomerPlan(customer: StripeCustomer, plan: StripePlan, source: Source): Fu[StripeSubscription] =
|
||||
|
|
|
@ -36,6 +36,9 @@ private final class StripeClient(config: StripeClient.Config) {
|
|||
'source -> source.map(_.value),
|
||||
'prorate -> false)
|
||||
|
||||
def getEvent(id: String): Fu[Option[JsObject]] =
|
||||
getOne[JsObject](s"events/$id")
|
||||
|
||||
private def getOne[A: Reads](url: String, queryString: (Symbol, Any)*): Fu[Option[A]] =
|
||||
get[A](url, queryString) map Some.apply recover {
|
||||
case _: NotFoundException => None
|
||||
|
|
|
@ -6,19 +6,24 @@ private final class WebhookHandler(api: StripeApi) {
|
|||
|
||||
import JsonHandlers._
|
||||
|
||||
def apply(js: JsValue): Funit = ~{
|
||||
def apply(js: JsValue): Funit = {
|
||||
logger.debug(s"Webhook ${js.toString.take(80)}")
|
||||
for {
|
||||
name <- (js \ "type").asOpt[String]
|
||||
data <- (js \ "data" \ "object").asOpt[JsObject]
|
||||
} yield (name match {
|
||||
case "charge.succeeded" =>
|
||||
val charge = data.asOpt[StripeCharge] err s"Invalid charge $data"
|
||||
api onCharge charge
|
||||
case "customer.subscription.deleted" =>
|
||||
val sub = data.asOpt[StripeSubscription] err s"Invalid subscription $data"
|
||||
api onSubscriptionDeleted sub
|
||||
case typ => funit
|
||||
})
|
||||
(js \ "id").asOpt[String] ?? api.getEvent flatMap {
|
||||
case None =>
|
||||
logger.warn(s"Forged webhook $js")
|
||||
funit
|
||||
case Some(event) => ~(for {
|
||||
name <- (event \ "type").asOpt[String]
|
||||
data <- (event \ "data" \ "object").asOpt[JsObject]
|
||||
} yield (name match {
|
||||
case "charge.succeeded" =>
|
||||
val charge = data.asOpt[StripeCharge] err s"Invalid charge $data"
|
||||
api onCharge charge
|
||||
case "customer.subscription.deleted" =>
|
||||
val sub = data.asOpt[StripeSubscription] err s"Invalid subscription $data"
|
||||
api onSubscriptionDeleted sub
|
||||
case typ => funit
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue