remove donation module

pull/2029/merge
Thibault Duplessis 2016-07-14 21:50:18 +02:00
parent 89fedd19a9
commit 1c24602a60
14 changed files with 41 additions and 402 deletions

View File

@ -133,7 +133,6 @@ object Env {
def coordinate = lila.coordinate.Env.current
def tv = lila.tv.Env.current
def blog = lila.blog.Env.current
def donation = lila.donation.Env.current
def qa = lila.qa.Env.current
def history = lila.history.Env.current
def worldMap = lila.worldMap.Env.current

View File

@ -1,55 +0,0 @@
package controllers
import play.api.mvc._, Results._
import lila.app._
import views._
object Donation extends LilaController {
def index = Open { implicit ctx =>
OptionFuOk(Prismic.getBookmark("donate")) {
case (doc, resolver) => Env.donation.api.list(100) zip
Env.donation.api.top(10) map {
case (donations, top) =>
views.html.donation.index(doc, resolver, donations, top)
}
}
}
def thanks = Open { implicit ctx =>
Redirect(routes.Plan.index).fuccess
}
def thanksRedirect = Action(Redirect(routes.Donation.thanks))
def ipn = Action.async { implicit req =>
Env.donation.forms.ipn.bindFromRequest.fold(
err => {
println(err)
fuccess(Ok)
},
ipn => {
val donation = lila.donation.Donation.make(
payPalTnx = ipn.txnId,
payPalSub = ipn.subId,
userId = ipn.userId,
email = ipn.email,
name = ipn.name,
gross = ipn.grossCents,
fee = ipn.feeCents,
message = "")
ipn.userId.?? { userId =>
import lila.plan.Patron.PayPal
Env.plan.api.onPaypalCharge(
userId = userId,
email = ipn.email map PayPal.Email.apply,
subId = ipn.subId map PayPal.SubId.apply,
cents = lila.plan.Cents(ipn.grossCents),
name = ipn.name,
txnId = ipn.txnId)
} >>
Env.donation.api.create(donation) inject Ok
})
}
}

View File

@ -96,4 +96,22 @@ object Plan extends LilaController {
def webhook = Action.async(parse.json) { req =>
Env.plan.webhook(req.body) map { _ => Ok("kthxbye") }
}
def payPalIpn = Action.async { implicit req =>
import lila.plan.Patron.PayPal
lila.plan.DataForm.ipn.bindFromRequest.fold(
err => {
println(err)
fuccess(Ok)
},
ipn => Env.plan.api.onPaypalCharge(
userId = ipn.userId,
email = ipn.email map PayPal.Email.apply,
subId = ipn.subId map PayPal.SubId.apply,
cents = lila.plan.Cents(ipn.grossCents),
name = ipn.name,
txnId = ipn.txnId
) inject Ok
)
}
}

View File

@ -1,120 +0,0 @@
@(doc: io.prismic.Document, resolver: io.prismic.DocumentLinkResolver, donations: List[lila.donation.Donation], top: List[User.ID])(implicit ctx: Context)
@payPalVars = {
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="custom" value="@ctx.userId">
}
@side = {
<h2>Top Donors</h2>
<div class="donors">
@top.map { userId =>
<div>@userIdLink(userId.some)</div>
}
</div>
<h2>Recent Donors</h2>
<div class="donors">
@donations.take(10).map { donation =>
<div>@userIdLink(donation.userId)</div>
}
</div>
}
@moreCss = {
@cssTag("page.css")
@cssTag("donation.css")
}
@site.layout(
moreCss = moreCss,
side = side.some,
title = s"${~doc.getText("doc.title")}",
openGraph = lila.app.ui.OpenGraph(
title = "Donate to lichess.org",
url = s"$netBaseUrl${routes.Donation.index.url}",
description = "Your donations help pay for the web servers, show that lichess is appreciated, and keep the developer motivated.").some) {
<div class="content_box small_box doc_box donate_box">
<h1 class="lichess_title">@doc.getText("doc.title")</h1>
<div class="body">
@Html(~doc.getHtml("doc.content", resolver))
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<! -- $5 -->
@payPalVars
<input type="hidden" name="hosted_button_id" value="JBSUYNPRCMT9U">
<strong>$5</strong> = <strong>3.5 hours</strong> of lichess costs:
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
</form>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<! -- $10 -->
@payPalVars
<input type="hidden" name="hosted_button_id" value="ZZ96PGW3UNRPQ">
<strong>$10</strong> = <strong>7 hours</strong> of lichess costs:
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
</form>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<! -- $20 -->
@payPalVars
<input type="hidden" name="hosted_button_id" value="VTKN4LNQZ2FNL">
<strong>$20</strong> = <strong>14 hours</strong> of lichess costs:
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
</form>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<! -- $50 -->
@payPalVars
<input type="hidden" name="hosted_button_id" value="XXYXZXY7GJQYJ">
<strong>$50</strong> = <strong>1.5 days</strong> of lichess costs:
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
</form>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<! -- any -->
@payPalVars
<input type="hidden" name="hosted_button_id" value="EDV5QHA9HYGJS">
Or specify any other amount:
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
</form>
<h2>Even better: monthly donation</h2>
<p>Because I pay for lichess servers every month, please consider a recurring donation!</p>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<! -- recurring -->
@payPalVars
<input type="hidden" name="hosted_button_id" value="36KH4D465UB9G">
<input type="hidden" name="on0" value="Monthly donation">Monthly donation
<select name="os0">
<option value="$5">3.5 hours: $5.00 USD - monthly</option>
<option value="$10">7 hours: $10.00 USD - monthly</option>
<option value="$20">14 hours: $20.00 USD - monthly</option>
<option value="$50">1.5 days: $50.00 USD - monthly</option>
</select>
<input type="hidden" name="currency_code" value="USD">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_subscribe_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
</form>
<h2>Thank you to all lichess.org donors!</h2>
<table class="slist donors">
<tbody>
@donations.map { donation =>
<tr>
<td>@showDate(donation.date)</td>
<td>@userIdLink(donation.userId)</td>
<td>@donation.nonEmptyMessage.map { message =>
<em>“@message”</em>
}</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}

View File

@ -140,6 +140,7 @@ GET /learn controllers.Learn.index
POST /learn/score controllers.Learn.score
POST /learn/reset controllers.Learn.reset
# Patron
GET /patron controllers.Plan.index
POST /patron/charge controllers.Plan.charge
GET /patron/thanks controllers.Plan.thanks
@ -147,6 +148,11 @@ POST /patron/switch controllers.Plan.switch
POST /patron/cancel controllers.Plan.cancel
POST /patron/webhook controllers.Plan.webhook
GET /features controllers.Plan.features
# Donate
GET /donate controllers.Plan.index
GET /donate/thanks controllers.Plan.thanks
POST /donate/thanks controllers.Plan.thanks
POST /donate/ipn controllers.Plan.payPalIpn
# Round
GET /$gameId<\w{8}> controllers.Round.watcher(gameId: String, color: String = "white")
@ -426,12 +432,6 @@ GET /network/stream controllers.WorldMap.stream
POST /mobile/register/:platform/:deviceId controllers.Main.mobileRegister(platform: String, deviceId: String)
POST /mobile/unregister controllers.Main.mobileUnregister
# Donate
GET /donate controllers.Donation.index
GET /donate/thanks controllers.Donation.thanks
POST /donate/thanks controllers.Donation.thanksRedirect
POST /donate/ipn controllers.Donation.ipn
# Pages
GET /thanks controllers.Page.thanks
GET /terms-of-service controllers.Page.tos

View File

@ -1,47 +0,0 @@
package lila.donation
import org.joda.time.DateTime
case class Donation(
_id: String, // random ID
payPalTnx: Option[String], // PayPal transaction ID
payPalSub: Option[String], // PayPal subscription ID
userId: Option[String],
email: Option[String],
name: Option[String],
date: DateTime,
gross: Int, // $ cents
fee: Int, // $ cents
net: Int, // $ cents
message: String,
public: Boolean,
publicAmount: Boolean) {
def nonEmptyMessage = Some(message.trim) filter (_.nonEmpty)
}
object Donation {
def make(
payPalTnx: Option[String],
payPalSub: Option[String],
email: Option[String],
name: Option[String],
userId: Option[String],
gross: Int,
fee: Int,
message: String) = Donation(
_id = ornicar.scalalib.Random nextStringUppercase 8,
payPalTnx = payPalTnx,
payPalSub = payPalSub,
email = email,
name = name,
userId = userId,
date = DateTime.now,
gross = gross,
fee = fee,
net = gross - fee,
message = message,
public = true,
publicAmount = false)
}

View File

@ -1,49 +0,0 @@
package lila.donation
import org.joda.time.{ DateTime, DateTimeConstants }
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
import reactivemongo.bson._
import scala.concurrent.duration._
import scala.util.Try
import lila.db.BSON.BSONJodaDateTimeHandler
import lila.db.dsl._
final class DonationApi(
coll: Coll,
weeklyGoal: Int,
bus: lila.common.Bus) {
private implicit val donationBSONHandler = Macros.handler[Donation]
private val minAmount = 200
// in $ cents
private def donatedByUser(userId: String): Fu[Int] =
coll.aggregate(
Match(decentAmount ++ BSONDocument("userId" -> userId)), List(
Group(BSONNull)("net" -> SumField("net"))
)).map {
~_.documents.headOption.flatMap { _.getAs[Int]("net") }
}
private val decentAmount = BSONDocument("gross" -> BSONDocument("$gte" -> BSONInteger(minAmount)))
def list(nb: Int) = coll.find(decentAmount)
.sort(BSONDocument("date" -> -1))
.cursor[Donation]()
.gather[List](nb)
def top(nb: Int): Fu[List[lila.user.User.ID]] = coll.aggregate(
Match(BSONDocument("userId" -> BSONDocument("$exists" -> true))), List(
GroupField("userId")("total" -> SumField("net")),
Sort(Descending("total")),
Limit(nb))).map {
_.documents.flatMap { _.getAs[String]("_id") }
}
def create(donation: Donation) = {
coll insert donation recover
lila.db.recoverDuplicateKey(e => println(e.getMessage)) void
}
}

View File

@ -1,30 +0,0 @@
package lila.donation
import com.typesafe.config.Config
import lila.common.PimpedConfig._
import scala.collection.JavaConversions._
final class Env(
config: Config,
db: lila.db.Env,
bus: lila.common.Bus) {
private val CollectionDonation = config getString "collection.donation"
private val WeeklyGoal = config getInt "weekly_goal"
def forms = DataForm
lazy val api = new DonationApi(
db(CollectionDonation),
WeeklyGoal,
bus = bus)
}
object Env {
lazy val current = "donation" boot new Env(
config = lila.common.PlayApp loadConfig "donation",
db = lila.db.Env.current,
bus = lila.common.PlayApp.system.lilaBus)
}

View File

@ -1,17 +0,0 @@
package lila.donation
import org.joda.time._
case class Progress(
from: DateTime,
goal: Int,
current: Int) {
val to = from plusWeeks 1
val remainingDays = Days.daysBetween(DateTime.now.toLocalDate, to.toLocalDate).getDays()
val percent = (current * 100) / goal
val complete = goal >= current
}

View File

@ -1,3 +0,0 @@
package lila
package object donation extends PackageObject with WithPlay

View File

@ -1,4 +1,4 @@
package lila.donation
package lila.plan
import play.api.data._
import play.api.data.Forms._

View File

@ -4,6 +4,7 @@ import lila.db.dsl._
import lila.user.{ User, UserRepo }
import org.joda.time.DateTime
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
final class PlanApi(
stripeClient: StripeClient,
@ -79,21 +80,21 @@ final class PlanApi(
}
def onPaypalCharge(
userId: String,
userId: Option[String],
email: Option[Patron.PayPal.Email],
subId: Option[Patron.PayPal.SubId],
cents: Cents,
name: Option[String],
txnId: Option[String]): Funit = (cents.value >= 500) ?? {
txnId: Option[String]): Funit = (cents.value >= 100) ?? {
chargeColl.insert(Charge.make(
userId = userId.some,
userId = userId,
payPal = Charge.PayPal(
name = name,
email = email.map(_.value),
txnId = txnId,
subId = subId.map(_.value)).some,
cents = cents)) >> {
UserRepo named userId flatMap {
cents = cents)) >>
(userId ?? UserRepo.named) flatMap {
_ ?? { user =>
userPatron(user).flatMap {
case None => patronColl.insert(Patron(
@ -113,7 +114,7 @@ final class PlanApi(
}
}
}
}
}
def onSubscriptionDeleted(sub: StripeSubscription): Funit =
@ -194,6 +195,14 @@ final class PlanApi(
def recentChargesOf(user: User): Fu[List[Charge]] =
chargeColl.find($doc("userId" -> user.id)).sort($doc("date" -> -1)).list[Charge]()
def topPatrons(nb: Int): Fu[List[User.ID]] = chargeColl.aggregate(
Match($doc("userId" $exists true)), List(
GroupField("userId")("total" -> SumField("cents")),
Sort(Descending("total")),
Limit(nb))).map {
_.documents.flatMap { _.getAs[String]("_id") }
}
private def getOrMakePlan(cents: Cents): Fu[StripePlan] =
stripeClient.getPlan(cents) getOrElse stripeClient.makePlan(cents)

View File

@ -57,7 +57,7 @@ object ApplicationBuild extends Build {
gameSearch, timeline, forum, forumSearch, team, teamSearch,
analyse, mod, site, round, lobby, setup,
importer, tournament, simul, relation, report, pref, // simulation,
evaluation, chat, puzzle, tv, coordinate, blog, donation, qa,
evaluation, chat, puzzle, tv, coordinate, blog, qa,
history, worldMap, opening, video, shutup, push,
playban, insight, perfStat, slack, quote, challenge,
study, fishnet, explorer, learn, plan)
@ -105,11 +105,6 @@ object ApplicationBuild extends Build {
libraryDependencies ++= provided(play.api, RM, prismic)
)
lazy val donation = project("donation", Seq(
common, db, user)).settings(
libraryDependencies ++= provided(play.api, RM)
)
lazy val evaluation = project("evaluation", Seq(
common, hub, db, user, game, analyse)).settings(
libraryDependencies ++= provided(play.api, RM)

View File

@ -1,61 +0,0 @@
.donate_box form {
margin: 20px 0;
}
.donate_box form input {
vertical-align: middle;
}
#site_header h2 {
font-size: 1.4em;
margin: 30px 0 10px 0;
}
#site_header .donors div {
padding: 5px 0;
}
#site_header a.user_link {
font-size: 1.1em;
font-weight: bold;
}
.donate_box .donors em {
font-style: italic;
}
.donate_box .block-img img {
width: 100%;
height: auto;
}
#site_header .progress {
color: #fff;
display: block;
}
#site_header .progress p {
color: #888;
}
#site_header .progress .progressbar {
position: relative;
height: 30px;
font-size: 1.2em;
font-weight: bold;
text-shadow: 0px 0px 3px rgba(0,0,0,0.8);
text-align: right;
line-height: 32px;
display: block;
}
#site_header .progress .current {
position:absolute;
top: 1px;
left: 1px;
z-index: 2;
height: 30px;
max-width: 100%;
font-size: 15px;
}
#site_header .progress .current span {
margin: 0 10px;
}
#site_header .progress .goal {
position: absolute;
right: 10px;
z-index: 1;
}
#site_header .progress p {
text-align: center;
}