stripe sub cancellations

This commit is contained in:
ntr
2019-08-28 18:57:23 +10:00
parent 54a65fc160
commit d726aa8d33
13 changed files with 173 additions and 39 deletions
+3 -1
View File
@@ -146,6 +146,8 @@ fn main() {
let pg_pool = pool.clone();
let mailer = mail::listen(mail_rx);
let stripe = payments::stripe_client();
spawn(move || http::start(http_pool, mailer));
spawn(move || warden.listen());
spawn(move || warden::upkeep_tick(warden_tick_tx));
@@ -154,5 +156,5 @@ fn main() {
// the main thread becomes this ws listener
let rpc_pool = pool.clone();
rpc::start(rpc_pool, rpc_events_tx);
rpc::start(rpc_pool, rpc_events_tx, stripe);
}
+47 -3
View File
@@ -1,3 +1,4 @@
use std::env;
use std::io::Read;
use http::State;
@@ -12,15 +13,16 @@ use postgres::transaction::Transaction;
use failure::Error;
use failure::err_msg;
use stripe::{Event, EventObject, CheckoutSession, SubscriptionStatus};
use stripe::{Client, Event, EventObject, CheckoutSession, SubscriptionStatus};
use http::{MnmlHttpError};
use pg::{PgPool};
use account;
use account::Account;
pub fn subscription_account(tx: &mut Transaction, sub: String) -> Result<Uuid, Error> {
let query = "
SELECT account
SELECT account, customer, checkout, subscription
FROM stripe_subscriptions
WHERE subscription = $1;
";
@@ -34,6 +36,41 @@ pub fn subscription_account(tx: &mut Transaction, sub: String) -> Result<Uuid, E
Ok(row.get(0))
}
pub fn subscription_cancel(tx: &mut Transaction, client: &Client, account: &Account) -> Result<Option<String>, Error> {
let query = "
SELECT account, customer, checkout, subscription
FROM stripe_subscriptions
WHERE account = $1;
";
let result = tx
.query(query, &[&account.id])?;
let row = result.iter().next()
.ok_or(err_msg("user not subscribed"))?;
let _customer: String = row.get(1);
let _checkout: String = row.get(2);
let subscription: String = row.get(3);
let id = subscription.parse()?;
let mut params = stripe::UpdateSubscription::new();
params.cancel_at_period_end = Some(true);
let updated = match stripe::Subscription::update(client, &id, params) {
Ok(s) => s,
Err(e) => {
warn!("{:?}", e);
return Err(err_msg("unable to cancel subscription"));
}
};
info!("subscription cancelled account={:?} subscription={:?}", account, updated);
Ok(Some(updated.status.to_string()))
}
// we use i64 because it is converted to BIGINT for pg
// and we can losslessly pull it into u32 which is big
// enough for the ballers
@@ -45,7 +82,7 @@ const CREDITS_SUB_BONUS: i64 = 40;
// we ensure that we store each object in pg with a link to the object
// and to the account id in case of refunds
#[derive(Debug,Clone,Serialize,Deserialize)]
enum StripeData {
pub enum StripeData {
Customer { account: Uuid, customer: String, checkout: String },
Subscription { account: Uuid, customer: String, checkout: String, subscription: String, },
@@ -211,6 +248,13 @@ pub fn stripe(req: &mut Request) -> IronResult<Response> {
}
}
pub fn stripe_client() -> Client {
let secret = env::var("STRIPE_SECRET")
.expect("STRIPE_SECRET must be set");
stripe::Client::new(secret)
}
#[cfg(test)]
mod tests {
use super::*;
+17 -3
View File
@@ -11,6 +11,8 @@ use failure::err_msg;
use serde_cbor::{from_slice, to_vec};
use cookie::Cookie;
use stripe::Client as StripeClient;
use crossbeam_channel::{unbounded, Sender as CbSender};
use ws::{listen, CloseCode, Message, Handler, Request, Response};
@@ -23,6 +25,7 @@ use instance::{Instance, instance_state, instance_practice, instance_ready};
use item::{Item, ItemInfoCtr, item_info};
use mtx;
use mail;
use payments;
use mail::Email;
use pg::{Db};
use pg::{PgPool};
@@ -37,6 +40,7 @@ pub enum RpcMessage {
AccountTeam(Vec<Construct>),
AccountInstances(Vec<Instance>),
AccountShop(mtx::Shop),
AccountSubscription(Option<String>),
ConstructSpawn(Construct),
EmailState(Email),
GameState(Game),
@@ -44,6 +48,7 @@ pub enum RpcMessage {
InstanceState(Instance),
Pong(()),
DevResolutions(Resolutions),
@@ -75,6 +80,8 @@ enum RpcRequest {
AccountConstructs {},
AccountSetTeam { ids: Vec<Uuid> },
SubscriptionCancel {},
InstanceQueue {},
InstancePractice {},
InstanceReady { instance_id: Uuid },
@@ -92,6 +99,7 @@ struct Connection {
pub id: usize,
pub ws: CbSender<RpcMessage>,
pool: PgPool,
stripe: StripeClient,
account: Option<Account>,
events: CbSender<Event>,
}
@@ -192,6 +200,9 @@ impl Connection {
RpcRequest::MtxBuy { mtx } =>
Ok(RpcMessage::AccountShop(mtx::buy(&mut tx, account, mtx)?)),
RpcRequest::SubscriptionCancel { } =>
Ok(RpcMessage::AccountSubscription(payments::subscription_cancel(&mut tx, &self.stripe, account)?)),
_ => Err(format_err!("unknown request request={:?}", request)),
};
@@ -270,8 +281,10 @@ impl Handler for Connection {
// if the user queries the state of something
// we tell events to push updates to them
match reply {
RpcMessage::AccountState(ref v) =>
self.events.send(Event::Subscribe(self.id, v.id)).unwrap(),
RpcMessage::AccountState(ref v) => {
self.account = Some(v.clone());
self.events.send(Event::Subscribe(self.id, v.id)).unwrap()
},
RpcMessage::GameState(ref v) =>
self.events.send(Event::Subscribe(self.id, v.id)).unwrap(),
RpcMessage::InstanceState(ref v) =>
@@ -332,7 +345,7 @@ impl Handler for Connection {
}
}
pub fn start(pool: PgPool, events_tx: CbSender<Event>) {
pub fn start(pool: PgPool, events_tx: CbSender<Event>, stripe: StripeClient) {
let mut rng = thread_rng();
listen("127.0.0.1:40055", move |out| {
@@ -364,6 +377,7 @@ pub fn start(pool: PgPool, events_tx: CbSender<Event>) {
account: None,
ws: tx,
pool: pool.clone(),
stripe: stripe.clone(),
events: events_tx.clone(),
}
}).unwrap();