|
|
|
@ -1,13 +1,13 @@
|
|
|
|
|
"""
|
|
|
|
|
Steve L. Nyemba <steve@the-phi.com>
|
|
|
|
|
The Phi Technology, LLC - Store
|
|
|
|
|
|
|
|
|
|
This file handles customer & plans associated with a given product/app
|
|
|
|
|
We understand that a product will have multiple plans under it and we make sure that we always have a free version:
|
|
|
|
|
- Having a free product insures there is no excuse not to signup users
|
|
|
|
|
- If a product doesn't fall under this model we will find a way to fix it.
|
|
|
|
|
-
|
|
|
|
|
The store must be prefixed with an authentication module, because customers must be signed in before making a purchase.
|
|
|
|
|
Steve L. Nyemba <steve@the-phi.com>
|
|
|
|
|
The Phi Technology, LLC - Store
|
|
|
|
|
|
|
|
|
|
This file handles customer & plans associated with a given product/app
|
|
|
|
|
We understand that a product will have multiple plans under it and we make sure that we always have a free version:
|
|
|
|
|
- Having a free product insures there is no excuse not to signup users
|
|
|
|
|
- If a product doesn't fall under this model we will find a way to fix it.
|
|
|
|
|
-
|
|
|
|
|
The store must be prefixed with an authentication module, because customers must be signed in before making a purchase.
|
|
|
|
|
"""
|
|
|
|
|
from __future__ import division
|
|
|
|
|
from flask import Flask, request, session, render_template, Response,redirect
|
|
|
|
@ -15,7 +15,7 @@ from flask_session import Session
|
|
|
|
|
from flask_cors import CORS
|
|
|
|
|
from flask_pymongo import PyMongo
|
|
|
|
|
from flask_mongo_sessions import MongoDBSessionInterface
|
|
|
|
|
|
|
|
|
|
import transport
|
|
|
|
|
import stripe
|
|
|
|
|
import json
|
|
|
|
|
# from StringIO import StringIO
|
|
|
|
@ -46,419 +46,423 @@ stripe.api_key = stripe_keys['secret_key'].strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if 'CLOUDVIEW_CONTEXT' in os.environ and os.environ['CLOUDVIEW_CONTEXT'] not in CONFIG['cloud-view']:
|
|
|
|
|
context = os.environ['CLOUDVIEW_CONTEXT']
|
|
|
|
|
CONFIG['cloud-view'] = CONFIG['cloud-view'].replace('cloud-view',context)
|
|
|
|
|
|
|
|
|
|
context = os.environ['CLOUDVIEW_CONTEXT']
|
|
|
|
|
CONFIG['cloud-view'] = CONFIG['cloud-view'].replace('cloud-view',context)
|
|
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
CORS(app)
|
|
|
|
|
|
|
|
|
|
SYS_STORE = CONFIG['store']
|
|
|
|
|
|
|
|
|
|
LOGGER = transport.factory.instance(**SYS_STORE['logger'])
|
|
|
|
|
# @app.route("/donate")
|
|
|
|
|
# def _donate() :
|
|
|
|
|
|
|
|
|
|
# amount = float(request.args['amount']) if 'amount' in request.args else 5.0
|
|
|
|
|
# args = {'amount':amount,'context':CONTEXT}
|
|
|
|
|
# return render_template('donate.html',**args)
|
|
|
|
|
|
|
|
|
|
# amount = float(request.args['amount']) if 'amount' in request.args else 5.0
|
|
|
|
|
# args = {'amount':amount,'context':CONTEXT}
|
|
|
|
|
# return render_template('donate.html',**args)
|
|
|
|
|
def get_id(id):
|
|
|
|
|
return CONFIG['default']['id'] if not id else id
|
|
|
|
|
@app.route("/")
|
|
|
|
|
def index():
|
|
|
|
|
if 'default' in CONFIG:
|
|
|
|
|
id = CONFIG['default']['id']
|
|
|
|
|
return get_plans_ui(id)
|
|
|
|
|
headers = {"content-type":"application/json"}
|
|
|
|
|
mystore = store.factory.instance(name='music')
|
|
|
|
|
products = mystore.get.products()
|
|
|
|
|
args = {"context":CONTEXT,"products":products}
|
|
|
|
|
return json.dumps(products),headers
|
|
|
|
|
|
|
|
|
|
# return render_template("index.html",**args)
|
|
|
|
|
if 'default' in CONFIG:
|
|
|
|
|
id = CONFIG['default']['id']
|
|
|
|
|
return get_plans_ui(id)
|
|
|
|
|
|
|
|
|
|
headers = {"content-type":"application/json"}
|
|
|
|
|
mystore = store.factory.instance(name='music')
|
|
|
|
|
products = mystore.get.products()
|
|
|
|
|
args = {"context":CONTEXT,"products":products}
|
|
|
|
|
return json.dumps(products),headers
|
|
|
|
|
|
|
|
|
|
# return render_template("index.html",**args)
|
|
|
|
|
@app.route("/json/<id>")
|
|
|
|
|
def get_plans_json(id):
|
|
|
|
|
"""
|
|
|
|
|
This function returns the plans for a given product
|
|
|
|
|
"""
|
|
|
|
|
HEADER={"Content-type":"application/json"}
|
|
|
|
|
try:
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
return json.dumps(mystore.get.plans()),HEADER
|
|
|
|
|
except Exception as e:
|
|
|
|
|
#
|
|
|
|
|
# Log this shit or not
|
|
|
|
|
pass
|
|
|
|
|
return "[]",HEADER
|
|
|
|
|
"""
|
|
|
|
|
This function returns the plans for a given product
|
|
|
|
|
"""
|
|
|
|
|
HEADER={"Content-type":"application/json"}
|
|
|
|
|
try:
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
return json.dumps(mystore.get.plans()),HEADER
|
|
|
|
|
except Exception as e:
|
|
|
|
|
#
|
|
|
|
|
# Log this shit or not
|
|
|
|
|
pass
|
|
|
|
|
return "[]",HEADER
|
|
|
|
|
|
|
|
|
|
@app.route("/store",methods=['POST','PUT'])
|
|
|
|
|
def to_session():
|
|
|
|
|
"""
|
|
|
|
|
This function will store/persist session variables for reuse
|
|
|
|
|
"""
|
|
|
|
|
info = request.json
|
|
|
|
|
if info :
|
|
|
|
|
for key in info :
|
|
|
|
|
session[key] = info[key]
|
|
|
|
|
return "{}",200
|
|
|
|
|
"""
|
|
|
|
|
This function will store/persist session variables for reuse
|
|
|
|
|
"""
|
|
|
|
|
info = request.json
|
|
|
|
|
if info :
|
|
|
|
|
for key in info :
|
|
|
|
|
session[key] = info[key]
|
|
|
|
|
return "{}",200
|
|
|
|
|
@app.route("/signup",methods=['GET','POST'])
|
|
|
|
|
def signup():
|
|
|
|
|
"""
|
|
|
|
|
This function will signup a user to a plan or upgrade them if necessary
|
|
|
|
|
The assumption here is one product - one plan
|
|
|
|
|
:request.form stripeToken (optional)
|
|
|
|
|
"""
|
|
|
|
|
if request.method == 'GET' :
|
|
|
|
|
if 'auth' not in session :
|
|
|
|
|
return "0",403
|
|
|
|
|
_object = {"data-key":CONFIG['stripe']['pub'].strip()}
|
|
|
|
|
return json.dumps(_object),{"Content-Type":"application/json"}
|
|
|
|
|
else:
|
|
|
|
|
#
|
|
|
|
|
# We are receiving a call from stripe framework and we need create a charge for this
|
|
|
|
|
# @NOTE: https://stripe.com/docs/payments/accept-a-payment-charges#web-create-charge
|
|
|
|
|
token = request.form['stripeToken'] if 'stripeToken' in request.form else None
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
plan_id = session['plan']['id']
|
|
|
|
|
id = session['product']['name']
|
|
|
|
|
mystore = store.factory.instance(name=id,email=email)
|
|
|
|
|
user = mystore.user
|
|
|
|
|
plans = user.plan.info()
|
|
|
|
|
plans = [plans] if isinstance(plans,dict) else plans
|
|
|
|
|
|
|
|
|
|
has_plan = [1 for item in plans if item['id'] == plan_id]
|
|
|
|
|
if np.sum(has_plan) == 0 and len(plans) == 0:
|
|
|
|
|
|
|
|
|
|
mystore.subscribe(id=plan_id,email=email)
|
|
|
|
|
elif np.sum(has_plan)==0 and len(plans) > 0:
|
|
|
|
|
#
|
|
|
|
|
# We should upgrade/downgrade the current plan
|
|
|
|
|
#
|
|
|
|
|
mystore.plan.upgrade(plan_id,email)
|
|
|
|
|
uri = session['product']['metadata']['uri'] if 'uri' in session['product']['metadata'] else '#status'
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# @NOTE:
|
|
|
|
|
# This function assumes one product one plan, operations outside of this scope will require a new function
|
|
|
|
|
return """
|
|
|
|
|
<script>
|
|
|
|
|
window.location = ':uri'
|
|
|
|
|
</script>
|
|
|
|
|
""".replace(":uri",uri)
|
|
|
|
|
"""
|
|
|
|
|
This function will signup a user to a plan or upgrade them if necessary
|
|
|
|
|
The assumption here is one product - one plan
|
|
|
|
|
:request.form stripeToken (optional)
|
|
|
|
|
"""
|
|
|
|
|
if request.method == 'GET' :
|
|
|
|
|
if 'auth' not in session :
|
|
|
|
|
return "0",403
|
|
|
|
|
_object = {"data-key":CONFIG['stripe']['pub'].strip()}
|
|
|
|
|
return json.dumps(_object),{"Content-Type":"application/json"}
|
|
|
|
|
else:
|
|
|
|
|
#
|
|
|
|
|
# We are receiving a call from stripe framework and we need create a charge for this
|
|
|
|
|
# @NOTE: https://stripe.com/docs/payments/accept-a-payment-charges#web-create-charge
|
|
|
|
|
token = request.form['stripeToken'] if 'stripeToken' in request.form else None
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
plan_id = session['plan']['id']
|
|
|
|
|
id = session['product']['name']
|
|
|
|
|
mystore = store.factory.instance(name=id,email=email)
|
|
|
|
|
user = mystore.user
|
|
|
|
|
plans = user.plan.info()
|
|
|
|
|
plans = [plans] if isinstance(plans,dict) else plans
|
|
|
|
|
|
|
|
|
|
has_plan = [1 for item in plans if item['id'] == plan_id]
|
|
|
|
|
if np.sum(has_plan) == 0 and len(plans) == 0:
|
|
|
|
|
|
|
|
|
|
mystore.subscribe(id=plan_id,email=email)
|
|
|
|
|
elif np.sum(has_plan)==0 and len(plans) > 0:
|
|
|
|
|
#
|
|
|
|
|
# We should upgrade/downgrade the current plan
|
|
|
|
|
#
|
|
|
|
|
mystore.plan.upgrade(plan_id,email)
|
|
|
|
|
uri = session['product']['metadata']['uri'] if 'uri' in session['product']['metadata'] else '#status'
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# @NOTE:
|
|
|
|
|
# This function assumes one product one plan, operations outside of this scope will require a new function
|
|
|
|
|
return """
|
|
|
|
|
<script>
|
|
|
|
|
window.location = ':uri'
|
|
|
|
|
</script>
|
|
|
|
|
""".replace(":uri",uri)
|
|
|
|
|
|
|
|
|
|
# @app.route("/ui/signup/<id>",methods=['GET','PUT'])
|
|
|
|
|
@app.route("/<id>/signup",methods=['GET','PUT'])
|
|
|
|
|
def signup_form(id):
|
|
|
|
|
"""
|
|
|
|
|
This function loads the signup form with cloud-view authentication support
|
|
|
|
|
This allows us to know who is signing up or upgrading their plan
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
plans = mystore.get.plans()
|
|
|
|
|
index = int(request.args['index'])
|
|
|
|
|
plan = plans[index]
|
|
|
|
|
|
|
|
|
|
args = {"product":id,"label":mystore.product['statement_descriptor'],"plan":plan,"context":CONTEXT,"now":datetime.now().year}
|
|
|
|
|
args['theme'] = 'theme-clouds'
|
|
|
|
|
args['cloud-view'] = CONFIG['cloud-view']
|
|
|
|
|
|
|
|
|
|
return render_template("signup.html",**args)
|
|
|
|
|
"""
|
|
|
|
|
This function loads the signup form with cloud-view authentication support
|
|
|
|
|
This allows us to know who is signing up or upgrading their plan
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
plans = mystore.get.plans()
|
|
|
|
|
index = int(request.args['index'])
|
|
|
|
|
plan = plans[index]
|
|
|
|
|
|
|
|
|
|
args = {"product":id,"label":mystore.product['statement_descriptor'],"plan":plan,"context":CONTEXT,"now":datetime.now().year}
|
|
|
|
|
args['theme'] = 'theme-clouds'
|
|
|
|
|
args['cloud-view'] = CONFIG['cloud-view']
|
|
|
|
|
|
|
|
|
|
return render_template("signup.html",**args)
|
|
|
|
|
@app.route("/me")
|
|
|
|
|
def me ():
|
|
|
|
|
#
|
|
|
|
|
#{'user': {'uid': 'nyemba@gmail.com', 'uii': 'Steve Nyemba', 'usage': {'used': 1.012175691, 'size': 4.02653184, 'units': 'GB'}, 'sid': 'dropbox'}, 'key': 'nsfCKKUWunUAAAAAAAAAAUMzU6oR6qp9TK7t-_zop-sBOcEaM3eb1mRi_PG8bM69', 'features': {}}
|
|
|
|
|
|
|
|
|
|
# mystore = store.factory.instance(name = session['product']['name'])
|
|
|
|
|
# mystore.init(email=session['auth']['user']['uid'])
|
|
|
|
|
try:
|
|
|
|
|
if 'auth' in session and 'product' in session :
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
name = session['product']['name']
|
|
|
|
|
|
|
|
|
|
mystore = store.factory.instance(name=name,email=email)
|
|
|
|
|
payments = mystore.user.invoices()
|
|
|
|
|
|
|
|
|
|
cards = mystore.user.card.html() if mystore.user.card.exists() else None
|
|
|
|
|
|
|
|
|
|
_args = {'context':CONTEXT,"user":session['auth']['user'],"product":session['product'],"plan":session['plan'],"payments":payments,"cards":cards}
|
|
|
|
|
return render_template('me.html',**_args)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print (e)
|
|
|
|
|
pass
|
|
|
|
|
return render_template("none.html",context=CONTEXT)
|
|
|
|
|
# return redirect("http://healthcareio.the-phi.com")
|
|
|
|
|
#
|
|
|
|
|
#{'user': {'uid': 'nyemba@gmail.com', 'uii': 'Steve Nyemba', 'usage': {'used': 1.012175691, 'size': 4.02653184, 'units': 'GB'}, 'sid': 'dropbox'}, 'key': 'nsfCKKUWunUAAAAAAAAAAUMzU6oR6qp9TK7t-_zop-sBOcEaM3eb1mRi_PG8bM69', 'features': {}}
|
|
|
|
|
|
|
|
|
|
# mystore = store.factory.instance(name = session['product']['name'])
|
|
|
|
|
# mystore.init(email=session['auth']['user']['uid'])
|
|
|
|
|
try:
|
|
|
|
|
if 'auth' in session and 'product' in session :
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
name = session['product']['name']
|
|
|
|
|
|
|
|
|
|
mystore = store.factory.instance(name=name,email=email)
|
|
|
|
|
payments = mystore.user.invoices()
|
|
|
|
|
|
|
|
|
|
cards = mystore.user.card.html() if mystore.user.card.exists() else None
|
|
|
|
|
|
|
|
|
|
_args = {'context':CONTEXT,"user":session['auth']['user'],"product":session['product'],"plan":session['plan'],"payments":payments,"cards":cards}
|
|
|
|
|
return render_template('me.html',**_args)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print (e)
|
|
|
|
|
pass
|
|
|
|
|
return render_template("none.html",context=CONTEXT)
|
|
|
|
|
# return redirect("http://healthcareio.the-phi.com")
|
|
|
|
|
|
|
|
|
|
@app.route("/me/card",methods=['POST'])
|
|
|
|
|
def me_card ():
|
|
|
|
|
if 'auth' in session :
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
name = session['product']['name']
|
|
|
|
|
mystore = store.factory.instance(name=name,email = email)
|
|
|
|
|
body = request.json
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
mystore.user.card.add(card=body)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print (e)
|
|
|
|
|
return "0",200
|
|
|
|
|
return "1",200
|
|
|
|
|
# pricing = mystore.get.checkout() #-- pricing
|
|
|
|
|
# pricing = [{"unit_amount":500,"currency":"usd"},{"unit_amount":1000,"currency":"usd"},{"unit_amount":2500,"currency":"usd"}]
|
|
|
|
|
# args = {"product":session['product']}
|
|
|
|
|
else:
|
|
|
|
|
return "0",403
|
|
|
|
|
return render_template("card.html")
|
|
|
|
|
if 'auth' in session :
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
name = session['product']['name']
|
|
|
|
|
mystore = store.factory.instance(name=name,email = email)
|
|
|
|
|
body = request.json
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
mystore.user.card.add(card=body)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print (e)
|
|
|
|
|
return "0",200
|
|
|
|
|
return "1",200
|
|
|
|
|
# pricing = mystore.get.checkout() #-- pricing
|
|
|
|
|
# pricing = [{"unit_amount":500,"currency":"usd"},{"unit_amount":1000,"currency":"usd"},{"unit_amount":2500,"currency":"usd"}]
|
|
|
|
|
# args = {"product":session['product']}
|
|
|
|
|
else:
|
|
|
|
|
return "0",403
|
|
|
|
|
return render_template("card.html")
|
|
|
|
|
@app.route("/<id>/cancel",methods=['POST'])
|
|
|
|
|
def cancel(id):
|
|
|
|
|
#
|
|
|
|
|
# This function will cancel the user's current plan
|
|
|
|
|
STATUS = "1"
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
|
|
if 'auth' in session :
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
mystore = store.factory.instance(name=id,email=email)
|
|
|
|
|
_id = mystore.user.plan.sub_id()
|
|
|
|
|
mystore.cancel(_id)
|
|
|
|
|
session['plan'] = None
|
|
|
|
|
session['payments'] = mystore.user.invoices()
|
|
|
|
|
else:
|
|
|
|
|
STATUS = "0"
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print (e)
|
|
|
|
|
STATUS = "0"
|
|
|
|
|
pass
|
|
|
|
|
return STATUS,200
|
|
|
|
|
#
|
|
|
|
|
# This function will cancel the user's current plan
|
|
|
|
|
STATUS = "1"
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
|
|
if 'auth' in session :
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
mystore = store.factory.instance(name=id,email=email)
|
|
|
|
|
_id = mystore.user.plan.sub_id()
|
|
|
|
|
mystore.cancel(_id)
|
|
|
|
|
session['plan'] = None
|
|
|
|
|
session['payments'] = mystore.user.invoices()
|
|
|
|
|
else:
|
|
|
|
|
STATUS = "0"
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print (e)
|
|
|
|
|
STATUS = "0"
|
|
|
|
|
pass
|
|
|
|
|
return STATUS,200
|
|
|
|
|
# @app.route("/ui/<id>")
|
|
|
|
|
|
|
|
|
|
@app.route("/<id>/plans")
|
|
|
|
|
def get_plans_ui(id):
|
|
|
|
|
"""
|
|
|
|
|
This function loads the form for signup and information about the various plans for a given product.
|
|
|
|
|
:id name of the products
|
|
|
|
|
"""
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
#
|
|
|
|
|
# sort plans by
|
|
|
|
|
|
|
|
|
|
description = mystore.product['metadata']['about'] if 'about' in mystore.product['metadata'] else ''
|
|
|
|
|
label = mystore.product['statement_descriptor']
|
|
|
|
|
args = {"product":id,"label":label,"description":description,"context":CONTEXT,"plans":mystore.get.plans(),"now":datetime.now().year}
|
|
|
|
|
args['product'] = mystore.product
|
|
|
|
|
args['theme'] = 'theme-clouds'
|
|
|
|
|
# print (mystore.product.keys())
|
|
|
|
|
session['cloud-view'] = CONFIG['cloud-view'].replace(':id',id)
|
|
|
|
|
session['product'] = mystore.product
|
|
|
|
|
return render_template('plans.html',**args)
|
|
|
|
|
"""
|
|
|
|
|
This function loads the form for signup and information about the various plans for a given product.
|
|
|
|
|
:id name of the products
|
|
|
|
|
"""
|
|
|
|
|
id = get_id(id) #-- will return default if need be
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
#
|
|
|
|
|
# sort plans by
|
|
|
|
|
|
|
|
|
|
description = mystore.product['metadata']['about'] if 'about' in mystore.product['metadata'] else ''
|
|
|
|
|
label = mystore.product['statement_descriptor']
|
|
|
|
|
args = {"product":id,"label":label,"description":description,"context":CONTEXT,"plans":mystore.get.plans(),"now":datetime.now().year}
|
|
|
|
|
args['product'] = mystore.product
|
|
|
|
|
args['theme'] = 'theme-clouds'
|
|
|
|
|
session['cloud-view'] = CONFIG['cloud-view'].replace(':id',id)
|
|
|
|
|
session['product'] = mystore.product
|
|
|
|
|
return render_template('plans.html',**args)
|
|
|
|
|
@app.route("/goto/<id>",methods=['POST','GET'])
|
|
|
|
|
def redirect(id ) :
|
|
|
|
|
"""
|
|
|
|
|
This function will redirect to a given product page given a payload. The payload is intended to set the a session
|
|
|
|
|
:info
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
This function will redirect to a given product page given a payload. The payload is intended to set the a session
|
|
|
|
|
:info
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
args = {"context":CONTEXT,"product":mystore.product}
|
|
|
|
|
HEADER = {"Location":mystore.product['metadata']['uri']}
|
|
|
|
|
info = request.json
|
|
|
|
|
if info :
|
|
|
|
|
session['auth'] = info['auth']
|
|
|
|
|
session['plan'] = info['plan']
|
|
|
|
|
session['product'] = mystore.product
|
|
|
|
|
return "1",HEADER
|
|
|
|
|
else:
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
args = {"context":CONTEXT,"product":mystore.product}
|
|
|
|
|
HEADER = {"Location":mystore.product['metadata']['uri']}
|
|
|
|
|
info = request.json
|
|
|
|
|
if info :
|
|
|
|
|
session['auth'] = info['auth']
|
|
|
|
|
session['plan'] = info['plan']
|
|
|
|
|
session['product'] = mystore.product
|
|
|
|
|
return "1",HEADER
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
|
|
return "0",403
|
|
|
|
|
pass
|
|
|
|
|
return "0",403
|
|
|
|
|
pass
|
|
|
|
|
@app.route("/<id>/donate")
|
|
|
|
|
def donate (id) :
|
|
|
|
|
"""
|
|
|
|
|
This will charge a given user/card for a given product. i.e it is designed for a one-time payment
|
|
|
|
|
"""
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
# pricing = mystore.get.checkout() #-- pricing
|
|
|
|
|
pricing = [{"unit_amount":500,"currency":"usd"},{"unit_amount":1000,"currency":"usd"},{"unit_amount":2500,"currency":"usd"}]
|
|
|
|
|
args = {"product":mystore.product,"plans":mystore.get.plans(),"context":CONTEXT,"pricing":pricing}
|
|
|
|
|
|
|
|
|
|
return render_template("card.html",**args)
|
|
|
|
|
"""
|
|
|
|
|
This will charge a given user/card for a given product. i.e it is designed for a one-time payment
|
|
|
|
|
"""
|
|
|
|
|
mystore = store.factory.instance(name=id)
|
|
|
|
|
# pricing = mystore.get.checkout() #-- pricing
|
|
|
|
|
pricing = [{"unit_amount":500,"currency":"usd"},{"unit_amount":1000,"currency":"usd"},{"unit_amount":2500,"currency":"usd"}]
|
|
|
|
|
args = {"product":mystore.product,"plans":mystore.get.plans(),"context":CONTEXT,"pricing":pricing}
|
|
|
|
|
|
|
|
|
|
return render_template("card.html",**args)
|
|
|
|
|
@app.route("/<id>/pay")
|
|
|
|
|
def pay(id):
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
fname = session['auth']['user']['uii'].split(' ')[0] if 'uii' in session['auth']['user'] else ''
|
|
|
|
|
lname = " ".join(session['auth']['user']['uii'].split(' ')[1:]) if 'uii' in session['auth']['user'] else ''
|
|
|
|
|
mystore = store.factory.instance(name=id,email=email) #--
|
|
|
|
|
amount = session['plan']['amount']
|
|
|
|
|
# cards = mystore.user.card.html() if mystore.user.card.exists() else None
|
|
|
|
|
_args = {"product":mystore.product,"pricing":None,"context":CONTEXT,"email":email,"lname":lname,"fname":fname,"amount":amount} #,"cards":cards}
|
|
|
|
|
return render_template("card.html",**_args)
|
|
|
|
|
email = session['auth']['user']['uid']
|
|
|
|
|
fname = session['auth']['user']['uii'].split(' ')[0] if 'uii' in session['auth']['user'] else ''
|
|
|
|
|
lname = " ".join(session['auth']['user']['uii'].split(' ')[1:]) if 'uii' in session['auth']['user'] else ''
|
|
|
|
|
mystore = store.factory.instance(name=id,email=email) #--
|
|
|
|
|
amount = session['plan']['amount']
|
|
|
|
|
# cards = mystore.user.card.html() if mystore.user.card.exists() else None
|
|
|
|
|
_args = {"product":mystore.product,"pricing":None,"context":CONTEXT,"email":email,"lname":lname,"fname":fname,"amount":amount} #,"cards":cards}
|
|
|
|
|
return render_template("card.html",**_args)
|
|
|
|
|
|
|
|
|
|
@app.route("/html/dialog",methods=['POST'])
|
|
|
|
|
def get_dialog():
|
|
|
|
|
info = request.get_json()
|
|
|
|
|
|
|
|
|
|
_args = {"context":CONTEXT}
|
|
|
|
|
_args = dict(_args,**info)
|
|
|
|
|
return render_template('dialog.html',**_args)
|
|
|
|
|
info = request.get_json()
|
|
|
|
|
|
|
|
|
|
_args = {"context":CONTEXT}
|
|
|
|
|
_args = dict(_args,**info)
|
|
|
|
|
return render_template('dialog.html',**_args)
|
|
|
|
|
@app.route('/<id>/pay',methods=['POST','PUT'])
|
|
|
|
|
def _payme(id) :
|
|
|
|
|
info = request.get_json()
|
|
|
|
|
|
|
|
|
|
mystore = store.factory.instance(name=id,email=info['email'])
|
|
|
|
|
user = mystore.user
|
|
|
|
|
#
|
|
|
|
|
# ... Let us massage the data so it can go through properly
|
|
|
|
|
_args = {}
|
|
|
|
|
if 'has_card' not in info and not info['has_card'] :
|
|
|
|
|
card = {"number":info['number'],"cvc":info['cvc']}
|
|
|
|
|
card['exp_month'] = info['exp'].split("/")[0]
|
|
|
|
|
card['exp_year'] = info['exp'].split("/")[1]
|
|
|
|
|
card['name'] = " ".join([info["fname"],info["lname"]])
|
|
|
|
|
_args = {"email":info['email'],"amount":info['amount'],"currency":"usd"}
|
|
|
|
|
else:
|
|
|
|
|
#
|
|
|
|
|
# Let us make a payment using the source we already have
|
|
|
|
|
card = {}
|
|
|
|
|
_args['card'] = card
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# if a plan information is provided we are running the card for the plan ?
|
|
|
|
|
#
|
|
|
|
|
if 'plan' in session :
|
|
|
|
|
#
|
|
|
|
|
# We are dealing with a subscription here and we should run this through the subscription engine
|
|
|
|
|
# and NOT charge the user immediately (handled by stripe)
|
|
|
|
|
#
|
|
|
|
|
# _args['amount'] = info['plan']['amount']
|
|
|
|
|
plan = session['plan']
|
|
|
|
|
|
|
|
|
|
_args['metadata'] = {"payment":plan['nickname'],"product":id}
|
|
|
|
|
_args['plan'] = plan
|
|
|
|
|
#
|
|
|
|
|
# @TODO: If we have a card we must add it to the cards on file
|
|
|
|
|
#
|
|
|
|
|
if card :
|
|
|
|
|
user.card.add(card=card)
|
|
|
|
|
if user.plan.info() :
|
|
|
|
|
|
|
|
|
|
r = mystore.plan.upgrade(plan['id'],info['email'])
|
|
|
|
|
else:
|
|
|
|
|
r = mystore.plan.subscribe(id=plan['id'],email=info['email'])
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
#
|
|
|
|
|
# For now we consider this a donation or other payment
|
|
|
|
|
_args['metadata'] = {"payment":"charge","product":id}
|
|
|
|
|
_args['statement_descriptor'] = " ".join([str(info['amount']),id])
|
|
|
|
|
|
|
|
|
|
r = user.charge(**_args)
|
|
|
|
|
|
|
|
|
|
if not r :
|
|
|
|
|
msg,status = "Payment error enountered",403
|
|
|
|
|
else :
|
|
|
|
|
msg,status = "Payment accepted, Thank you", 200
|
|
|
|
|
return Response(msg,status=status)
|
|
|
|
|
def _payme(id) :
|
|
|
|
|
info = request.get_json()
|
|
|
|
|
|
|
|
|
|
mystore = store.factory.instance(name=id,email=info['email'])
|
|
|
|
|
user = mystore.user
|
|
|
|
|
#
|
|
|
|
|
# ... Let us massage the data so it can go through properly
|
|
|
|
|
_args = {}
|
|
|
|
|
if 'has_card' not in info and not info['has_card'] :
|
|
|
|
|
card = {"number":info['number'],"cvc":info['cvc']}
|
|
|
|
|
card['exp_month'] = info['exp'].split("/")[0]
|
|
|
|
|
card['exp_year'] = info['exp'].split("/")[1]
|
|
|
|
|
card['name'] = " ".join([info["fname"],info["lname"]])
|
|
|
|
|
_args = {"email":info['email'],"amount":info['amount'],"currency":"usd"}
|
|
|
|
|
else:
|
|
|
|
|
#
|
|
|
|
|
# Let us make a payment using the source we already have
|
|
|
|
|
card = {}
|
|
|
|
|
_args['card'] = card
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# if a plan information is provided we are running the card for the plan ?
|
|
|
|
|
#
|
|
|
|
|
if 'plan' in session :
|
|
|
|
|
#
|
|
|
|
|
# We are dealing with a subscription here and we should run this through the subscription engine
|
|
|
|
|
# and NOT charge the user immediately (handled by stripe)
|
|
|
|
|
#
|
|
|
|
|
# _args['amount'] = info['plan']['amount']
|
|
|
|
|
plan = session['plan']
|
|
|
|
|
|
|
|
|
|
_args['metadata'] = {"payment":plan['nickname'],"product":id}
|
|
|
|
|
_args['plan'] = plan
|
|
|
|
|
#
|
|
|
|
|
# @TODO: If we have a card we must add it to the cards on file
|
|
|
|
|
#
|
|
|
|
|
if card :
|
|
|
|
|
user.card.add(card=card)
|
|
|
|
|
if user.plan.info() :
|
|
|
|
|
|
|
|
|
|
r = mystore.plan.upgrade(plan['id'],info['email'])
|
|
|
|
|
else:
|
|
|
|
|
r = mystore.plan.subscribe(id=plan['id'],email=info['email'])
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
#
|
|
|
|
|
# For now we consider this a donation or other payment
|
|
|
|
|
_args['metadata'] = {"payment":"charge","product":id}
|
|
|
|
|
_args['statement_descriptor'] = " ".join([str(info['amount']),id])
|
|
|
|
|
|
|
|
|
|
r = user.charge(**_args)
|
|
|
|
|
|
|
|
|
|
if not r :
|
|
|
|
|
msg,status = "Payment error enountered",403
|
|
|
|
|
else :
|
|
|
|
|
msg,status = "Payment accepted, Thank you", 200
|
|
|
|
|
return Response(msg,status=status)
|
|
|
|
|
|
|
|
|
|
@app.route("/me/logout",methods=["POST","GET"])
|
|
|
|
|
@app.route("/me/logout",methods=["POST","GET"])
|
|
|
|
|
def logout():
|
|
|
|
|
session.clear()
|
|
|
|
|
return "1",200
|
|
|
|
|
|
|
|
|
|
session.clear()
|
|
|
|
|
return "1",200
|
|
|
|
|
|
|
|
|
|
@app.route("/init/<product>",methods=['POST'])
|
|
|
|
|
def init(product):
|
|
|
|
|
"""
|
|
|
|
|
This function initializes/logs a product to a given user, i.e it will create a session for users/product/plans
|
|
|
|
|
if the user has provided a user identifier it will be used as her primary email. The understanding is that a product may have multiple plans under it but always a free one
|
|
|
|
|
@param uid user's email (primary)
|
|
|
|
|
@param pid plan identifier
|
|
|
|
|
"""
|
|
|
|
|
#
|
|
|
|
|
# get product and plans
|
|
|
|
|
#
|
|
|
|
|
if 'uid' in request.headers :
|
|
|
|
|
uid = request.headers['uid']
|
|
|
|
|
plan_id = request.headers['pid'] if 'pid' in request.headers else None
|
|
|
|
|
else:
|
|
|
|
|
_info = request.json()
|
|
|
|
|
"""
|
|
|
|
|
This function initializes/logs a product to a given user, i.e it will create a session for users/product/plans
|
|
|
|
|
if the user has provided a user identifier it will be used as her primary email. The understanding is that a product may have multiple plans under it but always a free one
|
|
|
|
|
@param uid user's email (primary)
|
|
|
|
|
@param pid plan identifier
|
|
|
|
|
"""
|
|
|
|
|
#
|
|
|
|
|
# get product and plans
|
|
|
|
|
#
|
|
|
|
|
if 'uid' in request.headers :
|
|
|
|
|
uid = request.headers['uid']
|
|
|
|
|
plan_id = request.headers['pid'] if 'pid' in request.headers else None
|
|
|
|
|
else:
|
|
|
|
|
_info = request.json()
|
|
|
|
|
|
|
|
|
|
mystore = store.factory.instance(name=product,email=uid)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
user = mystore.user
|
|
|
|
|
user.init (uid)
|
|
|
|
|
if not user.plan.info() :
|
|
|
|
|
mystore.plan.subscribe(email = user.info()['email'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
features = user.plan.info()['metadata']['features'] if 'features' in user.plan.info()['metadata'] else {}
|
|
|
|
|
#
|
|
|
|
|
#@TODO: Log that uid, has initiated use of product
|
|
|
|
|
#
|
|
|
|
|
HEADERS ={"content-type":"application/json"}
|
|
|
|
|
mystore = store.factory.instance(name=product,email=uid)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
user = mystore.user
|
|
|
|
|
user.init (uid)
|
|
|
|
|
# prrint (user.plan.info())
|
|
|
|
|
if not user.plan.info() :
|
|
|
|
|
mystore.plan.subscribe(email = user.info()['email'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
features = user.plan.info()['metadata']['features'] if 'features' in user.plan.info()['metadata'] else {}
|
|
|
|
|
#
|
|
|
|
|
#@TODO: Log that uid, has initiated use of product
|
|
|
|
|
#
|
|
|
|
|
HEADERS ={"content-type":"application/json"}
|
|
|
|
|
|
|
|
|
|
return features,HEADERS
|
|
|
|
|
return features,HEADERS
|
|
|
|
|
@app.route("/<id>/init",methods=['POST','PUT'])
|
|
|
|
|
def _init(id):
|
|
|
|
|
return init(id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_plans(product) :
|
|
|
|
|
lproducts = stripe.Product.list()
|
|
|
|
|
lproducts = [item for item in lproducts.auto_paging_iter() if item.name == product ]
|
|
|
|
|
if lproducts :
|
|
|
|
|
product_id = lproducts[0].id
|
|
|
|
|
alias = lproducts[0].statement_descriptor
|
|
|
|
|
plans = stripe.Plan.list(product=product_id)
|
|
|
|
|
i = 0
|
|
|
|
|
for plan in plans :
|
|
|
|
|
plan['product_alias'] = alias if alias is not None else ''
|
|
|
|
|
if 'features' in plan['metadata']:
|
|
|
|
|
plan['metadata']['features'] = json.loads(plan['metadata']['features'])
|
|
|
|
|
plans[i] = plan
|
|
|
|
|
i += 1
|
|
|
|
|
if plans :
|
|
|
|
|
plans = plans.data
|
|
|
|
|
plans.sort(key = lambda x:x.amount)
|
|
|
|
|
|
|
|
|
|
return plans
|
|
|
|
|
else:
|
|
|
|
|
return []
|
|
|
|
|
lproducts = stripe.Product.list()
|
|
|
|
|
lproducts = [item for item in lproducts.auto_paging_iter() if item.name == product ]
|
|
|
|
|
if lproducts :
|
|
|
|
|
product_id = lproducts[0].id
|
|
|
|
|
alias = lproducts[0].statement_descriptor
|
|
|
|
|
plans = stripe.Plan.list(product=product_id)
|
|
|
|
|
i = 0
|
|
|
|
|
for plan in plans :
|
|
|
|
|
plan['product_alias'] = alias if alias is not None else ''
|
|
|
|
|
if 'features' in plan['metadata']:
|
|
|
|
|
plan['metadata']['features'] = json.loads(plan['metadata']['features'])
|
|
|
|
|
plans[i] = plan
|
|
|
|
|
i += 1
|
|
|
|
|
if plans :
|
|
|
|
|
plans = plans.data
|
|
|
|
|
plans.sort(key = lambda x:x.amount)
|
|
|
|
|
|
|
|
|
|
return plans
|
|
|
|
|
else:
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
# @app.route('/features/<product>')
|
|
|
|
|
@app.route('/<product>/features')
|
|
|
|
|
def features(product):
|
|
|
|
|
"""
|
|
|
|
|
This function returns the plan/features of a user for a given application if provided a uid (email)
|
|
|
|
|
if no uid are provided then the function will return all the plans/features associated with the given product
|
|
|
|
|
@header uid user's email
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
This function returns the plan/features of a user for a given application if provided a uid (email)
|
|
|
|
|
if no uid are provided then the function will return all the plans/features associated with the given product
|
|
|
|
|
@header uid user's email
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
plans = []
|
|
|
|
|
if 'uid' in request.headers :
|
|
|
|
|
uid = request.headers['uid']
|
|
|
|
|
couchdb = CouchdbReader(uri=CONFIG['couchdb']['uri'],dbname=product,uid=uid,create=False)
|
|
|
|
|
key = couchdb.view("users/uid_map",key=uid)
|
|
|
|
|
if key :
|
|
|
|
|
key = key[0]['value']
|
|
|
|
|
plans = couchdb.view('users/active_plan',key=key)
|
|
|
|
|
plans = [plan['value'] for plan in plans if 'value' in plan]
|
|
|
|
|
else:
|
|
|
|
|
plans = []
|
|
|
|
|
else:
|
|
|
|
|
plans = get_plans(product)
|
|
|
|
|
#
|
|
|
|
|
# formatting plans for the output
|
|
|
|
|
#
|
|
|
|
|
return json.dumps(plans),{"content-type":"application/json"}
|
|
|
|
|
plans = []
|
|
|
|
|
if 'uid' in request.headers :
|
|
|
|
|
uid = request.headers['uid']
|
|
|
|
|
couchdb = CouchdbReader(uri=CONFIG['couchdb']['uri'],dbname=product,uid=uid,create=False)
|
|
|
|
|
key = couchdb.view("users/uid_map",key=uid)
|
|
|
|
|
if key :
|
|
|
|
|
key = key[0]['value']
|
|
|
|
|
plans = couchdb.view('users/active_plan',key=key)
|
|
|
|
|
plans = [plan['value'] for plan in plans if 'value' in plan]
|
|
|
|
|
else:
|
|
|
|
|
plans = []
|
|
|
|
|
else:
|
|
|
|
|
plans = get_plans(product)
|
|
|
|
|
#
|
|
|
|
|
# formatting plans for the output
|
|
|
|
|
#
|
|
|
|
|
return json.dumps(plans),{"content-type":"application/json"}
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__' :
|
|
|
|
|
#
|
|
|
|
|
# setup mongodb session management (not sure why)
|
|
|
|
|
app.config['SESSION_TYPE'] = 'mongodb'
|
|
|
|
|
app.config['MONGO_URI'] = 'mongodb://localhost:27017'
|
|
|
|
|
app.config['SESSION_MONGODB_DB'] = 'sessions'
|
|
|
|
|
app.config['SESSION_MONGODB_COLLECT'] = 'store'
|
|
|
|
|
mongo = PyMongo(app)
|
|
|
|
|
app.session_interface = MongoDBSessionInterface(app,mongo.db, 'store')
|
|
|
|
|
#
|
|
|
|
|
# setup mongodb session management (not sure why)
|
|
|
|
|
#app.config['SESSION_TYPE'] = 'mongodb'
|
|
|
|
|
#app.config['MONGO_URI'] = 'mongodb://localhost:27017'
|
|
|
|
|
#app.config['SESSION_MONGODB_DB'] = CONFIG['store']['logger']['db']
|
|
|
|
|
#app.config['SESSION_MONGODB_COLLECT'] = 'session'
|
|
|
|
|
#mongo = PyMongo(app)
|
|
|
|
|
#app.session_interface = MongoDBSessionInterface(app,mongo.db, 'store')
|
|
|
|
|
|
|
|
|
|
app.debug = True ;
|
|
|
|
|
app.secret_key = '360-8y-[0v@t10n]+kr81v17y'
|
|
|
|
|
app.config['MAX_CONTENT_LENGTH'] = 1600 * 1024 * 1024
|
|
|
|
|
Session(app)
|
|
|
|
|
app.run(port=PORT,threaded=True,host='0.0.0.0')
|
|
|
|
|
# app.run() #'0.0.0.0',PORT,True,threaded=True)
|
|
|
|
|
app.debug = True ;
|
|
|
|
|
app.secret_key = '360-8y-[0v@t10n]+kr81v17y'
|
|
|
|
|
app.config['MAX_CONTENT_LENGTH'] = 1600 * 1024 * 1024
|
|
|
|
|
#Session(app)
|
|
|
|
|
app.run(port=PORT,threaded=True,host='0.0.0.0')
|
|
|
|
|
# app.run() #'0.0.0.0',PORT,True,threaded=True)
|
|
|
|
|