legacy
Steve L. Nyemba 5 years ago
parent 60bbaab3a9
commit f13f7cd567

@ -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 """
<script>
window.location = ':uri'
</script>
""".replace(":uri",uri)
@app.route("/ui/signup/<id>",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/<id>")
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/<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
"""
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/<product>",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)
@ -154,53 +204,55 @@ def init(product):
features = user.plan.info()['metadata']['features'] if 'features' in user.plan.info()['metadata'] else {}
print (features)
#
#@TODO: Log that uid, has initiated use of product
#
return json.dumps(features),200
@app.route('/subscribe/<product>',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']
# @app.route('/subscribe/<product>',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']
# 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)

@ -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}

@ -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(){}

@ -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 ()
@ -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:

@ -3,7 +3,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1">
<link rel="shortcut icon" href="{{context}}/static/img/logo-0.png">
<link rel="stylesheet" href="{{context}}/static/css/default.css" type="text/css">
<link href="{{ context }}/static/css/fa/css/font-awesome.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="{{context}}/static/css/dialog.css" type="text/css">
<script src="https://kit.fontawesome.com/ab15160345.js" crossorigin="anonymous"></script>
<!--
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.css" />
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid-theme.min.css" />
@ -18,6 +20,7 @@
<title style="text-transform: capitalize">{{product.replace('-',' ')}}</title>
<script>
sessionStorage.context = "{{context|safe}}"
var signup_form = function(index,caller){
@ -25,8 +28,21 @@
var httpclient = HttpClient.instance()
httpclient.get(url,function(x){
var html = x.responseText ;
jx.modal.show({html:html,id:'signup'})
bind( JSON.parse( $(caller).attr('data')) )
var data = JSON.parse($(caller).attr('data'))
jx.modal.show({html:html,id:'dialog'})
jx.dom.set.value('signup-plan',data.nickname)
if(data.amount == 0){
var price = 'Free'
}else{
var price = parseFloat(data.amount / 100 ).toFixed(2)
price = ([price, data.interval]).join(' / ')
}
jx.dom.set.value('plan-price',price)
//jx.dom.set.focus('email')
bind (data)
//bind( JSON.parse( $(caller).attr('data')) )
})
}
@ -55,10 +71,20 @@
// At this point we need to provide a screen to provide credit card information
// And or redirect to application framework
//
//var data = $(button).attr('data')
console.log(data)
console.log(data.id)
var http = HttpClient.instance()
var info = {"auth":p,"plan":data}
var httpclient = HttpClient.instance()
httpclient.setHeader("Content-Type","application/json")
httpclient.setData(JSON.stringify(info) )
httpclient.post('{{context|safe}}/store',function(x){})
if (data.amount == 0){
//
// We should not be prompting the user but automatically logging her into her session
//
redirect_now(p,data)
}else{
pay_now(p,data)
/*var http = HttpClient.instance()
http.get('{{context}}/signup',function(x){
x = JSON.parse(x.responseText)
@ -98,7 +124,9 @@
})
})*/
}
})
@ -106,6 +134,97 @@
})
})
}
/**
*/
var pay_now = function(auth,plan){
console.log("oO")
var http = HttpClient.instance()
http.get('{{context}}/signup',function(x){
x = JSON.parse(x.responseText)
var form = jx.dom.get.instance('FORM')
form.id = plan.id
form.method = 'POST'
form.action = '{{context}}/signup'
var script = jx.dom.get.instance('SCRIPT')
var input = jx.dom.get.instance('INPUT')
input.type = 'submit'
input.type = 'stripe-button'
script.setAttribute('data-key', x['data-key'].trim())
script.setAttribute('data-email', auth.user.uid)
script.setAttribute('data-name', plan.nickname)
script.setAttribute('data-amount', plan.amount)
script.setAttribute('data-description','{{description|safe}} ' + plan.nickname)
script.src = 'https://checkout.stripe.com/checkout.js'
script.setAttribute('data-amount',plan.amount)
script.setAttribute('data-image','https://s3.amazonaws.com/stripe-uploads/acct_15kiA1EUWsmgY81Amerchant-icon-1493912370912-logo-0.png')
script.setAttribute('data-label',(['Pay $',plan.amount,plan.interval]).join(' '))
script.className = 'stripe-button'
form.appendChild(script)
form.appendChild(input)
//jx.dom.set.value('form','')
//jx.dom.append('form',form)
jx.modal.close('signup')
$('#form').html('')
$('#form').append(form)
setTimeout(function(){
console.log('###')
$('.stripe-button-el').click()
},500)
})
}
/**
* This function will redirect the call to the product homepage
*/
var redirect_now = function(auth,plan){
var info = {'auth':auth,'plan':plan}
var http = HttpClient.instance()
http.setHeader('Content-Type','application/json')
http.setData(JSON.stringify(info))
http.post('{{context|safe}}/goto/{{product|safe}}',function(x){
var uri = x.getResponseHeader('location')
if (uri != null){
var icon= '<i class="fas fa-cog fa-spin fa-3x"></i>'
var msg = 'Redirecting to {{product|safe}}'
}else{
var icon= '<i class="fas fa-times fa-3x"></i>'
var msg = "Error found, please try again"
}
jx.dom.set.value('icon',icon)
jx.dom.set.value('message',msg)
$('.auth').slideUp(function(){
$('.dialog').slideDown()
})
setTimeout(()=>{
if(uri != null){
http = HttpClient.instance()
http.post('{{context|safe}}/signup',function(x){
window.location = uri
})
}else{
}
},1700)
})
}
</script>
<body >
@ -160,9 +279,9 @@
<div class="feature">
<div class="label">{{ key }}</div>
{% if value == True %}
<div class="status"><i class="fa fa-check"></i></div>
<div class="status"><i class="fas fa-check"></i></div>
{% elif value == False %}
<div class="status"><i class="fa fa-times"></i></div>
<div class="status"><i class="fas fa-times"></i></div>
{%else %}
<div class="status">{{value}}</div>
{% endif %}

@ -1,14 +1,9 @@
<meta charset="UTF-8">
<meta http-equiv="cache-control" content="no-cache">
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1">
<link rel="shortcut icon" href="{{context}}/static/img/logo-0.png">
<link rel="stylesheet" href="{{context}}/static/css/default.css" type="text/css">
<link href="{{context}}/static/css/fa/css/font-awesome.css" rel="stylesheet" type="text/css">
<!--
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.css" />
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid-theme.min.css" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.js"></script>
-->
<script type="text/javascript" src="{{ context }}/static/js/jquery/jquery.min.js"></script>
<script type="text/javascript" src="{{ context }}/static/js/jx/rpc.js"></script>
<script type="text/javascript" src="{{ context }}/static/js/jx/utils.js"></script>
@ -17,12 +12,12 @@
<title style="text-transform: capitalize">Signup {{product.replace('-',' ')}}</title>
<style>
.pane {
display:grid;
/*display:grid;
align-content: center;
grid-gap:1px;
grid-template-columns: 50% auto;
min-width:650px;
*/min-width:500px;
font-size:16px;
}
@ -72,17 +67,73 @@
}
.input-form input[type=text] {
padding:6px; width:100%;
padding:6px; width:99%;
margin:4px;
color:gray;
color:#000000;
border:2px solid transparent;
background-color:#f3f3f3;
}
.input-form input[type=text]:focus{
outline:none;
border-left-color:#4682b4 ;
}
i {font-size:18px;}
.more {display:none}
.dialog {display:none}
</style>
<body >
<div class="pane">
<div class="" style="display:grid; grid-template-columns:auto 48px; gap:1px">
<div class="bold border-bottom">Signup <span id="signup-plan" style="text-transform:capitalize"></span></div>
<div align="center" class="active" onclick="jx.modal.close()"><i class="fa fa-times" style="font-size:18px;"></i></div>
</div>
<div class="bold"><i class="fa fa-check"></i> <span id="plan-price" class="small"></span></div>
<div class="auth">
<p>
<div align="center" style="display:grid; align-content:center; justify-content:center" >
<div>
<input type="image" src="{{context}}/static/assets/google/normal.png" style="height:48px;" data-value="google-drive" plan-id="{{plan.id}}"/>
<div class="signup-button" data-value="dropbox" plan-id="{{plan.id}}">
<img src="{{context}}/static/img/accounts/dropbox.png">
<span>Dropbox</span>
</div>
<div class="less">
<span class="active" onclick="$('.less').slideUp('fast', function(){$('.more').slideDown()})"><i class="fa fa-chevron-down"></i></span>
</div>
</div>
<div class="more">
<p>
<div class="border-left border-bottom signup-button" data-value="one-drive" plan-id="{{plan.id}}">
<img src="{{context}}/static/img/accounts/microsoft.png"> <span>One Drive</span>
</div>
<div class="border-left border-bottom signup-button" data-value="box" plan-id="{{plan.id}}" align="center">
<img src="{{context}}/static/img/accounts/box.png"> <span>Signin</span>
</div>
</p>
</div>
</div>
</p>
</div>
</div>
<div class="dialog">
<div style="display:grid; grid-template-columns:48px auto; gap:2px; grid-gap:2px; align-items:center; margin-left:25%; width:50%">
<div id="icon">
<i class="fas fa-cog fa-3x fa-spin"></i>
</div>
<div id="message">
Redirecting
</div>
</div>
</div>
<!--
<div class="border-round {{theme}}">
<div class="border-bottom" align="right" style="padding:4px;">
<span class="active" onclick="jx.modal.close()">
@ -155,5 +206,6 @@
</div>
</div>
</div> -->
</body>
Loading…
Cancel
Save