migrate plan module
parent
29a411ad38
commit
c27821e881
|
@ -4,24 +4,37 @@ import akka.actor._
|
|||
import com.typesafe.config.Config
|
||||
import play.api.Configuration
|
||||
|
||||
object actors {
|
||||
trait Actor {
|
||||
val actor: ActorSelection
|
||||
val ! = actor ! _
|
||||
}
|
||||
case class Relation(actor: ActorSelection) extends Actor
|
||||
case class Timeline(actor: ActorSelection) extends Actor
|
||||
case class Report(actor: ActorSelection) extends Actor
|
||||
case class Renderer(actor: ActorSelection) extends Actor
|
||||
}
|
||||
|
||||
final class Env(
|
||||
appConfig: Configuration,
|
||||
system: ActorSystem
|
||||
) {
|
||||
|
||||
import actors._
|
||||
|
||||
val config = appConfig.get[Config]("hub")
|
||||
|
||||
val gameSearch = select("actor.game.search")
|
||||
val renderer = select("actor.renderer")
|
||||
val renderer = Renderer(select("actor.renderer"))
|
||||
val captcher = select("actor.captcher")
|
||||
val forumSearch = select("actor.forum.search")
|
||||
val teamSearch = select("actor.team.search")
|
||||
val fishnet = select("actor.fishnet")
|
||||
val tournamentApi = select("actor.tournament.api")
|
||||
val timeline = select("actor.timeline.user")
|
||||
val timeline = Timeline(select("actor.timeline.user"))
|
||||
val bookmark = select("actor.bookmark")
|
||||
val relation = select("actor.relation")
|
||||
val report = select("actor.report")
|
||||
val relation = Relation(select("actor.relation"))
|
||||
val report = Report(select("actor.report"))
|
||||
val shutup = select("actor.shutup")
|
||||
val mod = select("actor.mod")
|
||||
val notification = select("actor.notify")
|
||||
|
|
|
@ -1,40 +1,43 @@
|
|||
package lila.plan
|
||||
|
||||
import com.typesafe.config.Config
|
||||
import com.softwaremill.macwire._
|
||||
import io.methvin.play.autoconfig._
|
||||
import play.api.libs.ws.WSClient
|
||||
import lila.memo.SettingStore.{ StringReader, Formable }
|
||||
import play.api.Configuration
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import lila.common.config._
|
||||
|
||||
@Module
|
||||
private class PlanConfig(
|
||||
@ConfigName("collection.patron") val patronColl: CollName,
|
||||
@ConfigName("collection.charge") val chargeColl: CollName,
|
||||
val stripe: StripeClient.Config,
|
||||
@ConfigName("paypal.ipn_key") val payPalIpnKey: Secret
|
||||
)
|
||||
|
||||
final class Env(
|
||||
config: Config,
|
||||
appConfig: Configuration,
|
||||
db: lila.db.Env,
|
||||
hub: lila.hub.Env,
|
||||
ws: WSClient,
|
||||
timeline: lila.hub.actors.Timeline,
|
||||
notifyApi: lila.notify.NotifyApi,
|
||||
system: akka.actor.ActorSystem,
|
||||
asyncCache: lila.memo.AsyncCache.Builder,
|
||||
lightUserApi: lila.user.LightUserApi,
|
||||
settingStore: lila.memo.SettingStore.Builder,
|
||||
scheduler: lila.common.Scheduler
|
||||
) {
|
||||
userRepo: lila.user.UserRepo,
|
||||
settingStore: lila.memo.SettingStore.Builder
|
||||
)(implicit system: akka.actor.ActorSystem) {
|
||||
|
||||
val stripePublicKey = config getString "stripe.keys.public"
|
||||
import StripeClient.configLoader
|
||||
private val config = appConfig.get[PlanConfig]("plan")(AutoConfig.loader)
|
||||
|
||||
private val CollectionPatron = config getString "collection.patron"
|
||||
private val CollectionCharge = config getString "collection.charge"
|
||||
private lazy val patronColl = db(config.patronColl)
|
||||
private lazy val chargeColl = db(config.chargeColl)
|
||||
|
||||
private lazy val patronColl = db(CollectionPatron)
|
||||
private lazy val chargeColl = db(CollectionCharge)
|
||||
private lazy val stripeClient: StripeClient = wire[StripeClient]
|
||||
|
||||
private lazy val stripeClient = new StripeClient(StripeClient.Config(
|
||||
endpoint = config getString "stripe.endpoint",
|
||||
publicKey = stripePublicKey,
|
||||
secretKey = config getString "stripe.keys.secret"
|
||||
))
|
||||
|
||||
private lazy val notifier = new PlanNotifier(
|
||||
notifyApi = notifyApi,
|
||||
scheduler = scheduler,
|
||||
timeline = hub.timeline
|
||||
)
|
||||
private lazy val notifier: PlanNotifier = wire[PlanNotifier]
|
||||
|
||||
private lazy val monthlyGoalApi = new MonthlyGoalApi(
|
||||
getGoal = () => Usd(donationGoalSetting.get()),
|
||||
|
@ -43,27 +46,32 @@ final class Env(
|
|||
|
||||
val donationGoalSetting = settingStore[Int](
|
||||
"donationGoal",
|
||||
default = 10 * 1000,
|
||||
default = 0,
|
||||
text = "Monthly donation goal in USD from https://lichess.org/costs".some
|
||||
)
|
||||
|
||||
lazy val api = new PlanApi(
|
||||
stripeClient,
|
||||
stripeClient = stripeClient,
|
||||
patronColl = patronColl,
|
||||
chargeColl = chargeColl,
|
||||
notifier = notifier,
|
||||
userRepo = userRepo,
|
||||
lightUserApi = lightUserApi,
|
||||
asyncCache = asyncCache,
|
||||
payPalIpnKey = PayPalIpnKey(config getString "paypal.ipn_key"),
|
||||
payPalIpnKey = config.payPalIpnKey,
|
||||
monthlyGoalApi = monthlyGoalApi
|
||||
)(system)
|
||||
)
|
||||
|
||||
private lazy val webhookHandler = new WebhookHandler(api)
|
||||
|
||||
private lazy val expiration = new Expiration(patronColl, notifier)
|
||||
private lazy val expiration = new Expiration(
|
||||
userRepo,
|
||||
patronColl,
|
||||
notifier
|
||||
)
|
||||
|
||||
scheduler.future(15 minutes, "Expire patron plans") {
|
||||
expiration.run
|
||||
system.scheduler.scheduleWithFixedDelay(15 minutes, 15 minutes) {
|
||||
() => expiration.run
|
||||
}
|
||||
|
||||
def webhook = webhookHandler.apply _
|
||||
|
@ -71,27 +79,12 @@ final class Env(
|
|||
def cli = new lila.common.Cli {
|
||||
def process = {
|
||||
case "patron" :: "lifetime" :: user :: Nil =>
|
||||
lila.user.UserRepo named user flatMap { _ ?? api.setLifetime } inject "ok"
|
||||
userRepo named user flatMap { _ ?? api.setLifetime } inject "ok"
|
||||
// someone donated while logged off.
|
||||
// we cannot bind the charge to the user so they get their precious wings.
|
||||
// instead, give them a free month.
|
||||
case "patron" :: "month" :: user :: Nil =>
|
||||
lila.user.UserRepo named user flatMap { _ ?? api.giveMonth } inject "ok"
|
||||
userRepo named user flatMap { _ ?? api.giveMonth } inject "ok"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Env {
|
||||
|
||||
lazy val current: Env = "plan" boot new Env(
|
||||
config = lila.common.PlayApp loadConfig "plan",
|
||||
db = lila.db.Env.current,
|
||||
hub = lila.hub.Env.current,
|
||||
notifyApi = lila.notify.Env.current.api,
|
||||
lightUserApi = lila.user.Env.current.lightUserApi,
|
||||
system = lila.common.PlayApp.system,
|
||||
asyncCache = lila.memo.Env.current.asyncCache,
|
||||
settingStore = lila.memo.Env.current.settingStore,
|
||||
scheduler = lila.common.PlayApp.scheduler
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,23 +5,27 @@ import lila.user.UserRepo
|
|||
|
||||
import org.joda.time.DateTime
|
||||
|
||||
private final class Expiration(patronColl: Coll, notifier: PlanNotifier) {
|
||||
private final class Expiration(
|
||||
userRepo: UserRepo,
|
||||
patronColl: Coll,
|
||||
notifier: PlanNotifier
|
||||
) {
|
||||
|
||||
import BsonHandlers._
|
||||
import PatronHandlers._
|
||||
|
||||
def run: Funit = getExpired flatMap {
|
||||
_.map { patron =>
|
||||
patronColl.update($id(patron.id), patron.removeStripe.removePayPal) >>
|
||||
patronColl.update.one($id(patron.id), patron.removeStripe.removePayPal) >>
|
||||
disableUserPlanOf(patron) >>-
|
||||
logger.info(s"Expired ${patron}")
|
||||
}.sequenceFu.void
|
||||
}
|
||||
|
||||
private def disableUserPlanOf(patron: Patron): Funit =
|
||||
UserRepo byId patron.userId flatMap {
|
||||
userRepo byId patron.userId flatMap {
|
||||
_ ?? { user =>
|
||||
UserRepo.setPlan(user, user.plan.disable) >>
|
||||
userRepo.setPlan(user, user.plan.disable) >>
|
||||
notifier.onExpire(user)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package lila.plan
|
||||
|
||||
import org.joda.time.DateTime
|
||||
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
|
||||
import reactivemongo.api.bson.BSONNull
|
||||
|
||||
import lila.db.dsl._
|
||||
|
@ -13,13 +12,14 @@ private final class MonthlyGoalApi(getGoal: () => Usd, chargeColl: Coll) {
|
|||
}
|
||||
|
||||
def monthAmount: Fu[Cents] =
|
||||
chargeColl.aggregateOne(
|
||||
Match($doc("date" $gt DateTime.now.withDayOfMonth(1).withTimeAtStartOfDay)), List(
|
||||
chargeColl.aggregateWith() { framework =>
|
||||
import framework._
|
||||
Match($doc("date" $gt DateTime.now.withDayOfMonth(1).withTimeAtStartOfDay)) -> List(
|
||||
Group(BSONNull)("cents" -> SumField("cents"))
|
||||
)
|
||||
).map {
|
||||
~_.flatMap { _.getAs[Int]("cents") }
|
||||
} map Cents.apply
|
||||
}.headOption.map {
|
||||
~_.flatMap { _.int("cents") }
|
||||
} dmap Cents.apply
|
||||
}
|
||||
|
||||
case class MonthlyGoal(current: Cents, goal: Cents) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework
|
|||
import reactivemongo.api.ReadPreference
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import lila.common.config.Secret
|
||||
import lila.common.{ Bus, Every, AtMost }
|
||||
import lila.db.dsl._
|
||||
import lila.memo.PeriodicRefreshCache
|
||||
|
@ -15,9 +16,10 @@ final class PlanApi(
|
|||
patronColl: Coll,
|
||||
chargeColl: Coll,
|
||||
notifier: PlanNotifier,
|
||||
userRepo: UserRepo,
|
||||
lightUserApi: lila.user.LightUserApi,
|
||||
asyncCache: lila.memo.AsyncCache.Builder,
|
||||
payPalIpnKey: PayPalIpnKey,
|
||||
payPalIpnKey: Secret,
|
||||
monthlyGoalApi: MonthlyGoalApi
|
||||
)(implicit system: akka.actor.ActorSystem) {
|
||||
|
||||
|
@ -56,7 +58,7 @@ final class PlanApi(
|
|||
isLifetime(user).flatMap { lifetime =>
|
||||
!lifetime ?? setDbUserPlan(user, user.plan.disable)
|
||||
} >>
|
||||
patronColl.update($id(user.id), $unset("stripe", "payPal", "expiresAt")).void >>-
|
||||
patronColl.update.one($id(user.id), $unset("stripe", "payPal", "expiresAt")).void >>-
|
||||
logger.info(s"Canceled subscription $sub of ${user.username}")
|
||||
}
|
||||
}
|
||||
|
@ -75,12 +77,12 @@ final class PlanApi(
|
|||
funit
|
||||
case Some(patron) =>
|
||||
logger.info(s"Charged $charge $patron")
|
||||
UserRepo byId patron.userId flatten s"Missing user for $patron" flatMap { user =>
|
||||
userRepo byId patron.userId orFail s"Missing user for $patron" flatMap { user =>
|
||||
val p2 = patron.copy(
|
||||
stripe = Patron.Stripe(stripeCharge.customer).some,
|
||||
free = none
|
||||
).levelUpIfPossible
|
||||
patronColl.update($id(patron.id), p2) >>
|
||||
patronColl.update.one($id(patron.id), p2) >>
|
||||
setDbUserPlanOnCharge(user, p2) >> {
|
||||
stripeCharge.lifetimeWorthy ?? setLifetime(user)
|
||||
}
|
||||
|
@ -97,9 +99,9 @@ final class PlanApi(
|
|||
name: Option[String],
|
||||
txnId: Option[String],
|
||||
ip: String,
|
||||
key: PayPalIpnKey
|
||||
key: String
|
||||
): Funit =
|
||||
if (key != payPalIpnKey) {
|
||||
if (key != payPalIpnKey.value) {
|
||||
logger.error(s"Invalid PayPal IPN key $key from $ip $userId $cents")
|
||||
funit
|
||||
} else if (cents.value < 100) {
|
||||
|
@ -118,11 +120,11 @@ final class PlanApi(
|
|||
cents = cents
|
||||
)
|
||||
addCharge(charge) >>
|
||||
(userId ?? UserRepo.named) flatMap { userOption =>
|
||||
(userId ?? userRepo.named) flatMap { userOption =>
|
||||
userOption ?? { user =>
|
||||
val payPal = Patron.PayPal(email, subId, DateTime.now)
|
||||
userPatron(user).flatMap {
|
||||
case None => patronColl.insert(Patron(
|
||||
case None => patronColl.insert.one(Patron(
|
||||
_id = Patron.UserId(user.id),
|
||||
payPal = payPal.some,
|
||||
lastLevelUp = DateTime.now
|
||||
|
@ -134,7 +136,7 @@ final class PlanApi(
|
|||
payPal = payPal.some,
|
||||
free = none
|
||||
).levelUpIfPossible.expireInOneMonth
|
||||
patronColl.update($id(patron.id), p2) >>
|
||||
patronColl.update.one($id(patron.id), p2) >>
|
||||
setDbUserPlanOnCharge(user, p2)
|
||||
} >> {
|
||||
charge.lifetimeWorthy ?? setLifetime(user)
|
||||
|
@ -160,9 +162,9 @@ final class PlanApi(
|
|||
logger.info(s"Ignore sub end for lifetime patron $patron")
|
||||
funit
|
||||
case Some(patron) =>
|
||||
UserRepo byId patron.userId flatten s"Missing user for $patron" flatMap { user =>
|
||||
userRepo byId patron.userId orFail s"Missing user for $patron" flatMap { user =>
|
||||
setDbUserPlan(user, user.plan.disable) >>
|
||||
patronColl.update($id(user.id), patron.removeStripe).void >>
|
||||
patronColl.update.one($id(user.id), patron.removeStripe).void >>
|
||||
notifier.onExpire(user) >>-
|
||||
logger.info(s"Unsubed ${user.username} ${sub}")
|
||||
}
|
||||
|
@ -204,10 +206,10 @@ final class PlanApi(
|
|||
case (Some(stripe), _) => stripeClient.getCustomer(stripe.customerId) flatMap {
|
||||
case None =>
|
||||
logger.warn(s"${user.username} sync: unset DB patron that's not in stripe")
|
||||
patronColl.update($id(patron.id), patron.removeStripe) >> sync(user)
|
||||
patronColl.update.one($id(patron.id), patron.removeStripe) >> sync(user)
|
||||
case Some(customer) if customer.firstSubscription.isEmpty =>
|
||||
logger.warn(s"${user.username} sync: unset DB patron of customer without a subscription")
|
||||
patronColl.update($id(patron.id), patron.removeStripe) >> sync(user)
|
||||
patronColl.update.one($id(patron.id), patron.removeStripe) >> sync(user)
|
||||
case Some(customer) if customer.firstSubscription.isDefined && !user.plan.active =>
|
||||
logger.warn(s"${user.username} sync: enable plan of customer with a subscription")
|
||||
setDbUserPlan(user, user.plan.enable) inject ReloadUser
|
||||
|
@ -234,11 +236,11 @@ final class PlanApi(
|
|||
_.exists(_.isLifetime)
|
||||
}
|
||||
|
||||
def setLifetime(user: User): Funit = UserRepo.setPlan(user, lila.user.Plan(
|
||||
def setLifetime(user: User): Funit = userRepo.setPlan(user, lila.user.Plan(
|
||||
months = user.plan.months | 1,
|
||||
active = true,
|
||||
since = user.plan.since orElse DateTime.now.some
|
||||
)) >> patronColl.update(
|
||||
)) >> patronColl.update.one(
|
||||
$id(user.id),
|
||||
$set(
|
||||
"lastLevelUp" -> DateTime.now,
|
||||
|
@ -248,11 +250,11 @@ final class PlanApi(
|
|||
upsert = true
|
||||
).void >>- lightUserApi.invalidate(user.id)
|
||||
|
||||
def giveMonth(user: User): Funit = UserRepo.setPlan(user, lila.user.Plan(
|
||||
def giveMonth(user: User): Funit = userRepo.setPlan(user, lila.user.Plan(
|
||||
months = user.plan.months | 1,
|
||||
active = true,
|
||||
since = user.plan.since orElse DateTime.now.some
|
||||
)) >> patronColl.update(
|
||||
)) >> patronColl.update.one(
|
||||
$id(user.id),
|
||||
$set(
|
||||
"lastLevelUp" -> DateTime.now,
|
||||
|
@ -274,8 +276,8 @@ final class PlanApi(
|
|||
|
||||
def recentChargeUserIds: Fu[List[User.ID]] = recentChargeUserIdsCache.get
|
||||
|
||||
def recentChargesOf(user: User): Fu[List[Charge]] =
|
||||
chargeColl.find($doc("userId" -> user.id)).sort($doc("date" -> -1)).list[Charge]()
|
||||
def recentCharesOf(user: User): Fu[List[Charge]] =
|
||||
chargeColl.ext.find($doc("userId" -> user.id)).sort($doc("date" -> -1)).list[Charge]()
|
||||
|
||||
private val topPatronUserIdsNb = 300
|
||||
private val topPatronUserIdsCache = new PeriodicRefreshCache[List[User.ID]](
|
||||
|
@ -283,16 +285,18 @@ final class PlanApi(
|
|||
every = Every(1 hour),
|
||||
atMost = AtMost(1 minute),
|
||||
f = () => chargeColl.aggregateList(
|
||||
Match($doc("userId" $exists true)), List(
|
||||
maxDocs = topPatronUserIdsNb * 2,
|
||||
readPreference = ReadPreference.secondaryPreferred
|
||||
) { framework =>
|
||||
import framework._
|
||||
Match($doc("userId" $exists true)) -> List(
|
||||
GroupField("userId")("total" -> SumField("cents")),
|
||||
Sort(Descending("total")),
|
||||
Limit(topPatronUserIdsNb * 3 / 2)
|
||||
),
|
||||
maxDocs = topPatronUserIdsNb * 2,
|
||||
readPreference = ReadPreference.secondaryPreferred
|
||||
).map {
|
||||
_.flatMap { _.getAs[User.ID]("_id") }
|
||||
} flatMap filterUserIds map (_ take topPatronUserIdsNb),
|
||||
)
|
||||
}.dmap {
|
||||
_.flatMap { _.getAsOpt[User.ID]("_id") }
|
||||
} flatMap filterUserIds dmap (_ take topPatronUserIdsNb),
|
||||
default = Nil,
|
||||
initialDelay = 35 seconds
|
||||
)
|
||||
|
@ -301,13 +305,13 @@ final class PlanApi(
|
|||
|
||||
private def filterUserIds(ids: List[User.ID]): Fu[List[User.ID]] = {
|
||||
val dedup = ids.distinct
|
||||
UserRepo.filterByEnabledPatrons(dedup) map { enableds =>
|
||||
userRepo.filterByEnabledPatrons(dedup) map { enableds =>
|
||||
dedup filter enableds.contains
|
||||
}
|
||||
}
|
||||
|
||||
private def addCharge(charge: Charge): Funit =
|
||||
chargeColl.insert(charge).void >>- {
|
||||
chargeColl.insert.one(charge).void >>- {
|
||||
recentChargeUserIdsCache.refresh
|
||||
monthlyGoalApi.get foreach { m =>
|
||||
Bus.publish(lila.hub.actorApi.plan.ChargeEvent(
|
||||
|
@ -364,7 +368,7 @@ final class PlanApi(
|
|||
}
|
||||
|
||||
private def setDbUserPlan(user: User, plan: lila.user.Plan): Funit =
|
||||
UserRepo.setPlan(user, plan) >>- lightUserApi.invalidate(user.id)
|
||||
userRepo.setPlan(user, plan) >>- lightUserApi.invalidate(user.id)
|
||||
|
||||
private def createCustomer(user: User, data: Checkout, plan: StripePlan): Fu[StripeCustomer] =
|
||||
stripeClient.createCustomer(user, data, plan) flatMap { customer =>
|
||||
|
@ -375,12 +379,12 @@ final class PlanApi(
|
|||
}
|
||||
|
||||
private def saveStripePatron(user: User, customerId: CustomerId, freq: Freq): Funit = userPatron(user) flatMap {
|
||||
case None => patronColl.insert(Patron(
|
||||
case None => patronColl.insert.one(Patron(
|
||||
_id = Patron.UserId(user.id),
|
||||
stripe = Patron.Stripe(customerId).some,
|
||||
lastLevelUp = DateTime.now
|
||||
).expireInOneMonth(!freq.renew))
|
||||
case Some(patron) => patronColl.update(
|
||||
case Some(patron) => patronColl.update.one(
|
||||
$id(patron.id),
|
||||
patron.copy(
|
||||
stripe = Patron.Stripe(customerId).some
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package lila.plan
|
||||
|
||||
import akka.actor.ActorSelection
|
||||
import akka.actor._
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import lila.hub.actorApi.timeline.{ Propagate }
|
||||
|
@ -10,12 +10,11 @@ import lila.user.User
|
|||
|
||||
private[plan] final class PlanNotifier(
|
||||
notifyApi: NotifyApi,
|
||||
scheduler: lila.common.Scheduler,
|
||||
timeline: ActorSelection
|
||||
) {
|
||||
timeline: lila.hub.actors.Timeline
|
||||
)(implicit system: ActorSystem) {
|
||||
|
||||
def onStart(user: User) = fuccess {
|
||||
scheduler.once(5 seconds) {
|
||||
system.scheduler.scheduleOnce(5 seconds) {
|
||||
notifyApi.addNotification(Notification.make(
|
||||
Notifies(user.id),
|
||||
lila.notify.PlanStart(user.id)
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package lila.plan
|
||||
|
||||
import play.api.libs.json._
|
||||
import play.api.libs.ws.{ WS, WSResponse }
|
||||
import play.api.Play.current
|
||||
import play.api.libs.ws.{ WSClient, WSResponse }
|
||||
|
||||
import lila.common.config.Secret
|
||||
import lila.user.User
|
||||
|
||||
private final class StripeClient(config: StripeClient.Config) {
|
||||
private final class StripeClient(
|
||||
ws: WSClient,
|
||||
config: StripeClient.Config
|
||||
) {
|
||||
|
||||
import StripeClient._
|
||||
import JsonHandlers._
|
||||
|
@ -125,7 +128,7 @@ private final class StripeClient(config: StripeClient.Config) {
|
|||
|
||||
private def post[A: Reads](url: String, data: Seq[(String, Any)]): Fu[A] = {
|
||||
logger.info(s"POST $url ${debugInput(data)}")
|
||||
request(url).post(fixInput(data).toMap mapValues { Seq(_) }) flatMap response[A]
|
||||
request(url).post(fixInput(data).toMap) flatMap response[A]
|
||||
}
|
||||
|
||||
private def delete[A: Reads](url: String, data: Seq[(String, Any)]): Fu[A] = {
|
||||
|
@ -134,7 +137,7 @@ private final class StripeClient(config: StripeClient.Config) {
|
|||
}
|
||||
|
||||
private def request(url: String) =
|
||||
WS.url(s"${config.endpoint}/$url").withHeaders("Authorization" -> s"Bearer ${config.secretKey}")
|
||||
ws.url(s"${config.endpoint}/$url").withHeaders("Authorization" -> s"Bearer ${config.secretKey}")
|
||||
|
||||
private def response[A: Reads](res: WSResponse): Fu[A] = res.status match {
|
||||
case 200 => (implicitly[Reads[A]] reads res.json).fold(
|
||||
|
@ -156,9 +159,9 @@ private final class StripeClient(config: StripeClient.Config) {
|
|||
(js.asOpt[JsObject] flatMap { o => (o \ "deleted").asOpt[Boolean] }) == Some(true)
|
||||
|
||||
private def fixInput(in: Seq[(String, Any)]): Seq[(String, String)] = (in map {
|
||||
case (sym, Some(x)) => Some(sym.name -> x.toString)
|
||||
case (sym, None) => None
|
||||
case (sym, x) => Some(sym.name -> x.toString)
|
||||
case (name, Some(x)) => Some(name -> x.toString)
|
||||
case (name, None) => None
|
||||
case (name, x) => Some(name -> x.toString)
|
||||
}).flatten
|
||||
|
||||
private def listReader[A: Reads]: Reads[List[A]] = (__ \ "data").read[List[A]]
|
||||
|
@ -166,7 +169,7 @@ private final class StripeClient(config: StripeClient.Config) {
|
|||
private def debugInput(data: Seq[(String, Any)]) = fixInput(data) map { case (k, v) => s"$k=$v" } mkString " "
|
||||
}
|
||||
|
||||
object StripeClient {
|
||||
private object StripeClient {
|
||||
|
||||
class StripeException(msg: String) extends Exception(msg)
|
||||
class DeletedException(msg: String) extends StripeException(msg)
|
||||
|
@ -174,5 +177,11 @@ object StripeClient {
|
|||
class NotFoundException(msg: String) extends StatusException(msg)
|
||||
class InvalidRequestException(msg: String) extends StatusException(msg)
|
||||
|
||||
case class Config(endpoint: String, publicKey: String, secretKey: String)
|
||||
import io.methvin.play.autoconfig._
|
||||
case class Config(
|
||||
endpoint: String,
|
||||
@ConfigName("keys.public") publicKey: String,
|
||||
@ConfigName("keys.public") secretKey: Secret
|
||||
)
|
||||
implicit val configLoader = AutoConfig.loader[Config]
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ package lila.plan
|
|||
|
||||
import org.joda.time.DateTime
|
||||
|
||||
case class PayPalIpnKey(value: String) extends AnyVal
|
||||
|
||||
case class CustomerId(value: String) extends AnyVal
|
||||
case class ChargeId(value: String) extends AnyVal
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import play.api.Configuration
|
|||
import scala.concurrent.duration._
|
||||
|
||||
import lila.common.config._
|
||||
import lila.hub.actors
|
||||
|
||||
@Module
|
||||
private class RelationConfig(
|
||||
|
@ -20,7 +21,9 @@ private class RelationConfig(
|
|||
final class Env(
|
||||
appConfig: Configuration,
|
||||
db: lila.db.Env,
|
||||
hub: lila.hub.Env,
|
||||
relation: actors.Relation,
|
||||
timeline: actors.Timeline,
|
||||
report: actors.Report,
|
||||
onlineUserIds: () => Set[lila.user.User.ID],
|
||||
lightUserApi: lila.user.LightUserApi,
|
||||
followable: String => Fu[Boolean],
|
||||
|
@ -38,9 +41,9 @@ final class Env(
|
|||
lazy val api = new RelationApi(
|
||||
coll = coll,
|
||||
repo = repo,
|
||||
actor = hub.relation,
|
||||
timeline = hub.timeline,
|
||||
reporter = hub.report,
|
||||
actor = relation,
|
||||
timeline = timeline,
|
||||
reporter = report,
|
||||
followable = followable,
|
||||
asyncCache = asyncCache,
|
||||
maxFollow = config.maxFollow,
|
||||
|
|
|
@ -11,15 +11,16 @@ import lila.common.Bus
|
|||
import lila.common.config.Max
|
||||
import lila.db.dsl._
|
||||
import lila.db.paginator._
|
||||
import lila.hub.actors
|
||||
import lila.hub.actorApi.timeline.{ Propagate, Follow => FollowUser }
|
||||
import lila.user.User
|
||||
|
||||
final class RelationApi(
|
||||
coll: Coll,
|
||||
repo: RelationRepo,
|
||||
actor: ActorSelection,
|
||||
timeline: ActorSelection,
|
||||
reporter: ActorSelection,
|
||||
actor: actors.Relation,
|
||||
timeline: actors.Timeline,
|
||||
reporter: actors.Report,
|
||||
followable: ID => Fu[Boolean],
|
||||
asyncCache: lila.memo.AsyncCache.Builder,
|
||||
maxFollow: Max,
|
||||
|
|
Loading…
Reference in New Issue