diff --git a/.gitignore b/.gitignore index 1de35a0..fbde3b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,94 +1,6 @@ -# ---> Python -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# ---> Android -# Built application files -*.apk -*.ap_ - -# Files for the Dalvik VM -*.dex - -# Java class files -*.class - -# Generated files -bin/ -gen/ - -# Gradle files -.gradle/ -build/ - -# Local configuration file (sdk path, etc) -local.properties - -# Proguard folder generated by Eclipse -proguard/ - -# Log Files -*.log - -# Android Studio Navigation editor temp files -.navigation/ - -# Android Studio captures folder -captures/ - +sandbox +*.pyc +*.swp +*.swo +.gitignore +config.json diff --git a/init.sh b/init.sh index 132c58f..9220d1e 100644 --- a/init.sh +++ b/init.sh @@ -14,5 +14,15 @@ start(){ stop(){ ps -eo pid,command |grep python |grep $PWD |grep -E "^ {0,}[0-9]+" -o |xargs kill -9 } - +check(){ + pid=`ps -eo pid,command |grep python |grep $PWD |grep -E "^ {0,}[0-9]+" -o` + if [ "$pid" ]; then + echo "*** Online $pid" + else + echo "*** Offline" + fi +} +status(){ + check +} $1 diff --git a/src/Domain.py b/src/Domain.py index 0eabf9e..c99a7bb 100644 --- a/src/Domain.py +++ b/src/Domain.py @@ -1,5 +1,10 @@ """ - This class is designed to handle Clients + This class is designed to handle Customers in coordination with stripes. + + Identity Federation + A user with several emails should not have to pay for a service more than once because she has several email/cloud accounts. + We have therefore decided to tie several emails to a stripe customer identity + """ import stripe from couchdbkit import Server, Document @@ -23,27 +28,47 @@ class User: """ This function creates a stripe customer, and saves a copy with us for internal use We use couchdb as a cache of sorts - """ + @param uid customer's email + @param plans list of plans the user is subscribing + """ + def getId(self,uid): + r = self.db.view('federation/ids',key=uid) + if r.count() > 0 : + r = r.first() + return r['value'] + else: + None def init (self,uid,plans): customer = {} - if self.db.doc_exist(uid) : - self.user = self.db.get(uid) + id = self.getId(uid) + if id is not None: + self.user = self.db.get(id) + # if self.db.doc_exist(uid) : + # self.user = self.db.get(uid) + if self.stripeToken is not None: + + if 'sources' not in self.user or self.user['sources'] is None: + #@TODO: get the appropriate id + customer = stripe.Customer.retrieve(self.user['id']) + customer.source=self.stripeToken + customer.save() # self.hasPlan(uid,plan) has_plan = True if self.user is None and plans and stripe : # # First time customer, register them and sign them up for the first plan # - customer['source'] = str(self.stripeToken) + customer['sources'] = str(self.stripeToken) customer = self.stripe.Customer.create( source=self.stripeToken, email=uid ) ; + has_plan = False id = customer['id'] - self.user = {"_id":uid,"id":id} + self.user = {"_id":uid,"id":id,"source":self.stripeToken} else: # # The user exists but let's see if the user is subscribed to this plan @@ -52,7 +77,10 @@ class User: self.user = self.db.get(uid) ; id = self.user['id'] - + # + # If this user's isn't already subscribed we should subscribe her + # We perform a set operation to determine if she is alread susbscribed + # lsub = self.subscriptions() lplans = [str(item['plan']['id']) for item in lsub.data if item.ended_at in [None,""]] x_plans = [item['id'] for item in plans] @@ -62,7 +90,9 @@ class User: x = list(set(x_plans) - set(lplans)) plans = [ item for item in plans if item.id in x] else: - + # + # In case the user doesn't have any plans with us + # has_plan = False if has_plan == False : @@ -93,15 +123,28 @@ class User: def subscribe(self,id,plans): r = [] for plan in plans: - x = self.stripe.Subscription.create( - customer=id, - plan=plan['id'] - ) ; + if self.stripeToken is None: + sub = self.stripe.Subscription.create( + customer=id, + plan=plan['id'] + ) ; + else: + + customer = stripe.Customer.retrieve(id) + + self.user['sources'] = self.cast(customer.sources) + sub = self.stripe.Subscription.create( + customer=id, + plan=plan['id'], + source=self.stripeToken + ) ; + r.append(sub) + # # We need to create an invoiced item out of this plan # We will attach it later to an invoice ... # - r.append(x) + #r.append(x) return r """ This function will save card information @@ -122,7 +165,9 @@ class User: self.db.save_doc(user) ; self.user = user - def invoice(self,uid,plans,iid): + # + # Creating an invoice for this user + def invoice(self,uid,sid): self.user = self.db.get(uid) id = self.user['id'] r = [ stripe.InvoiceItem.create(customer=id,amount=item['amount'],currency=item['currency'],description=item['statement_descriptor'],subscription=item['subscription'],invoice=iid) for item in plans] diff --git a/src/api/index.py b/src/api/index.py index 2b6006e..f56de56 100644 --- a/src/api/index.py +++ b/src/api/index.py @@ -45,19 +45,32 @@ def subscribe(app_name): # # The name is the full name of the service # + resp = "0" + if 'stripeToken' in request.form : + stripeToken = request.form['stripeToken'] + uid = request.form['stripeEmail'] + tokenType = request.form['stripeTokenType'] + amount = request.form['amount'] + key = request.form['plan'] - key = request.headers['key'] - uid = request.headers['uid'] + else: + key = request.headers['key'] + uid = request.headers['uid'] + stripeToken = None plans = stripe.Plan.list().data plan = [item for item in plans if item.id == key] 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 : - couch_handler = Couchdb(uri=CONFIG['couchdb']['uri'],dbname=app_name,uid=uid) - DB = couch_handler.dbase - handler = Domain.User(DB,stripe) ; handler.init(uid,plan) - resp = plan[0].id - return resp + + + resp = plan[0].id + + return ('done',204) """ This function returns the meta data about a given plan or set of plans for a given application @resource app_name application identifier diff --git a/src/api/templates/subscribe.html b/src/api/templates/subscribe.html index 34473d2..07e8591 100644 --- a/src/api/templates/subscribe.html +++ b/src/api/templates/subscribe.html @@ -2,6 +2,7 @@ +{{app_name.replace('-',' ')}}