enhancements, and bug fixes: no multiple subscriptions and update of plans

legacy
Steve L. Nyemba 6 years ago
parent 33ec166792
commit b41b1556be

@ -14,8 +14,8 @@ class User :
self.stripe = args["stripe"]
self.store = args['store']
self.store['dbname'] = args['product']
self.product = args['product']
self.store['dbname'] = str(args['product'])
self.product = str(args['product'])
self.me = {}
self.init()
@ -25,10 +25,13 @@ class User :
lproducts = [item for item in lproducts.auto_paging_iter() if item.name == self.product ]
if lproducts :
self.me['info'] = {"active":lproducts[0].active,"id":lproducts[0].id,"description":lproducts[0].statement_descriptor,"images":lproducts[0].images}
self.plans = self.stripe.Plan.list(product=lproducts[0].id)
self.plans = [item for item in self.plans.auto_paging_iter() ]
def init_customer(self,uid):
def init_customer(self,uid,pid):
"""
This function copies a customer to the internal database
This function copies a customer to the internal database.
This would allow the object to be in sync with what is available in stripe and we will save the content later on ...
"""
customer = self.stripe.Customer.list(email=uid)
if customer :
@ -37,20 +40,40 @@ class User :
#
# Insure the product is the one we are looking for ...
args = dict(self.store)
args['uid']=uid
reader = CouchdbReader(**args)
key = reader.view('users/uid_map',key=uid)
if not key :
self.store['uid'] = customer.id
self.update(_id=customer.id,emails=[uid])
#
# We need to update the user's subscription
#
product_id = self.me['info']['id']
info = {}
lsub = customer.subscriptions ;
info = {}
found = False
for sub in lsub.data :
if sub.plan.id == pid or sub.plan.product == product_id:
info[sub.plan.nickname] = sub.plan
self.update(subscriptions=info)
self.post()
#-- housekeeping work
else:
#
# The key exists we need to just read the user info in me
reader.uid = key
document = reader.read()
self.me = dict(self.me,**document)
self.user_key = customer.id
return customer
else:
return None
def update(self,**args):
for key in args :
value = args[key]
@ -66,19 +89,34 @@ class User :
self.me[key] = value
def post(self,**args):
document = dict(self.me,**{})
args = dict(self.store)
args['create'] = True
writer = CouchdbWriter(**args)
writer.set(self.me)
writer.set(document)
# writer.close()
def get_key(self,uid):
reader = CouchdbReader(**self.store)
key = reader.view('users/uid_map',key=uid)
if key :
if isinstance(key,list) :
key = key[0]['value']
elif 'value' in key :
key = key['value']
else:
key = None
return key
def get(self,uid,key):
args = dict(self.store)
args['uid'] = 'logs'
args['uid'] = self.get_key(uid)
if key not in self.me :
couchdb = CouchdbReader(**args)
document = couchdb.view('users/uid_map',key=uid)
return document
document = couchdb.basic_read()
return document[key] if key in document else {}
else:
return self.me[key]
# def plans(self,free=False):
# lproducts = self.stripe.Product.list()
# plans = [item for item in lproducts.auto_paging_iter() if item.name == self.product ]
@ -91,22 +129,14 @@ class User :
@param pid plan id
@param stripeToken stripe token to process payments
"""
# customer = self.stripe.Customer.list(email=uid).data
# if customer :
# customer = [item for item in customer if item.email == uid]
# customer = customer[0]
#
customer = self.init_customer(uid)
customer = self.init_customer(uid,pid)
product_id = self.me['info']['id']
if pid is None :
#
# In this block we try to find the free plan if one isn't specified
# The informtion about the product is already known (constructor)
#
# lproducts = self.stripe.Product.list()
# lproducts = [item for item in lproducts.auto_paging_iter() if item.name == self.product ]
product_id = self.me['info']['id']
plans = self.stripe.Plan.list(product=product_id)
plans = [item for item in plans.auto_paging_iter() if item.amount == 0 ]
plans = [item for item in self.plans if item.amount == 0]
pid = None if not plans else plans[0].id
if not customer :
@ -120,29 +150,14 @@ class User :
if stripeToken:
args['source'] = stripeToken
if customer.subscriptions.data :
lsub = customer.subscriptions ;
found = False
for sub in lsub.data :
if sub.plan.id == pid :
found = True
break
# for sub in lsub :
# found = [ for item in lsub.d
# found = [plan for plan in customer.subscriptions.data if plan.id == pid and plan.active == True]
# print " found ",len(found) > 0
else:
found = False
sub = self.me['subscriptions']
found = len([1 for plan_key in sub if sub[plan_key]['id'] == pid]) > 0
if found is False :
sub = self.stripe.Subscription.create(**args)
info = {sub.plan.nickname:sub.plan}
self.update(subscriptions=info)
self.post()
else:
pass
#
# keep a copy of this on our servers ...
#
@ -155,21 +170,27 @@ class User :
parent.store['uid'] = customer.id
lsub = customer.subscriptions
reader = CouchdbReader(**parent.store)
parent.me = reader.read()
_me = reader.read()
if 'emails' not in parent.me :
parent.me['emails'] = []
emails = list(set(parent.me['emails']) | set(_me['emails']))
parent.me = dict(parent.me,**_me)
parent.me['emails'] = emails
product_id = parent.me['info']['id']
[parent.update(subscriptions={sub.plan.nickname:sub.plan}) for sub in lsub.auto_paging_iter() if sub.plan.product == product_id and sub.plan.active == True]
parent.post()
reader = CouchdbReader(**self.store)
key = reader.view('users/uid_map',key=uid)
key = self.get_key(uid)
# reader = CouchdbReader(**self.store)
# key = reader.view('users/uid_map',key=uid)
# if key :
# if isinstance(key,list) :
# key = key[0]['value']
# elif 'value' in key :
# key = key['value']
if key :
if isinstance(key,list) :
key = key[0]['value']
elif 'value' in key :
key = key['value']
thread = Thread(target=_update,args=(key,))
thread.start()

@ -12,6 +12,7 @@ from __future__ import division
from flask import Flask, request, session, render_template,Response
from flask_cors import CORS
import Domain
from User import User
from couchdbkit import Server, Document
import stripe
import json
@ -37,6 +38,7 @@ stripe.api_key = stripe_keys['secret_key'].strip()
app = Flask(__name__)
CORS(app)
COUCHDB = Server(uri=CONFIG['couchdb']['uri']) ;
SYS_STORE = CONFIG['couchdb']
"""
This function will set the user information to the session and update the information
@header uid user email address
@ -49,18 +51,30 @@ def init(product):
@param uid user's email (primary)
@param pid plan identifier
"""
email = request.headers['uid']
plan_id = request.headers['pid']
uid = request.headers['uid']
plan_id = request.headers['pid'] if 'pid' in request.headers else None
user = User(stripe=stripe,store=CONFIG['couchdb'],product=product)
user.susbscribe(uid,plan_id)
user.subscribe(uid,plan_id)
sub = None
if 'auid' in request.headers :
auid = request.header['auid']
user.update(emails=auid)
user.post()
features = json.loads(users.me['subscriptions'][pid][0]['metadata'])
else:
features = user.get(uid,key)
user.refresh()
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
return json.dumps(features),200
# @app.route("/init/<app_name>",methods=['POST'])
@ -109,16 +123,16 @@ def init(product):
"""
This function will update the user's email
"""
@app.route('/init/<app_name>',methods=['PUT'])
def init_update(app_name):
uid = request.headers['uid']
id = session['customer.id']
couchdb = Couchdb(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=None)
DB = couchdb.dbase
handler = Domain.User(DB,stripe)
handler.update_user(uid=uid,id=id)
# @app.route('/init/<app_name>',methods=['PUT'])
# def init_update(app_name):
# uid = request.headers['uid']
# id = session['customer.id']
# couchdb = Couchdb(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=None)
# DB = couchdb.dbase
# handler = Domain.User(DB,stripe)
# handler.update_user(uid=uid,id=id)
return ('',204)
# return ('',204)
"""
@ -127,12 +141,13 @@ def init_update(app_name):
@resource name name of the application {cloud-music}
@header key service/plan
"""
@app.route('/subscribe/<app_name>',methods=['POST'])
def subscribe(app_name):
@app.route('/subscribe/<product>',methods=['POST'])
def subscribe(product):
#
# 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']
@ -141,43 +156,73 @@ def subscribe(app_name):
pid = request.form['plan']
else:
pid = request.headers['pid']
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 :
plans = stripe.Plan.list().data
plan = [item for item in plans if item.id == pid]
resp = "0"
couch_handler = Couchdb(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=uid)
DB = couch_handler.dbase
handler = Domain.User(DB,stripe,stripeToken) ;
if plan :
handler.init(uid,plan)
resp = plan[0].id
return ('',204)
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
return (json.dumps(plans),200)
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 []
@app.route('/features/<product>')
def features(product):
"""
This function returns the features of a user for a given application
The features are returned provided the plan is still valid i.e (end_date,status={active|trailing})
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
"""
@app.route('/features/<app_name>')
def features(app_name):
plans = []
if 'uid' in request.headers :
uid = request.headers['uid']
couchdb = CouchdbReader(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=uid,create=False)
handler = Domain.User(couchdb.dbase,stripe)
handler.initialize(uid)
lsub = handler.subscriptions()
plans = [ sub['plan'] for sub in lsub if sub['ended_at'] is None ]
plans = [item['metadata'] for item in plans if item['id']]
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)
"""
This function returns a user's plans/status for an application
@ -199,48 +244,31 @@ def status(app_name):
It will allow user's to be able to signup for various plans
@pre 'uid' in request.headers
"""
@app.route('/signup/<app_name>')
def get_plans(app_name) :
@app.route('/signup/<product>')
def signup(product) :
apikey = CONFIG['stripe']['pub'].strip()
#
# This function returns the plans for a given application
# We assume the application name is the prefix of the plan identifier in stripe
#
uid = session['uid'] if 'uid' in session else None
if 'user-info' in session :
_info = session['user-info']
session['uid'] = _info['uid']
uid = session['uid'] if 'uid' in session else ''
can_purchase = True
if uid is None :
uid = request.args.get('uid') if 'uid' in request.args else None
plans = stripe.Plan.list(limit=10)
# plans = handler.cast(plans.data)
plans = json.loads(json.dumps(plans.data, sort_keys=True, indent=2))
plans = [item for item in plans if re.match(app_name,item['name'])]
if uid is not None:
couchdb = Couchdb(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=uid,create=False)
handler = Domain.User(couchdb.dbase,stripe)
if handler.getId(uid) is not None:
handler.init(uid,[])
subs = handler.subscriptions().data
ids = [item.id for item in subs]
for item in plans :
if item['id'] in ids :
item['active'] = True
#
# let's determine if this user can make a purchase
#
else:
# #
# This should address any case of the database of customers being out of sync
# @TODO: Have a log suggesting a utility imports the customer
#
return json.dumps(plans)
plans = get_plans(product)
#
# @TODO: Mark the plans the current user is signed up for
#
return render_template('subscribe.html',context=CONTEXT,uid=uid,app_name=app_name,plans=plans,apikey=apikey)
platform='web' if 'platform' not in request.args else request.args['platform']
alias = plans[0]['product_alias']
active_plan = session['plans'] if 'plans' in session else []
print [' ** ',uid,active_plan]
return render_template('subscribe.html',context=CONTEXT,uid=uid,alias=alias,platform=platform,app_name=product,plans=plans,apikey=apikey)
@app.route('/subscribe/<name>',methods=['DELETE'])
def cancel_subscribe(name) :
@ -279,4 +307,5 @@ def is_customer (app_name):
if __name__ == '__main__' :
app.debug = True ;
app.secret_key = '360-8y-[0v@t10n]+kr81v17y'
app.run(port=PORT,threaded=True)
app.config['MAX_CONTENT_LENGTH'] = 1600 * 1024 * 1024
app.run(port=PORT,threaded=True,host='0.0.0.0')

@ -0,0 +1 @@
Subproject commit df17531499104b155e5ac97ee2755a8bf10bf8ff

@ -8,9 +8,13 @@
<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/jx/rpc.js"></script>
<script type="text/javascript" src="{{ context }}/static/js/jx/utils.js"></script>
<script type="text/javascript" src="{{ context }}/static/js/jx/dom.js"></script>
<title style="text-transform: capitalize">{{app_name.replace('-',' ')}}</title>
<style>
img {width:48px}
body{
font-family:sans-serif;
font-size:14px;
@ -28,6 +32,20 @@
font-family:sans-serif ;
text-transform:capitalize;
}
.plan {
padding:4px;
margin:4px;
border-radius: 4px;
border:1px solid #CAD5E0
}
.pricing {
display:grid;
grid-template-columns: repeat(auto-fit,minmax(250px, 1fr) )
}
.plan .title { font-size:24px; font-family:verdana; text-transform: capitalize; border-bottom:1px solid #CAD5E0; }
.plan .feature {display:grid; grid-template-columns: 60% 40%; grid-gap:4px; margin:4px}
.plan .feature .label {text-transform: uppercase; grid-column:1}
.plan .feature .status {font-size:20px; text-align: right}
.border-bottom{ border-bottom:1px solid #CAD5E0}
.border-right{ border-right:1px solid #CAD5E0}
.border-left{ border-left:1px solid #CAD5E0}
@ -37,7 +55,8 @@
.width-50{width:50%; padding:4px;}
.width-25{width:25%; padding:4px}
.height-48{height:48px;}
.fa-times {color:maroon}
.fa-check {color:green}
table { border:1px solid #CAD5E0;
border-radius:8px;
-webkit-border-radius:8px;
@ -70,44 +89,66 @@
}
@media only screen and (min-device-width: 320px){
table {width:99%}
img {width:28px}
.medium-caption {font-size:14px}
body {font-size:12px;}
.height-48{height:40px}
.width-50{width:47%; padding:4px;}
.width-25{width:24%; padding:4px}
.pricing {
display:block;
}
.plan .title { font-size:18px; font-family:verdana; text-transform: capitalize; border-bottom:1px solid #CAD5E0; }
.plan .feature {display:grid; grid-template-columns: 60% 40%; grid-gap:4px; margin:4px}
.plan .feature .label {font-size:12px; text-transform: uppercase; grid-column:1}
.plan .feature .status {font-size:16px; text-align: right}
.header{display:none}
.caption {font-size:20px}
}
@media only screen and (min-device-width: 768px){
body {font-size:12px}
.header img {width:48px}
.header {display:block}
table {width:70%; margin-left:20%}
.medium-caption {font-size:18px}
.width-50{width:50%; padding:4px;}
.width-25{width:25%; padding:4px}
.height-48{height:48px;}
.pricing {
display:grid;
grid-template-columns: repeat(auto-fit,minmax(250px, 1fr) )
}
.plan .title { font-size:24px; font-family:verdana; text-transform: capitalize; border-bottom:1px solid #CAD5E0; }
.plan .feature {display:grid; grid-template-columns: 60% 40%; grid-gap:4px; margin:4px}
.plan .feature .label {text-transform: uppercase; grid-column:1}
.plan .feature .status {font-size:20px; text-align: right}
}
</style>
<script>
</script>
<body >
<div>
{{active_plan}}
</div>
<br>
<div id="grid">
<table align="center" style="border-color:transparent">
<table align="center" class="header" style="border:1px solid transparent">
<tr>
<td style="width:60%">
<div align="left" class="default">
<img src="{{context}}/static/img/logo-0.png" style="width:48px; margin:4px" class="left" style="margin:4px">
<div style="padding:8px">The Phi Technology
<div class="small" style="text-transform:capitalize">{{ app_name }}</div>
<td style="width:80%" valign="bottom">
<div align="left">
<img src="{{context}}/static/img/logo-0.png" align="left" style="margin:4px">
<div style="padding:8px" >
<div class="caption">The Phi Technology</div>
<div class="small" style="text-transform:capitalize">{{ alias }}</div>
</div>
</div>
</td>
<td class="small" valign="middle">
<div>Call : 615-866-0454</div>
<div>Email: support@the-phi.com</div>
<td align="right" class="small" valign="bottom">
{{uid}}
</td>
</tr>
</table>
@ -116,47 +157,45 @@
<!-- style="background-image:url(https://az616578.vo.msecnd.net/files/responsive/cover/main/desktop/2016/05/09/635983505329496433385654456_concert-audience.jpg)"> -->
<tr >
<td colspan="{{ plans|length}}" align="center" class="border-bottom">
{% if alias %}
<div class="caption">{{alias.replace('-',' ') }}</div>
{% else %}
<div class="caption">{{app_name.replace('-',' ') }}</div>
{% endif %}
<div class="small">Available Plans</div>
</td>
</tr>
<tr>
<td>
<div class="pricing">
{% for item in plans%}
<div class="left width-50 height-48 border-right border-bottom" style="margin:4px">
<div class="bold medium-caption">{{ item.metadata.info|safe }}</div>
{% if 'note' in item.metadata %}
<div class="small" style="text-transform:capitalize; color:gray">{{item.metadata.note|safe}}</div>
{% endif %}
</div>
<div class="left width-25 height-48 border-bottom" style="margin:4px">
{% if item.amount > 0 %}
<div class="" align="center">{{ item.amount / 100 }}</div>
<div class="small" align="center"> {{item.currency.upper() }}/{{ item.interval.replace('month','Mo') }}</div>
<div class="plan">
<div class="title">{{ item.nickname }}</div>
{% for key,value in item.metadata['features'].iteritems() %}
<div class="feature">
<div class="label">{{ key }}</div>
{% if value == 1 %}
<div class="status"><i class="fa fa-check"></i></div>
{% else %}
<div class="bold medium-caption" align="center">Free</div>
<div class="status"><i class="fa fa-times"></i></div>
{% endif %}
</div>
<div class="left height-48 border-left border-bottom" style="margin:4px; padding:4px; width:15%" align="center">
{% if item.amount > 0 or item.active == True %}
<div class="action hidden" align="center">
<i class="fa fa-credit-card fa-2x" ></i>
{% endfor %}
{% if item.amount > 0 and platform != 'mobile' %}
<div align="right">
</div>
<div align="center">
<form action="{{context}}/subscribe/{{app_name|safe}}" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button action"
data-key="{{apikey|safe}}"
data-email="{{uid|safe}}"
data-amount={{item.amount|safe}}
data-name="{{item.metadata.info}}"
data-description="{{app_name }}"
data-name="{{item.nickname}}"
data-description="{{alias }}"
data-label="Signup"
data-label="Signup $ {{item.amount/100 }} / {{item.interval[:2]}}"
data-image="https://s3.amazonaws.com/stripe-uploads/acct_15kiA1EUWsmgY81Amerchant-icon-1493912370912-logo-0.png"
data-locale="auto">
@ -166,26 +205,24 @@
<input type="hidden" name="plan" value="{{item.id|safe}}"/>
</form>
</div>
{% else %}
<div align="center" class="left" style="margin:4px"><i class="fa fa-check fa-2x" style="color:green"></i> </div>
{% if item.amount > 0 %}
<div align="center" class="left" style="margin:4px"><i class="fa fa-times fa-2x" style="color:maroon"></i> </div>
{% elif item.amount == 0 and platform != 'mobile' %}
<br><div align="right" style="float:right; color:#4682B4; font-weight:bold;">Login, it's Free</div>
{% endif%}
{% endif %}
</div>
</div>
{% endfor %}
</div>
</td>
</tr>
<tr>
<td align="center" valign="middle" class="border-top">
<div>Your first subscription should be enabled Online</div>
<div>https://the-phi.com/store/subscribe</div>
<div class="small">support@the-phi.com</div>
</td>
</tr>
</table>
<br>
</div>
</body>

@ -261,6 +261,7 @@ class MessageQueue:
self.close()
return resp
def close(self):
if self.connection.is_closed == False :
self.channel.close()
self.connection.close()
"""
@ -351,7 +352,6 @@ class QueueReader(MessageQueue,Reader):
self.durable = False
self.size = -1
self.data = {}
def init(self,qid):
properties = pika.ConnectionParameters(host=self.host)
@ -368,6 +368,7 @@ class QueueReader(MessageQueue,Reader):
"""
def callback(self,channel,method,header,stream):
r = []
if re.match("^\{|\[",stream) is not None:
r = json.loads(stream)
@ -399,9 +400,12 @@ class QueueReader(MessageQueue,Reader):
# We enabled the reader to be able to read from several queues (sequentially for now)
# The qid parameter will be an array of queues the reader will be reading from
#
if isinstance(self.qid,basestring) :
self.qid = [self.qid]
for qid in self.qid:
self.init(qid)
# r[qid] = []
if self.info.method.message_count > 0:
self.channel.basic_consume(self.callback,queue=qid,no_ack=False);
@ -420,7 +424,7 @@ class QueueListener(QueueReader):
self.channel = self.connection.channel()
self.channel.exchange_declare(exchange=self.uid,type='direct',durable=True )
self.info = self.channel.queue_declare(exclusive=True,queue=qid)
self.info = self.channel.queue_declare(passive=True,exclusive=True,queue=qid)
self.channel.queue_bind(exchange=self.uid,queue=self.info.method.queue,routing_key=qid)
#self.callback = callback
@ -470,8 +474,6 @@ class Couchdb:
create = args['create'] if 'create' in args else False
if self.dbase.doc_exist(self.uid) == False and create == True:
self.dbase.save_doc({"_id":self.uid})
def view(self,id,**args):
return self.dbase.view(id,**args).all()
"""
Insuring the preconditions are met for processing
"""
@ -484,8 +486,13 @@ class Couchdb:
# We are also sure that the database actually exists
#
q = self.dbase.doc_exist(self.uid)
return p and q
if q == False:
return False
return True
def view(self,id,**args):
r =self.dbase.view(id,**args)
r = r.all()
return r[0]['value'] if len(r) > 0 else []
"""
This function will read an attachment from couchdb and return it to calling code. The attachment must have been placed before hand (otherwise oops)
@ -518,13 +525,14 @@ class CouchdbReader(Couchdb,Reader):
#
doc = self.dbase.get(self.uid)
q = doc is not None
if '_attachments' in doc:
r = self.filename in doc['_attachments'].keys()
else:
r = True
r = False
return p and q and r
return r
def stream(self):
content = self.dbase.fetch_attachment(self.uid,self.filename).split('\n') ;
i = 1
@ -555,6 +563,7 @@ class CouchdbWriter(Couchdb,Writer):
@param dbname database name (target)
"""
def __init__(self,**args):
Couchdb.__init__(self,**args)
uri = args['uri']
self.uid = args['uid']
@ -571,27 +580,53 @@ class CouchdbWriter(Couchdb,Writer):
def set(self,document):
_document = self.dbase.get(self.uid)
if _document :
document['_id'] = _document['_id']
document['_rev']= _document['_rev']
document = dict(document,**_document)
# if _document :
# document['_id'] = _document['_id']
# document['_rev']= _document['_rev']
self.dbase.save_doc(document)
def write(self,**params):
"""
write a given attribute to a document database
@param label scope of the row repair|broken|fixed|stats
@param row row to be written
"""
def write(self,**params):
document = self.dbase.get(self.uid)
label = params['label']
if 'row' in params :
row = params['row']
row_is_list = isinstance(row,list)
if label not in document :
document[label] = []
document[label] = row if row_is_list else [row]
elif isinstance(document[label][0],list) :
document[label].append(row)
else:
document[label] += row
else :
if label not in document :
document[label] = {}
if isinstance(params['data'],list) == False :
document[label] = dict(document[label],**params['data'])
else:
document[label] = params['data']
# if label not in document :
# document[label] = [] if isinstance(row,list) else {}
# if isinstance(document[label],list):
# document[label].append(row)
# else :
# document[label] = dict(document[label],**row)
self.dbase.save_doc(document)
def flush(self,**params) :
size = params['size']
size = params['size'] if 'size' in params else 0
has_changed = False
document = self.dbase.get(self.uid)
for key in document:
@ -599,7 +634,7 @@ class CouchdbWriter(Couchdb,Writer):
content = document[key]
else:
continue
if isinstance(content,list):
if isinstance(content,list) and size > 0:
index = len(content) - size
content = content[index:]
document[key] = content
@ -607,7 +642,7 @@ class CouchdbWriter(Couchdb,Writer):
else:
document[key] = {}
has_changed = True
if has_changed:
self.dbase.save_doc(document)
def archive(self,params=None):

Loading…
Cancel
Save