""" This file handles customer & plans associated with a given product/app The subscription works as follows: - """ from __future__ import division from flask import Flask, request, session, render_template,Response import Domain from couchdbkit import Server, Document import stripe import json from StringIO import StringIO import re import os from utils.params import PARAMS from utils.transport import Couchdb, CouchdbReader PORT = 8100 if 'port' not in PARAMS else int(PARAMS['port']) ; path = PARAMS['path'] #os.environ['CONFIG'] f = open(path) CONFIG = json.loads(f.read()) stripe_keys = { 'secret_key': CONFIG['stripe']['secret'].strip(), 'publishable_key': CONFIG['stripe']['pub'].strip() } stripe.api_key = stripe_keys['secret_key'].strip() app = Flask(__name__) """ This function will attempt to create an account for a user if the user does NOT exist Then Setup the stage for initialization of {signup for, user-account} """ COUCHDB = Server(uri=CONFIG['couchdb']['uri']) ; """ This function subscribes a user to a given service for an application This function guarantees not to duplicate subscriptions @resource name name of the application {cloud-music} @header key service/plan """ @app.route('/subscribe/',methods=['POST']) def subscribe(app_name): # # The name is the full name of the service # key = request.headers['key'] uid = request.headers['uid'] plans = stripe.Plan.list().data plan = [item for item in plans if item.id == key] resp = "0" if plan : couch_handler = Couchdb(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=uid) DB = couch_handler.dbase handler = Domain.User(DB,stripe) ; handler.init(uid,plan) resp = plan[0].id return resp """ This function returns the meta data about a given plan or set of plans for a given application @resource app_name application identifier @header pid plan identifier (optional) @header uid user identifier """ @app.route('/get/info/',methods=['GET']) def get_plan_info(app_name) : uid = request.headers['uid'] pid = request.headers['pid'] if 'pid' in request.headers else None couchdb = CouchdbReader(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=uid,create=False) info = couchdb.read() lsub = info['subscriptions'] plans = [ sub['plan'] for sub in lsub if sub['ended_at'] is None ] if pid is not None : plans = [item['metadata'] for item in plans if item['id'] == pid] return json.dumps(plans) @app.route('/get/sub/') def get_sub_info(app_name): uid = request.headers['uid'] pid = request.headers['pid'] if 'pid' in request.headers else None couchdb = CouchdbReader(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=uid,create=False) info = couchdb.read() lsub = info['subscriptions'] # # @TODO: Return critical information only i.e: # - subscription state (dates,status) # - how much is owed # - subscription id # if pid is not None: subs = [ sub for sub in lsub if sub['plan']['id'] == pid ] else: subs = lsub return json.dumps(subs) @app.route('/subscribe/',methods=['DELETE']) def cancel_subscribe(name) : pass """ This function defines if a given user is a customer or not We should be able to tell by how we create customers """ @app.route('/checkout/',methods=['GET']) def is_customer (app_name): uid = request.args.get('uid') pid = request.args.get('pid') couchdb = CouchdbReader(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=uid,create=False) info = couchdb.read() lsub = info['subscriptions'] plans = [dict(dict(item['plan'],**{"status":item['status']}),**{"subscription":item['id']}) for item in lsub] if pid is not None: plans = [item for item in plans if item['id'] == pid] # # Caching the subscription identifiers so we can create an invoice later on (if need be) # @TODO Improve this process later on by allowing user's to pay for what they can (not everything) # session['plans'] = plans # bill = {"amount":0,"count":0} # key = "" # if 'user-plans' in session : # plans = session['user-plans'] ; # amount = [plan['amount'] for plan in plans if plan['amount'] > 0] # if len(amount) > 0: # key = CONFIG['stripe']['pub'].strip() # bill['count'] = len(amount) # bill['amount']= sum(amount) html = """
""" session['plans'] amount = sum([item['amount'] for item in plans]) apikey = CONFIG['stripe']['pub'].strip() html = html.replace(":email",uid).replace(":amount",str(amount)).replace(":key",apikey) amount = amount / 100 return render_template('bill.html',apikey=apikey,app_name=app_name.replace('-',' '),plans=plans,total_amount=amount,html=html) """ This function is intended to performa an actual payment """ @app.route('/pay',methods=['POST']) def pay(): token = request.form['stripeToken'] uid = request.form['stripeEmail'] tokenType = request.form['stripeTokenType'] couchdb = CouchdbReader(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=uid,create=False) DB = couchdb.dbase #COUCHDB.get_db(CONFIG['couchdb']['db']) ; handler = Domain.User(DB,stripe) ; plans = session['plans'] # Assuming all is fine, we must do the following at this point # - create an invoice with the designated subscriptions # - create a charge on the invoice # # Let's insure the preconditions are met i.e # card,invoice info = session['user-info'] uid = info['_id'] if 'sources' not in info or token not in info['sources']: # # Let's create the card handler.save_card(uid,token) # # Let's create a charge here ... plans = session['user-plans'] amount=[item['price'] for item in plans if item['status'] == 'past_due' ] if len(amount) == 0: amount = 0 else: amount = sum(amount) handler.charge(uid,amount) session['user-info'] = handler.user return ('',204) #return render_template("bill.html",plans=plans, total_amount=amount) @app.route('/bill',methods=['GET']) def bill(): return render_template('bill.html') @app.route('/buy',methods=['POST']) def buy(): id = request.form['id'] ; if id in ['subscribe','now']: email = request.form['stripeEmail'] token = request.form['stripeToken'] user = Domain.User(DB,stripe,token) ; user.init(email) ; if user.exists() : print "Update with anything if need be" pass else: # # Create the user with the associated plan/or payment method # user.save() ; user.publish() else: pass return "0" """ This function provides general information about service plans @TODO: provide filtering criteria """ @app.route('/plans',methods=['GET']) def plans(): plans = stripe.Plan.list().data if 'filter' in request.headers: filter = request.headers['filter'] plans = [ item for item in plans if re.match(filter,item.name)] else: # # Let's get a user's subscription information # uid = request.headers['uid'] if 'uid' in request.headers and request.headers['uid'] != '': uid = request.headers['uid'] DB = COUCHDB.get_db(CONFIG['couchdb']['db']) ; handler = Domain.User(DB) handler.init(uid) myplans = [{"id":item.plan.id,"price":item.plan.amount/100,"feature":item.plan.metadata['info'],"status":item.status} for item in handler.subscriptions()] keys = [plan['id'] for plan in myplans] plans = [plan for plan in plans if plan['price'] > 0 and plan['id'] not in keys] plans = {'myplans':myplans,"plans":plans} session['user-plans'] = myplans plans = json.dumps(plans) return plans """ This function subscribes a user to a given plan(s) If the plan is new, then we do NOT need a credit card info @header app application/requesting service @body info {user:_id,plan:[]} """ @app.route('/_subscribe',methods=['POST']) def _subscribe(): if 'user-info' not in session: info = request.get_json(silent=True) user = info['user'] plans = info['plans'] else: plans = [{"id":id} for id in request.get_json(silent=True)] user = session['user-info'] app = request.headers['app'] # # @TODO: # This should be handled by transport layer ... # DB = COUCHDB.get_db(CONFIG['couchdb']['db']) ; handler = Domain.User(DB,stripe) r = handler.subscribe(user['id'],plans) return json.dumps(r) if __name__ == '__main__' : app.debug = True ; app.secret_key = '360-8y-[0v@t10n]+kr81v17y' app.run(port=PORT,threaded=True)