diff --git a/src/api/index.py b/src/api/index.py
index 3c5b3ab..d3c32f7 100755
--- a/src/api/index.py
+++ b/src/api/index.py
@@ -10,11 +10,12 @@
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
+from flask import Flask, request, session, render_template
+from flask_session import Session
from flask_cors import CORS
-# import Domain
-# from User import User
-# from couchdbkit import Server, Document
+from flask_pymongo import PyMongo
+from flask_mongo_sessions import MongoDBSessionInterface
+
import stripe
import json
# from StringIO import StringIO
@@ -25,6 +26,9 @@ from transport import factory
# from store import Store
import store
from datetime import datetime
+import numpy as np
+import requests
+
# from utils.transport import Couchdb, CouchdbReader
PORT = 8100 if 'port' not in PARAMS else int(PARAMS['port']) ;
path = PARAMS['path'] #os.environ['CONFIG']
@@ -41,9 +45,8 @@ stripe.api_key = stripe_keys['secret_key'].strip()
app = Flask(__name__)
-# CORS(app)
-# COUCHDB = Server(uri=CONFIG['couchdb']['uri']) ;
-# SYS_STORE = CONFIG['couchdb']
+CORS(app)
+
SYS_STORE = CONFIG['store']
@app.route("/")
def index():
@@ -66,18 +69,67 @@ def get_plans_json(id):
# 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 "{}"
@app.route("/signup",methods=['GET','POST'])
-def get_stripe():
+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)
+ return json.dumps(_object),{"Content-Type":"application/json"}
else:
- print (request.args)
- return 1
+ #
+ # 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 """
+
+ """.replace(":uri",uri)
@app.route("/ui/signup/",methods=['GET','PUT'])
-def signup(id):
+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)
@@ -92,6 +144,10 @@ def signup(id):
return render_template("signup.html",**args)
@app.route("/ui/")
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
@@ -102,7 +158,28 @@ def get_plans_ui(id):
args['theme'] = 'theme-clouds'
# print (mystore.product.keys())
session['cloud-view'] = CONFIG['cloud-view']
+ session['product'] = mystore.product
return render_template('plans.html',**args)
+@app.route("/goto/",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
+ """
+
+ 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
@app.route("/init/",methods=['POST'])
def init(product):
"""
@@ -116,34 +193,7 @@ def init(product):
#
uid = request.headers['uid']
plan_id = request.headers['pid'] if 'pid' in request.headers else None
- #
- # We should just pull the factory method and get a storage handler to handle the logs
- #
- # store = dict(CONFIG['couchdb'])
- # store['dbname'] = product
- # user = User(stripe=stripe,store=store,product=product)
- # user.subscribe(uid,plan_id)
-
- # sub = None
- # if 'auid' in request.headers :
- # auid = request.headers['auid']
- # user.update(emails=auid)
- # user.post()
-
-
- # store = dict(CONFIG['couchdb'],**{})
- # store['dbname'] = product
- # store['uid'] = 'logs'
-
- # sub = user.get(uid,'subscriptions')
- # features = {}
- # for id in sub :
- # if sub[id]['active'] is True :
- # features[id] = sub[id]
-
- # user.refresh(uid)
- # session['key'] = user.user_key
- # session['uid'] = uid
+
mystore = store.factory.instance(name=product,email=uid)
@@ -153,54 +203,56 @@ def init(product):
mystore.plan.subscribe(email = user.info()['email'])
- features = user.plan.info()['metadata']['features'] if 'features' in user.plan.info()['metadata'] else {}
- print (features)
+ features = user.plan.info()['metadata']['features'] if 'features' in user.plan.info()['metadata'] else {}
+ #
+ #@TODO: Log that uid, has initiated use of product
+ #
return json.dumps(features),200
-@app.route('/subscribe/',methods=['POST'])
-def subscribe(product):
- """
- 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(product):
+# """
+# 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
+# """
- #
- # The name is the full name of the service
- #
- resp = "0"
- user = User(stripe=stripe,store=CONFIG['couchdb'],product=product)
- if 'stripeToken' in request.form :
- stripeToken = request.form['stripeToken']
- uid = request.form['stripeEmail']
- tokenType = request.form['stripeTokenType']
- amount = request.form['amount']
- pid = request.form['plan']
+# #
+# # The name is the full name of the service
+# #
+# resp = "0"
+# user = User(stripe=stripe,store=CONFIG['couchdb'],product=product)
+# if 'stripeToken' in request.form :
+# stripeToken = request.form['stripeToken']
+# uid = request.form['stripeEmail']
+# tokenType = request.form['stripeTokenType']
+# amount = request.form['amount']
+# pid = request.form['plan']
- else:
- pid = request.headers['pid'] if 'pid' in request.headers else None
- uid = request.headers['uid']
- stripeToken = None
- user.subscribe(uid,pid,stripeToken)
- if 'auid' in request.headers :
+# else:
+# pid = request.headers['pid'] if 'pid' in request.headers else None
+# uid = request.headers['uid']
+# stripeToken = None
+# user.subscribe(uid,pid,stripeToken)
+# if 'auid' in request.headers :
- if request.headers['auid'].startswith('[') or request.headers['auid'].startswith("{") :
- auid = json.loads(request.headers['auid'])
- else:
- auid = [request.headers['auid']]
- user.update(emails=auid)
- user.refresh(uid)
+# if request.headers['auid'].startswith('[') or request.headers['auid'].startswith("{") :
+# auid = json.loads(request.headers['auid'])
+# else:
+# auid = [request.headers['auid']]
+# user.update(emails=auid)
+# user.refresh(uid)
- reader = CouchdbReader(uri=SYS_STORE['uri'],dbname=product,uid=uid,create=False)
- plans = reader.view('users/active_plan',key=user.user_key) #me['_id'])
- #session['plans'] = plans
- session['key'] = user.user_key
- session['uid'] = uid
- session['active-plans'] = [item['id'] for item in plans]
- print (session['active-plans'])
- return (json.dumps(plans),200)
+# reader = CouchdbReader(uri=SYS_STORE['uri'],dbname=product,uid=uid,create=False)
+# plans = reader.view('users/active_plan',key=user.user_key) #me['_id'])
+# #session['plans'] = plans
+# session['key'] = user.user_key
+# session['uid'] = uid
+# session['active-plans'] = [item['id'] for item in plans]
+# print (session['active-plans'])
+# return (json.dumps(plans),200)
def get_plans(product) :
lproducts = stripe.Product.list()
@@ -342,9 +394,16 @@ def is_customer (app_name):
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')
+
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)
diff --git a/src/api/static/css/dialog.css b/src/api/static/css/dialog.css
new file mode 100644
index 0000000..1d60e1e
--- /dev/null
+++ b/src/api/static/css/dialog.css
@@ -0,0 +1,10 @@
+.dialog {
+ widows: 500px;
+}
+.dialog input[type=text]{
+ padding:8px;
+ width:100px;
+}
+.dialog .fa-check {color:#20B2AA; font-size:18px;}
+.dialog .fa-times{color:maroon}
+.dialog .title { display:grid; grid-template-columns: auto 32px; grid-gap:2px; gap:2px}
diff --git a/src/api/static/js/plans.js b/src/api/static/js/plans.js
new file mode 100644
index 0000000..7ff40e3
--- /dev/null
+++ b/src/api/static/js/plans.js
@@ -0,0 +1,7 @@
+/***
+ * This file has the functionalities to manage plans i.e signup users, bind controls and establish operational patterns
+ */
+var Plans = {}
+Plans.get = function(id){}
+Plans.ui = {}
+Plans.ui.bind = function(){}
\ No newline at end of file
diff --git a/src/api/store.py b/src/api/store.py
index fc48e77..cf42313 100644
--- a/src/api/store.py
+++ b/src/api/store.py
@@ -11,7 +11,7 @@ import json
class User :
def __init__(self,email,plans):
self.plans = plans
- self.me = {"plan":[],"customer":{},"payments":[]}
+ self.me = {"plan":[],"customer":{},"payments":[],"plan2sub":{}}
self.init(email)
self.format() #-- creating properties
pass
@@ -58,6 +58,7 @@ class User :
self.plan = void()
self.plan.info = lambda: self.me["plan"]
+ self.plan.sub_id = lambda: self.me['plan2sub'].get(self.plan.info()['id'],{})
# self.user.plan.cancel = lambda id: stripe.subscription.Subscription.delete(self.customer['id'],prorate=True,invoice_now=True)
self.card = void ()
@@ -66,7 +67,7 @@ class User :
self.card.charge = self.charge
self.card.html = lambda: [{} for card in self.me["payments"]]
self.card.delete = lambda index: stripe.customer.Customer.delete_source(self.me["customer"]['id'],self.me["payment"][index])
-
+
def init(self,email):
#
# get customer information
@@ -89,6 +90,12 @@ class User :
# self.plan.subscribe(free_plan['id'],email)
# self.customer = {"email":email,"id":customers['id']}
self.me["customer"] = {"email":email,"id":customer['id']}
+ lsub = customer.subscriptions.data
+ for sub in lsub :
+
+ id = sub.plan.id
+ self.me['plan2sub'][id] = sub.id
+
#
# extract payments available,
if 'sources' in customer and 'data' in customer['sources'] :
@@ -258,10 +265,11 @@ class Plans(Store) :
if not self.user and email:
self.user = User(email,self.plans)
- sub_id = self.user.plan.info()['id']
+ # sub_id = self.user.plan.info()['id']
+ sub_id = self.user.plan.sub_id()
try:
self.cancel(sub_id)
- self.subscribe(id,email)
+ r = self.subscribe(id=id,email=email)
#
# We need to reload everything
self.user.init(email)
@@ -306,6 +314,7 @@ class Plans(Store) :
# customer=self.user.info()['id'], #if not email else email,
# items=[plan]
# )
+
self.user.init(email)
return 1
else:
diff --git a/src/api/templates/plans.html b/src/api/templates/plans.html
index 11fa07e..b069761 100755
--- a/src/api/templates/plans.html
+++ b/src/api/templates/plans.html
@@ -3,7 +3,9 @@
-
+
+
+
+
+
@@ -17,12 +12,12 @@
Signup {{product.replace('-',' ')}}
-
+
+
+
+
+
+
+
+
+
+ Redirecting
+
+
+
+
+
+
\ No newline at end of file