mirror of
https://github.com/gooba42/adventureland.git
synced 2026-10-14 10:33:47 -05:00
python3 compatibility + webapp to flask refactoring
This commit is contained in:
@@ -8,9 +8,16 @@
|
||||
/node/node_modules/
|
||||
/scripts/node_modules/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pem
|
||||
*.pub
|
||||
*.bak
|
||||
/scripts/test.js
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
/venv/
|
||||
/Resources/
|
||||
/lib/
|
||||
/include/
|
||||
*.cfg
|
||||
@@ -49,10 +49,11 @@ pip2.7 check
|
||||
|
||||
For MacOS pyenv makes sense as it prevents clash between Python versions and allows local versioning by just adding a .python-version to the folder https://github.com/pyenv/pyenv
|
||||
|
||||
Make sure to install lxml afterwards:
|
||||
Make sure to install lxml and Flask afterwards:
|
||||
|
||||
```sh
|
||||
pip2.7 install lxml
|
||||
pip2.7 install flask -t lib
|
||||
```
|
||||
|
||||
Run the Python2.7 backend - includes an HTTP server, datastore, various utilities - emulates Google App Engine:
|
||||
|
||||
@@ -1,218 +1,189 @@
|
||||
from config import *
|
||||
from functions import *
|
||||
|
||||
class Renderer(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
whtml(self,"utility/htmls/renderer.html",domain=gdi(self))
|
||||
def post(self): self.get()
|
||||
@app.route('/admin/make')
|
||||
@ndb.toplevel
|
||||
def serve_admin_maker():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or user.info.email!="your_email_here": return "no permission"
|
||||
user.admin=True
|
||||
user.put()
|
||||
return "done!"
|
||||
|
||||
class Events(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,tag):
|
||||
cursor=gdmul(self,"cursor")
|
||||
if not tag: tag="noteworthy"
|
||||
if tag=="all": events=Event.query().order(-Event.created)
|
||||
else: events=Event.query(Event.tag==tag).order(-Event.created)
|
||||
if cursor: events,ncursor,more=events.fetch_page(100,start_cursor=ndb.Cursor(urlsafe=cursor))
|
||||
else: events,ncursor,more=events.fetch_page(100)
|
||||
ncursor=more and ncursor.urlsafe()
|
||||
whtml(self,"utility/htmls/events.html",domain=gdi(self),events=events,ncursor=ncursor)
|
||||
def post(self,tag): self.get(tag)
|
||||
|
||||
@app.route('/admin/renderer')
|
||||
@ndb.toplevel
|
||||
def serve_render():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not getattr(user,"admin",False): return "no permission"
|
||||
return shtml("utility/htmls/renderer.html",domain=gdi(request))
|
||||
|
||||
@app.route('/admin/events/<tag>')
|
||||
@ndb.toplevel
|
||||
def serve_events(tag):
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not getattr(user,"admin",False): return "no permission"
|
||||
cursor=gdmul(request,"cursor")
|
||||
if not tag: tag="noteworthy"
|
||||
if tag=="all": events=Event.query().order(-Event.created)
|
||||
else: events=Event.query(Event.tag==tag).order(-Event.created)
|
||||
if cursor: events,ncursor,more=events.fetch_page(100,start_cursor=ndb.Cursor(urlsafe=cursor))
|
||||
else: events,ncursor,more=events.fetch_page(100)
|
||||
ncursor=more and ncursor.urlsafe()
|
||||
return whtml(request,"utility/htmls/events.html",domain=gdi(request),events=events,ncursor=ncursor)
|
||||
|
||||
def executor_task(the_code):
|
||||
self=None
|
||||
request=None
|
||||
try:
|
||||
exec(the_code)
|
||||
except:
|
||||
#admin_email(domain,"executor_task failed")
|
||||
log_trace()
|
||||
|
||||
class Executor(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
whtml(self,"utility/htmls/executor.html",domain=gdi(self))
|
||||
@ndb.toplevel
|
||||
def post(self):
|
||||
the_none="the_none_output_48"
|
||||
the_code,is_task=gdmul(self,"code","is_task"); output=the_none; json_output=None; json_size=0; html_output=the_none; output_html=the_none; inspect=the_none; ess=datetime.now()
|
||||
logging=custom_logging()
|
||||
#logging=code_logs
|
||||
if is_task:
|
||||
deferred.defer(executor_task,the_code,_queue="default")
|
||||
output="executor_task triggered"
|
||||
else:
|
||||
try:
|
||||
exec(the_code)
|
||||
except DeadlineExceededError: logging.error("Deadline Exceeded")
|
||||
except:
|
||||
log_trace_i("",logging)
|
||||
if json_output!=None: json_size=olen(json_output); json_output=json.dumps(recursive_datetime_conversion(json_output))
|
||||
if html_output!=the_none: output_html=html_output
|
||||
whtml(self,"utility/htmls/executor_output.html",logs=logging.output(),created=datetime.now(),ess_ms=mssince(ess),
|
||||
output=output,json=json_output,json_size=json_size,html_output=output_html,inspector_output=(inspect!=the_none and ginspect(inspect,force_inspection=1)))
|
||||
@app.route('/admin/executor',methods=['GET'])
|
||||
@ndb.toplevel
|
||||
def serve_executor_get():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not getattr(user,"admin",False): return "no permission"
|
||||
return whtml(request,"utility/htmls/executor.html",domain=gdi(request))
|
||||
|
||||
class CommunityMapEditor(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,name):
|
||||
if not name: return
|
||||
name=name.split("/")[0]
|
||||
#if not ((name in community_maps) or name.startswith("jayson_")): return
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
#if name.startswith("jayson_") and (not user or (user.k()+"") not in inner_circle): return
|
||||
map=get_by_iid("map|%s"%name)
|
||||
whtml(self,"utility/htmls/map_editor.html",domain=domain,name="main",map=map,tilesets=tilesets,community=1)
|
||||
@ndb.toplevel
|
||||
def post(self,name):
|
||||
data=self.request.get("data")
|
||||
name=name.split("/")[0]
|
||||
if not ((name in community_maps) or name.startswith("jayson_")): return self.response.out.write("Not Permitted!")
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
if name.startswith("jayson_") and (not user or (user.k()+"") not in inner_circle): return self.response.out.write("Not Permitted!")
|
||||
map=get_by_iid("map|%s"%name)
|
||||
if not map: map=Map(key=ndb.Key(Map,name),info=GG())
|
||||
map.info.data=json.loads(data)
|
||||
process_map(map)
|
||||
map.updated=datetime.now()
|
||||
map.put()
|
||||
copy_map(name,"test")
|
||||
self.response.out.write(to_pretty_num(olen(map.info.data)))
|
||||
|
||||
class ArtistMapEditor(webapp.RequestHandler):
|
||||
# from /admin/executor set the user.info.map_editor flag to True for artists, this also unlocks the interface in the game menu
|
||||
@ndb.toplevel
|
||||
def get(self,name):
|
||||
if not name: return
|
||||
name=name.split("/")[0]
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
if not user or not gf(user,"map_editor"): return self.response.out.write("Not Permitted!")
|
||||
map=get_by_iid("map|%s"%name)
|
||||
whtml(self,"utility/htmls/map_editor.html",domain=domain,name="main",map=map,tilesets=tilesets,community=1)
|
||||
@ndb.toplevel
|
||||
def post(self,name):
|
||||
data=self.request.get("data")
|
||||
name=name.split("/")[0]
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
if not user or not gf(user,"map_editor"): return self.response.out.write("Not Permitted!")
|
||||
map=get_by_iid("map|%s"%name)
|
||||
if not map: map=Map(key=ndb.Key(Map,name),info=GG())
|
||||
map.info.data=json.loads(data)
|
||||
process_map(map)
|
||||
map.updated=datetime.now()
|
||||
map.put()
|
||||
copy_map(name,"test")
|
||||
self.response.out.write(to_pretty_num(olen(map.info.data)))
|
||||
|
||||
class MapEditor(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,name):
|
||||
if not name: self.redirect("/admin/map_editor/main"); return
|
||||
name=name.split("/")[0]
|
||||
map=get_by_iid("map|%s"%name)
|
||||
whtml(self,"utility/htmls/map_editor.html",domain=gdi(self),name="main",map=map,tilesets=tilesets)
|
||||
@ndb.toplevel
|
||||
def post(self,name):
|
||||
data=self.request.get("data")
|
||||
name=name.split("/")[0]
|
||||
map=get_by_iid("map|%s"%name)
|
||||
if not map: map=Map(key=ndb.Key(Map,name),info=GG())
|
||||
map.info.data=json.loads(data)
|
||||
process_map(map)
|
||||
map.updated=datetime.now()
|
||||
map.put()
|
||||
copy_map(name,"test")
|
||||
self.response.out.write(to_pretty_num(olen(map.info.data)))
|
||||
|
||||
class Selector(webapp.RequestHandler): #NOTICE: << Publicly available at /communityselector! >> [10/10/16]
|
||||
@ndb.toplevel
|
||||
def get(self,name):
|
||||
if not name:
|
||||
whtml(self,"utility/htmls/imagesets/select-imageset.html",domain=gdi(self),imagesets=imagesets)
|
||||
return
|
||||
|
||||
name=name.split("/")[0]
|
||||
file=imagesets[name]["file"]
|
||||
size=imagesets[name]["size"]
|
||||
width=imagesets[name]["columns"]*size
|
||||
height=imagesets[name]["rows"]*size
|
||||
xs=[]; ys=[]
|
||||
for i in xrange(width/size): xs.append(i)
|
||||
for j in xrange(height/size): ys.append(j)
|
||||
whtml(self,"utility/htmls/imagesets/selector.html",domain=gdi(self),name=name,file=file,size=size,width=width,height=height,xs=xs,ys=ys,scale=3)
|
||||
def post(self,name): self.get(name)
|
||||
|
||||
class PhotoUpload(blobstore_handlers.BlobstoreUploadHandler):
|
||||
@ndb.toplevel
|
||||
def post(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
if security_threat(self,domain): return
|
||||
upload_files = self.get_file_infos('image'); file_info = upload_files[0]; blob_key=blobstore.create_gs_key_async(file_info.gs_object_name)
|
||||
key=gdmul(self,"key");
|
||||
logging.info("Image Upload %s"%(key))
|
||||
upload=get_by_iid("upload|%s"%key); blob_key=blob_key.get_result()
|
||||
if not upload: upload=Upload(key=ndb.Key(Upload,key),info=GG())
|
||||
@app.route('/admin/executor',methods=['POST'])
|
||||
@ndb.toplevel
|
||||
def serve_executor_post():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not getattr(user,"admin",False): return "no permission"
|
||||
the_none="the_none_output_48"
|
||||
the_code,is_task=gdmul(request,"code","is_task"); output=the_none; json_output=None; json_size=0; html_output=the_none; output_html=the_none; inspect=the_none; ess=datetime.now()
|
||||
logging=custom_logging()
|
||||
#logging=code_logs
|
||||
if is_task:
|
||||
deferred.defer(executor_task,the_code,_queue="default")
|
||||
output="executor_task triggered"
|
||||
else:
|
||||
try:
|
||||
exec(the_code)
|
||||
except DeadlineExceededError: logging.error("Deadline Exceeded")
|
||||
except:
|
||||
log_trace_i("",logging)
|
||||
if json_output!=None: json_size=olen(json_output); json_output=json.dumps(recursive_datetime_conversion(json_output))
|
||||
if html_output!=the_none: output_html=html_output
|
||||
return whtml(request,"utility/htmls/executor_output.html",logs=logging.output(),created=datetime.now(),ess_ms=mssince(ess),
|
||||
output=output,json=json_output,json_size=json_size,html_output=output_html,inspector_output=(inspect!=the_none and ginspect(inspect,force_inspection=1)))
|
||||
|
||||
|
||||
if file_info.content_type in ["image/jpg","image/jpeg","image/jpe","image/png","image/gif"]:
|
||||
if gf(upload,"blob_key"):
|
||||
try:
|
||||
blobstore.delete(blob_keys=upload.info.blob_key)
|
||||
logging.info("Old image deleted")
|
||||
except: log_trace()
|
||||
@app.route('/communitymaps/<name>',methods=['GET'])
|
||||
def serve_community_maps_get(name=""):
|
||||
if not name: return "no map"
|
||||
name=name.split("/")[0]
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
map=get_by_iid("map|%s"%name)
|
||||
return whtml(request,"utility/htmls/map_editor.html",domain=domain,name="main",map=map,tilesets=tilesets,community=1)
|
||||
|
||||
url=get_serving_url(blob_key,size=images.IMG_SERVING_SIZES_LIMIT)
|
||||
size=get_image_size(blob_key,encoding=filetype_to_image_encoding(file_info.content_type))
|
||||
|
||||
upload.info.blob_key=blob_key
|
||||
upload.info.content_type=file_info.content_type
|
||||
upload.info.gs_object_name=file_info.gs_object_name
|
||||
upload.info.url=url
|
||||
upload.info.width=size.width
|
||||
upload.info.height=size.height
|
||||
@ndb.toplevel
|
||||
@app.route('/communitymaps/<name>',methods=['POST'])
|
||||
def serve_community_maps_post(name=""):
|
||||
data=request.values.get("data")
|
||||
name=name.split("/")[0]
|
||||
if not ((name in community_maps) or name.startswith("jayson_")): return make_response("Not Permitted!")
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if name.startswith("jayson_") and (not user or (user.k()+"") not in inner_circle): return make_response("Not Permitted!")
|
||||
map=get_by_iid("map|%s"%name)
|
||||
if not map: map=Map(key=ndb.Key(Map,name),info=GG())
|
||||
map.info.data=json.loads(data)
|
||||
process_map(map)
|
||||
map.updated=datetime.now()
|
||||
map.put()
|
||||
copy_map(name,"test")
|
||||
return make_response(to_pretty_num(olen(map.info.data)))
|
||||
|
||||
self.response.out.write("{<br/> '%s':{'url':'%s','width':%s,'height':%s},<br />}"%(key,url,size.width,size.height))
|
||||
upload.put()
|
||||
else:
|
||||
blobstore.delete(blob_keys=blob_key)
|
||||
self.response.out.write("Not an image")
|
||||
def get(self): self.post()
|
||||
@app.route('/editmap')
|
||||
def serve_map_editor_redirect():
|
||||
return redirect(url_for('editmap/main'))
|
||||
|
||||
class PhotoUploader(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
if security_threat(self,domain): return
|
||||
upload_url=blobstore.create_upload_url('/admin/upload/handler',gs_bucket_name=domain.gcs_bucket+"/files")
|
||||
whtml(self,"utility/htmls/uploader.html",domain=domain,upload_url=upload_url)
|
||||
# from /admin/executor set the user.info.map_editor flag to True for artists, this also unlocks the interface in the game menu
|
||||
@app.route('/editmap/<name>',methods=['GET'])
|
||||
def serve_editmap_get(name=""):
|
||||
if not name: return "no map"
|
||||
name=name.split("/")[0]
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not (gf(user,"map_editor") or getattr(user,"admin",False)): return make_response("Not Permitted!")
|
||||
map=get_by_iid("map|%s"%name)
|
||||
return whtml(request,"utility/htmls/map_editor.html",domain=domain,name=name,map=map,tilesets=tilesets,community=1)
|
||||
|
||||
class Items(webapp.RequestHandler): #NOTICE: << Publicly available at /communityitems! >> [10/10/16]
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self)
|
||||
#if not is_current_user_admin():
|
||||
# user=get_user(self,domain)
|
||||
# if not user or user.k()+"" not in [ellian_id,hello_id]: return
|
||||
mode,items=gdmul(self,"mode","items")
|
||||
whtml(self,"utility/htmls/items.html",domain=domain,mode=mode,items=items)
|
||||
def post(self): self.get()
|
||||
@ndb.toplevel
|
||||
@app.route('/editmap/<name>',methods=['POST'])
|
||||
def serve_editmap_post(name=""):
|
||||
data=request.values.get("data")
|
||||
name=name.split("/")[0]
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not (gf(user,"map_editor") or getattr(user,"admin",False)): return make_response("Not Permitted!")
|
||||
map=get_by_iid("map|%s"%name)
|
||||
if not map: map=Map(key=ndb.Key(Map,name),info=GG())
|
||||
map.info.data=json.loads(data)
|
||||
process_map(map)
|
||||
map.updated=datetime.now()
|
||||
map.put()
|
||||
copy_map(name,"test")
|
||||
return make_response(to_pretty_num(olen(map.info.data)))
|
||||
|
||||
class Backups(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,m,id):
|
||||
domain=gdi(self)
|
||||
backups=Backup.query(Backup.backup_item_id=="%s|%s"%(m,id)).order(-Backup.backup_created).fetch(50)
|
||||
whtml(self,"utility/htmls/backups.html",domain=domain,backups=backups)
|
||||
def post(self,m,id): self.get(m,id)
|
||||
@app.route('/admin/selector')
|
||||
@app.route('/communityselector')
|
||||
def serve_selector_options():
|
||||
return whtml(request,"utility/htmls/imagesets/select-imageset.html",domain=gdi(request),imagesets=imagesets)
|
||||
|
||||
application = webapp.WSGIApplication([
|
||||
('/admin/renderer', Renderer),
|
||||
('/admin/executor', Executor),
|
||||
('/admin/items', Items),
|
||||
('/admin/upload', PhotoUploader),
|
||||
('/admin/upload/handler', PhotoUpload),
|
||||
('/admin/backups/(.*)/(.*)', Backups),
|
||||
('/admin/events/?(.*)', Events),
|
||||
('/admin/map_editor/?(.*)', MapEditor),
|
||||
('/admin/selector/?(.*)', Selector),
|
||||
('/admin/items', Items),
|
||||
],debug=is_sdk)
|
||||
@app.route('/admin/selector/<name>')
|
||||
@app.route('/communityselector/<name>') #NOTICE: << Publicly available at /communityselector! >> [10/10/16]
|
||||
def serve_selector(name=""):
|
||||
name=name.split("/")[0]
|
||||
file=imagesets[name]["file"]
|
||||
size=imagesets[name]["size"]
|
||||
width=imagesets[name]["columns"]*size
|
||||
height=imagesets[name]["rows"]*size
|
||||
xs=[]; ys=[]
|
||||
for i in xrange(width/size): xs.append(i)
|
||||
for j in xrange(height/size): ys.append(j)
|
||||
return whtml(request,"utility/htmls/imagesets/selector.html",domain=gdi(request),name=name,file=file,size=size,width=width,height=height,xs=xs,ys=ys,scale=3)
|
||||
|
||||
#TODO: Re-implement uploaders at uploaders.py
|
||||
|
||||
@app.route('/admin/items')
|
||||
@app.route('/communityitems') #NOTICE: << Publicly available at /communityitems! >> [10/10/16]
|
||||
def serve_items():
|
||||
domain=gdi(request)
|
||||
#if not is_current_user_admin():
|
||||
# user=get_user(self,domain)
|
||||
# if not user or user.k()+"" not in [ellian_id,hello_id]: return
|
||||
mode,items=gdmul(request,"mode","items")
|
||||
return whtml(request,"utility/htmls/items.html",domain=domain,mode=mode,items=items)
|
||||
|
||||
@app.route('/admin/backups/<m>/<id>')
|
||||
@ndb.toplevel
|
||||
def serve_backups(m,id):
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not getattr(user,"admin",False): return "no permission"
|
||||
backups=Backup.query(Backup.backup_item_id=="%s|%s"%(m,id)).order(-Backup.backup_created).fetch(50)
|
||||
whtml(request,"utility/htmls/backups.html",domain=domain,backups=backups)
|
||||
|
||||
@app.route('/admin/ips')
|
||||
def serve_ips():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not getattr(user,"admin",False): return "no permission"
|
||||
def ip_to_html(ip):
|
||||
return "<div style='margin-bottom: 2px'>%s {%s} [%s]</div>"%(ip.info.explanation,ip.random_id,ip.info.limit)
|
||||
html="<style> html{background-color:gray}</style>"
|
||||
for ip in IP.query(IP.exception==True).fetch(5000): html+=ip_to_html(ip)
|
||||
return html
|
||||
|
||||
@app.route('/admin/visualize/<name>')
|
||||
def serve_visualize(name=""):
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not getattr(user,"admin",False): return "no permission"
|
||||
character=get_character(name)
|
||||
if not character: return whtml(request,"htmls/simple_message.html",domain=domain,message="Not Found")
|
||||
characters=[character]
|
||||
for c in Backup.query(Backup.backup_item_id==character.k('i')).order(-Backup.backup_created).fetch(80):
|
||||
c.name=c.info.name="%s%s"%(c.info.name,(datetime.now()-c.backup_created).days)
|
||||
logging.info(c.info.slots["mainhand"]["name"])
|
||||
characters.append(c)
|
||||
domain.title=character.info.name
|
||||
return whtml(request,"htmls/player.html",domain=domain,characters=characters)
|
||||
|
||||
@@ -87,7 +87,7 @@ def signup_or_login_api(**args):
|
||||
{"type":"success","message":"Signup Complete!" },
|
||||
selection_info(self,user,domain),
|
||||
])
|
||||
add_event(user,"signup",["new","noteworthy"],self=self,info=cGG(message="Signup %s"%(user.info.email)),async=True)
|
||||
add_event(user,"signup",["new","noteworthy"],self=self,info=cGG(message="Signup %s"%(user.info.email)),_async=True)
|
||||
increase_signupth()
|
||||
|
||||
try:
|
||||
@@ -503,7 +503,7 @@ def create_character_api(**args):
|
||||
{"type":"success","message":"%s is alive!"%name },
|
||||
selection_info(self,owner,domain),
|
||||
])
|
||||
add_event(owner,"new_character",["characters","noteworthy"],self=self,info=cGG(message="New Character %s from %s"%(character.info.name,user.info.email)),backup=True,async=True)
|
||||
add_event(owner,"new_character",["characters","noteworthy"],self=self,info=cGG(message="New Character %s from %s"%(character.info.name,user.info.email)),backup=True,_async=True)
|
||||
increase_characterth()
|
||||
|
||||
def sort_characters_api(**args):
|
||||
@@ -846,8 +846,8 @@ def cli_time_api(**args):
|
||||
if result:
|
||||
logging.info(result)
|
||||
return jhtmlm(self,"Purchased 7 more days of CLI time for %s shells! You have: %.2d"%(amount,-dsince(result.cli_time)))
|
||||
if amount>0: add_event(result,"bill",["cashflow"],self=self,info=cGG(message="%s [%s] spent %s shells for: %s"%(name,user.k(),amount,reason),amount=amount,reason=reason),async=True)
|
||||
else: add_event(result,"ishells",["cashflow"],self=self,info=cGG(message="%s [%s] received %s shells from: %s"%(name,user.k(),-amount,reason),amount=-amount,reason=reason),async=True)
|
||||
if amount>0: add_event(result,"bill",["cashflow"],self=self,info=cGG(message="%s [%s] spent %s shells for: %s"%(name,user.k(),amount,reason),amount=amount,reason=reason),_async=True)
|
||||
else: add_event(result,"ishells",["cashflow"],self=self,info=cGG(message="%s [%s] received %s shells from: %s"%(name,user.k(),-amount,reason),amount=-amount,reason=reason),_async=True)
|
||||
try: deferred.defer(update_characters,result)
|
||||
except: log_trace()
|
||||
else:
|
||||
@@ -870,8 +870,8 @@ def bill_user_api(**args):
|
||||
if result:
|
||||
logging.info(result)
|
||||
jhtml(self,{"done":1,"cash":result.cash})
|
||||
if amount>0: add_event(result,"bill",["cashflow"],self=self,info=cGG(message="%s [%s] spent %s shells for: %s"%(name,user.k(),amount,reason),amount=amount,reason=reason),async=True)
|
||||
else: add_event(result,"ishells",["cashflow"],self=self,info=cGG(message="%s [%s] received %s shells from: %s"%(name,user.k(),-amount,reason),amount=-amount,reason=reason),async=True)
|
||||
if amount>0: add_event(result,"bill",["cashflow"],self=self,info=cGG(message="%s [%s] spent %s shells for: %s"%(name,user.k(),amount,reason),amount=amount,reason=reason),_async=True)
|
||||
else: add_event(result,"ishells",["cashflow"],self=self,info=cGG(message="%s [%s] received %s shells from: %s"%(name,user.k(),-amount,reason),amount=-amount,reason=reason),_async=True)
|
||||
try: deferred.defer(update_characters,result)
|
||||
except: log_trace()
|
||||
else:
|
||||
@@ -1021,7 +1021,7 @@ def send_mail_api(**args):
|
||||
if fro and not frop or not top: return jhtml(self,{"failed":1,"reason":"nocharacter","return":True})
|
||||
if fro: user1=get_by_iid_async("user|%s"%frop.owner);
|
||||
user2=get_by_iid("user|%s"%top.owner)
|
||||
ud2=get_user_data(user2,async=True); c2=Mail.query(Mail.owner==user2.k(),Mail.read==False).fetch_async(98,keys_only=True)
|
||||
ud2=get_user_data(user2,_async=True); c2=Mail.query(Mail.owner==user2.k(),Mail.read==False).fetch_async(98,keys_only=True)
|
||||
if fro: user1=user1.get_result()
|
||||
if not server: return jhtml(self,{"failed":1,"reason":"noserver"})
|
||||
if fro and not user1 or not user2: return jhtml(self,{"failed":1,"reason":"nouser","return":True})
|
||||
@@ -1183,7 +1183,7 @@ def stripe_payment_api(**args): #TODO: Patch for .server checks [10/07/18]
|
||||
currency="usd",
|
||||
description="%s SHELLS for %s USD"%(shells,usd),
|
||||
source=token)
|
||||
add_event(user,"stripe",["payments","cashflow"],self=self,info=cGG(message="STRIPE! %s spent %s USD!"%(user.name,usd),usd=usd,token=token,response=response),async=True)
|
||||
add_event(user,"stripe",["payments","cashflow"],self=self,info=cGG(message="STRIPE! %s spent %s USD!"%(user.name,usd),usd=usd,token=token,response=response),_async=True)
|
||||
def stripe_transaction():
|
||||
element=get_by_iid(user.k('i'))
|
||||
element.cash+=int(shells)
|
||||
@@ -1191,7 +1191,7 @@ def stripe_payment_api(**args): #TODO: Patch for .server checks [10/07/18]
|
||||
return element
|
||||
result=ndb.transaction(stripe_transaction,xg=True,retries=120)
|
||||
if result:
|
||||
add_event(result,"shells",["cashflow"],self=self,info=cGG(message="STRIPE! %s received %s SHELLS!"%(user.name,shells),usd=usd,token=token),async=True)
|
||||
add_event(result,"shells",["cashflow"],self=self,info=cGG(message="STRIPE! %s received %s SHELLS!"%(user.name,shells),usd=usd,token=token),_async=True)
|
||||
jfunc(self,"stripe_result",["success",result.cash])
|
||||
jhtmls(self,"You received %s SHELLS!"%shells)
|
||||
try: deferred.defer(add_cash,result.k(),int(shells),referrer=True,only_referrer=True)
|
||||
@@ -1304,7 +1304,7 @@ def start_character_api(**args):
|
||||
return jhtml(self,data)
|
||||
if is_in_game(character): jhtml(self,{"failed":1,"reason":"ingame"}); return
|
||||
if not is_sdk and ssince(gf(character,"last_start",really_old))<40: jhtml(self,{"failed":1,"reason":"wait_%d_seconds"%(40-ssince(gf(character,"last_start",really_old)))}); return
|
||||
add_event(character,"start",["activity"],self=self,info=cGG(message="%s [LV.%s] logged into %s %s"%(character.info.name,character.level,server.region,server.name),server=server.k('i')),async=True)
|
||||
add_event(character,"start",["activity"],self=self,info=cGG(message="%s [LV.%s] logged into %s %s"%(character.info.name,character.level,server.region,server.name),server=server.k('i')),_async=True)
|
||||
if user.guild: guild=get_by_iid_async("guild|%s"%user.guild)
|
||||
def start_character_transaction():
|
||||
element=get_by_iid(character.k('i'))
|
||||
@@ -1380,7 +1380,7 @@ def stop_character_api(**args):
|
||||
if result:
|
||||
character=result
|
||||
jhtml(self,{"done":1,"name":character.info.name})
|
||||
add_event(character,"stop",["activity"],self=self,info=cGG(message="%s [LV.%s] logged out of %s %s"%(character.info.name,character.level,server.region,server.name),server=server.k('i')),async=True)
|
||||
add_event(character,"stop",["activity"],self=self,info=cGG(message="%s [LV.%s] logged out of %s %s"%(character.info.name,character.level,server.region,server.name),server=server.k('i')),_async=True)
|
||||
else:
|
||||
jhtml(self,{"failed":1,"reason":"unknown"})
|
||||
|
||||
@@ -1490,10 +1490,10 @@ def reload_server_api(**args):
|
||||
def create_server_api(**args):
|
||||
self,domain,keyword,port,region,pvp,gameplay,sname=gdmuld(args,"self","domain","keyword","port","region","pvp","gameplay","name")
|
||||
if keyword!=secrets.SERVER_MASTER: jhtml(self,{"failed":1}); return
|
||||
actual_ip=ip=self.request.remote_addr; server_name="XX"
|
||||
actual_ip=ip=request.remote_addr; server_name="XX"
|
||||
if is_sdk: actual_ip=ip=domain.server_ip
|
||||
if domain.https_mode: ip="%s.%s"%(ip_to_subdomain.get(ip,ip),live_domain)
|
||||
lat,lon=(self.request.headers.get("X-Appengine-Citylatlong")or"0,0").split(",")
|
||||
lat,lon=(request.headers.get("X-Appengine-Citylatlong")or"0,0").split(",")
|
||||
try: lat,lon=float(lat),float(lon)
|
||||
except: lat,lon=0,0
|
||||
|
||||
@@ -1685,7 +1685,6 @@ def delete_map_api(**args):
|
||||
jhtml(self,[{"type":"success","message":"Done!"},selection_info(self,user,domain)])
|
||||
|
||||
def test_api(**args):
|
||||
asdfdfsa=dsfafsd
|
||||
self,user,server,domain=gdmuld(args,"self","user","server","domain")
|
||||
logging.info("test")
|
||||
jfunc(self,"alert",["lol"])
|
||||
@@ -1705,34 +1704,34 @@ def simplify_args_for_logging(args):
|
||||
except:
|
||||
return args
|
||||
|
||||
class APICall(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def post(self):
|
||||
domain=gdi(self)
|
||||
server=get_server(self,domain)
|
||||
args,method=gdmul(self,"arguments","method")
|
||||
if security_threat(self,domain): return
|
||||
user=get_user(self,domain,api_override=(server and method and method!="start_character")) # only "start_character" has an auth check, the rest doesn't re-check user auths #IMPORTANT! [09/08/20]
|
||||
method="%s_api"%method
|
||||
if args: args=json.loads(args)
|
||||
if not args: args={}
|
||||
logging.info("\n\nAPI Method Called: %s Arguments: %s\n"%(method,simplify_args_for_logging(args)))
|
||||
#logging.info(self.request.cookies.get("auth"))
|
||||
if not user and method not in ["log_error_api","signup_or_login_api","load_article_api","get_server_api","test_api","create_server_api","stop_server_api","update_server_api","reload_server_api","set_friends_api","not_friends_api","password_reminder_api","server_event_api","reset_password_api","ban_user_api","send_mail_api","log_chat_api","take_item_from_mail_api","broadcast_api"]:
|
||||
if self.request.get("server_auth"): jhtml(self,{"failed":1,"reason":"nouser"}); return
|
||||
jhtml(self,[{"type":"func","func":"add_log","args":["Not logged in."]}]); return
|
||||
function=globals().get(method)
|
||||
args["domain"]=domain
|
||||
args["user"]=user
|
||||
args["server"]=server
|
||||
args["self"]=self
|
||||
if user and not server and gf(user,"blocked_until",really_old)>datetime.now() and method not in ["logout_api_X"]: return jhtml(self,[{"type":"func","func":"add_log","args":["Blocked"]}])
|
||||
if function: function(**args)
|
||||
else:
|
||||
if args.get("dataType")=="json": jhtml(self,[{"type":"ui_log","message":"Invalid method"}])
|
||||
else: logging.error("no function")
|
||||
safe_commit(user); safe_commit(server); domain_routine(domain)
|
||||
@app.route('/api', methods=['POST'])
|
||||
@app.route('/api/<name>', methods=['POST'])
|
||||
@app.route('/api/<name>/<extra>', methods=['POST'])
|
||||
@ndb.toplevel
|
||||
def server_api(name="",extra=""):
|
||||
self=request # [26/01/24] easier for now
|
||||
domain=gdi(self)
|
||||
server=get_server(self,domain)
|
||||
args,method=gdmul(self,"arguments","method")
|
||||
if security_threat(self,domain): return "security_threat"
|
||||
user=get_user(self,domain,api_override=(server and method and method!="start_character")) # only "start_character" has an auth check, the rest doesn't re-check user auths #IMPORTANT! [09/08/20]
|
||||
method="%s_api"%method
|
||||
if args: args=json.loads(args)
|
||||
if not args: args={}
|
||||
logging.info("\n\nAPI Method Called: %s Arguments: %s\n"%(method,simplify_args_for_logging(args)))
|
||||
if not user and method not in ["log_error_api","signup_or_login_api","load_article_api","get_server_api","test_api","create_server_api","stop_server_api","update_server_api","reload_server_api","set_friends_api","not_friends_api","password_reminder_api","server_event_api","reset_password_api","ban_user_api","send_mail_api","log_chat_api","take_item_from_mail_api","broadcast_api"]:
|
||||
if self.values.get("server_auth"): jhtml(self,{"failed":1,"reason":"nouser"}); return "nouser"
|
||||
jhtml(self,[{"type":"func","func":"add_log","args":["Not logged in."]}]); return "notloggedin"
|
||||
function=globals().get(method)
|
||||
args["domain"]=domain
|
||||
args["user"]=user
|
||||
args["server"]=server
|
||||
args["self"]=self
|
||||
if user and not server and gf(user,"blocked_until",really_old)>datetime.now() and method not in ["logout_api_X"]: return jhtml(self,[{"type":"func","func":"add_log","args":["Blocked"]}])
|
||||
if function: function(**args)
|
||||
else:
|
||||
if args.get("dataType")=="json": jhtml(self,[{"type":"ui_log","message":"Invalid method"}])
|
||||
else: logging.error("no function")
|
||||
safe_commit(user); safe_commit(server); domain_routine(domain)
|
||||
return request.response
|
||||
|
||||
application = webapp.WSGIApplication([
|
||||
('/api.*',APICall),
|
||||
],debug=is_sdk)
|
||||
|
||||
@@ -36,20 +36,20 @@ handlers:
|
||||
static_dir: sounds
|
||||
- url: /js
|
||||
static_dir: js
|
||||
- url: /api.*
|
||||
script: api.application
|
||||
- url: /admin.*
|
||||
script: admin.application
|
||||
login: admin
|
||||
- url: /cr/.*
|
||||
script: crons.application
|
||||
login: admin
|
||||
- url: /tasks.*
|
||||
script: tasks.application
|
||||
- url: /test.*
|
||||
script: tests.application
|
||||
- url: .*
|
||||
script: main.application
|
||||
script: main.app
|
||||
- url: /admin/upload.*
|
||||
script: uploaders.application
|
||||
- url: /upload.*
|
||||
script: uploaders.application
|
||||
- url: /tileset/.*
|
||||
script: uploaders.application
|
||||
|
||||
# skip_files:
|
||||
# - ^lib(/.*)?
|
||||
# - .*lib.*
|
||||
# - ^electron(/.*)?
|
||||
# - .*electron.*
|
||||
|
||||
libraries:
|
||||
- name: jinja2
|
||||
|
||||
@@ -3,26 +3,50 @@ from __future__ import with_statement
|
||||
# Python3 compatibility [06/01/24]
|
||||
from __future__ import print_function
|
||||
import os,logging,cgi
|
||||
if os.environ.get('SERVER_SOFTWARE', '').startswith('Dev'):
|
||||
if os.environ.get('SERVER_SOFTWARE', '').startswith('Dev') or not os.getenv('GAE_ENV', '').startswith('standard'):
|
||||
try:
|
||||
from google.appengine.tools.dev_appserver import HardenedModulesHook
|
||||
HardenedModulesHook._WHITE_LIST_C_MODULES += ['_ctypes', 'gestalt']
|
||||
except: pass
|
||||
import sys,json,random,time,re,math,copy,base64,cPickle,jinja2,types,urllib,operator,pickle,unicodedata
|
||||
import sys,json,random,time,re,math,copy,base64,jinja2,types,urllib,operator,pickle,unicodedata
|
||||
import gc as gbc
|
||||
from lxml import etree as lxmletree
|
||||
import datetime as rdatetime
|
||||
import time as rtime
|
||||
from datetime import datetime,timedelta,date
|
||||
from urlparse import urlparse
|
||||
from google.appengine.api.users import is_current_user_admin
|
||||
from google.appengine.ext.webapp import blobstore_handlers # template,util,
|
||||
from google.appengine.api import memcache,urlfetch,urlfetch_errors,mail,taskqueue,images,files,namespace_manager,search,modules,logservice
|
||||
from google.appengine.ext import webapp,ndb,blobstore,deferred
|
||||
if 1/2 == 0: #python2
|
||||
from urlparse import urlparse
|
||||
urlencode=urllib.urlencode
|
||||
# webapp/blobstore_handlers is for photo upload and resort tileset upload - so that the python2 sdk still retains upload capabilities [27/01/24]
|
||||
from google.appengine.ext import webapp,vendor
|
||||
from google.appengine.ext.webapp import blobstore_handlers
|
||||
from google.appengine.api import files,logservice # I don't think these were originally used
|
||||
vendor.add('lib')
|
||||
from libraries import stripe
|
||||
from libraries import amazon_ses
|
||||
import cPickle
|
||||
else: #python3
|
||||
basestring=str
|
||||
xrange=range
|
||||
from urllib.parse import urlparse
|
||||
urlencode= urllib.parse.urlencode
|
||||
from google.appengine.api import wrap_wsgi_app
|
||||
from libraries import stripe3 as stripe
|
||||
from libraries import amazon_ses3 as amazon_ses
|
||||
import _pickle as cPickle
|
||||
from google.appengine.api import memcache,urlfetch,urlfetch_errors,mail,taskqueue,images,namespace_manager,search,modules
|
||||
from google.appengine.ext import ndb,blobstore,deferred
|
||||
from google.appengine.runtime import DeadlineExceededError
|
||||
from google.appengine.runtime.apiproxy_errors import DeadlineExceededError as DeadlineExceededError2
|
||||
from google.appengine.datastore.datastore_query import Cursor
|
||||
|
||||
from flask import Flask, render_template, request, make_response
|
||||
|
||||
app = Flask(__name__)
|
||||
if 1/2 != 0:
|
||||
app.wsgi_app = wrap_wsgi_app(app.wsgi_app, use_deferred=True)
|
||||
|
||||
class mj2u(jinja2.Undefined):
|
||||
def __str__(self): 0 and logging.info("Non existing variable"); return ""
|
||||
def __call__(self,*a,**d): 0 and logging.info("Non existing variables non existing call with a %s d %s"%(a,d)); return "";mj2u()
|
||||
@@ -34,11 +58,9 @@ class GG(): pass
|
||||
import secrets
|
||||
|
||||
from libraries.country_to_latlon import c_to_ll
|
||||
from libraries import stripe
|
||||
from libraries import amazon_ses
|
||||
#from libraries import get_image_size
|
||||
|
||||
if os.environ.get('SERVER_SOFTWARE', '').startswith('Dev'):
|
||||
if os.environ.get('SERVER_SOFTWARE', '').startswith('Dev') or not os.getenv('GAE_ENV', '').startswith('standard'):
|
||||
is_sdk=True; is_production=is_appengine=False
|
||||
stripe.verify_ssl_certs = False
|
||||
stripe.api_key=secrets.stripe_test_api_key
|
||||
@@ -82,12 +104,12 @@ if is_production:
|
||||
#maps["desertland"]["key"]="jayson_desertland_copy"
|
||||
pass
|
||||
|
||||
game_version=785
|
||||
game_version=786
|
||||
SALES=4+5+388+5101+125/20 #donation+manual+macos+steam+sales
|
||||
update_notes=[
|
||||
"Lunar New Year Event",
|
||||
"Last Update [19th of January]",
|
||||
"Adding Python3 compatibility",
|
||||
"Switched to Python3",
|
||||
]
|
||||
ip_to_subdomain={ #IMPORTANT: SPECIAL PAGE RULES ARE NEEDED: https://dash.cloudflare.com/b6f5a13bded5fdd273e4a1cd3777162d/adventure.land/page-rules - uss1 / eus1 was best
|
||||
"35.187.255.184":"asia1",
|
||||
@@ -110,11 +132,18 @@ live_domain='adventure.land'
|
||||
sdk_domain='thegame.com'
|
||||
SDK_UPLOAD_PASSWORD=ELEMENT_PASSWORD=secrets.sdk_password
|
||||
|
||||
def gdi(self=None):
|
||||
def init_request(request):
|
||||
if request and not getattr(request,"response",None):
|
||||
request.response=make_response("")
|
||||
# this way cookies etc. can be set from the request object ahead of time
|
||||
# otherwise the Flask flow is limiting as it doesn't let you do these things from function calls ahead of response creation [25/01/24]
|
||||
|
||||
def gdi(request=None):
|
||||
init_request(request)
|
||||
domain=GG()
|
||||
if is_sdk:
|
||||
if self:
|
||||
url=urlparse(self.request.url)
|
||||
if request:
|
||||
url=urlparse(request.url)
|
||||
protocol=url.scheme
|
||||
hostname=url.hostname
|
||||
else:
|
||||
@@ -130,7 +159,7 @@ def gdi(self=None):
|
||||
domain.domain=hostname
|
||||
else:
|
||||
protocol="http"
|
||||
if self and "https" in (self.request.headers.get("Cf-Visitor") or ""): protocol="https"
|
||||
if request and "https" in (request.headers.get("Cf-Visitor") or ""): protocol="https"
|
||||
domain.base_url=protocol + "://" + live_domain
|
||||
domain.pref_url=domain.base_url
|
||||
domain.stripe_pkey=stripe_pkey
|
||||
@@ -186,56 +215,56 @@ def gdi(self=None):
|
||||
domain.access_master=secrets.ACCESS_MASTER
|
||||
domain.servers=[]
|
||||
domain.characters=[]
|
||||
try: domain.scale=int(float(self and self.request.get("scale") or 2))
|
||||
try: domain.scale=int(float(request and request.values.get("scale") or 2))
|
||||
except: domain.scale=2
|
||||
try: domain.times=int(self and self.request.get("times") or 0)
|
||||
try: domain.times=int(request and request.values.get("times") or 0)
|
||||
except: domain.times=0
|
||||
domain.load_character=self and self.request.get("load") or ""
|
||||
domain.load_character=request and request.values.get("load") or ""
|
||||
domain.electron=False
|
||||
domain.platform="web"
|
||||
domain.update_notes=update_notes
|
||||
if self:
|
||||
if "Electron" in self.request.headers.get("User-Agent",""):
|
||||
if request:
|
||||
if "Electron" in request.headers.get("User-Agent",""):
|
||||
domain.electron=True
|
||||
if self.request.get("buildid") and "win32" in self.request.get("buildid"): domain.platform="steam"
|
||||
if self.request.get("buildid") and "darwin" in self.request.get("buildid"): domain.platform="mac"
|
||||
if self.request.cookies.get("music")!="off": domain.music_on=True
|
||||
if self.request.cookies.get("sfx")!="off": domain.sfx_on=True
|
||||
domain.url=self.request.url
|
||||
domain.section=self.request.get("section")
|
||||
if self.request.get("test_clicks"): domain.test_clicks=True; domain.pixi_version="4.0.2"
|
||||
if self.request.get("no_cache"): domain.v=100000+random.randrange(0,100000000)
|
||||
if self.request.get("no_html"): domain.no_html=True
|
||||
if self.request.get("no_html")=="bot": domain.no_html="bot"
|
||||
if self.request.get("is_bot"): domain.is_bot=True
|
||||
if self.request.get("is_cli"): domain.is_cli=True
|
||||
if self.request.get("recording_mode"): domain.recording_mode=True; domain.boost=20; domain.sfx_on=False; domain.music_on=False
|
||||
if self.request.get("no_graphics") or domain.no_html:
|
||||
if request.values.get("buildid") and "win32" in request.values.get("buildid"): domain.platform="steam"
|
||||
if request.values.get("buildid") and "darwin" in request.values.get("buildid"): domain.platform="mac"
|
||||
if request.cookies.get("music")!="off": domain.music_on=True
|
||||
if request.cookies.get("sfx")!="off": domain.sfx_on=True
|
||||
domain.url=request.url
|
||||
domain.section=request.values.get("section")
|
||||
if request.values.get("test_clicks"): domain.test_clicks=True; domain.pixi_version="4.0.2"
|
||||
if request.values.get("no_cache"): domain.v=100000+random.randrange(0,100000000)
|
||||
if request.values.get("no_html"): domain.no_html=True
|
||||
if request.values.get("no_html")=="bot": domain.no_html="bot"
|
||||
if request.values.get("is_bot"): domain.is_bot=True
|
||||
if request.values.get("is_cli"): domain.is_cli=True
|
||||
if request.values.get("recording_mode"): domain.recording_mode=True; domain.boost=20; domain.sfx_on=False; domain.music_on=False
|
||||
if request.values.get("no_graphics") or domain.no_html:
|
||||
domain.no_graphics=True;
|
||||
domain.pixi_version="fake" #NOGTODO is the hashtag
|
||||
domain.pixi_fversion="?v=%s"%game_version
|
||||
if self.request.get("borders") or self.request.get("border_mode"): domain.border_mode=True
|
||||
if self.request.cookies.get("perfect_pixels_off") and not SCREENSHOT_MODE:
|
||||
if request.values.get("borders") or request.values.get("border_mode"): domain.border_mode=True
|
||||
if request.cookies.get("perfect_pixels_off") and not SCREENSHOT_MODE:
|
||||
domain.perfect_pixels=False
|
||||
if self.request.cookies.get("d_lines_off"):
|
||||
if request.cookies.get("d_lines_off"):
|
||||
domain.d_lines=False
|
||||
if self.request.cookies.get("no_tutorial"):
|
||||
if request.cookies.get("no_tutorial"):
|
||||
domain.tutorial=False
|
||||
if self.request.cookies.get("no_fast_mode"):
|
||||
if request.cookies.get("no_fast_mode"):
|
||||
domain.fast_mode=False
|
||||
if self.request.get("engine") or self.request.cookies.get("engine_mode"):
|
||||
domain.engine_mode=self.request.get("engine") or self.request.cookies.get("engine_mode")
|
||||
if self.request.cookies.get("sd_lines_off"):
|
||||
if request.values.get("engine") or request.cookies.get("engine_mode"):
|
||||
domain.engine_mode=request.values.get("engine") or request.cookies.get("engine_mode")
|
||||
if request.cookies.get("sd_lines_off"):
|
||||
domain.sd_lines=False
|
||||
if self.request.cookies.get("pro_mode"):
|
||||
if request.cookies.get("pro_mode"):
|
||||
domain.newcomer_ui=False
|
||||
if self.request.cookies.get("no_weapons"):
|
||||
if request.cookies.get("no_weapons"):
|
||||
domain.new_attacks=False
|
||||
if self.request.cookies.get("manual_reload"):
|
||||
if request.cookies.get("manual_reload"):
|
||||
domain.auto_reload="off"
|
||||
else:
|
||||
domain.auto_reload="auto"
|
||||
if self.request.scheme=="https" or self.request.headers.get("Cf-Visitor") and self.request.headers.get("Cf-Visitor").find("https")!=-1:
|
||||
if request.scheme=="https" or request.headers.get("Cf-Visitor") and request.headers.get("Cf-Visitor").find("https")!=-1:
|
||||
domain.https=True
|
||||
return domain
|
||||
secure_cookies=False #not is_sdk
|
||||
|
||||
@@ -164,6 +164,10 @@ def all_user_cron(num): #<<NEW
|
||||
user.banned=True
|
||||
user.put()
|
||||
|
||||
def all_user_cron(num): #<<NEW
|
||||
for user in User.query(User.random_number==num):
|
||||
logging.info(user.info.email)
|
||||
|
||||
def all_character_cron(num):
|
||||
for character in Character.query(Character.random_number==num):
|
||||
if gf(character,"map") in ["main","batcave"]:
|
||||
@@ -214,7 +218,7 @@ def all_cbackup_cron(num):
|
||||
element=get_by_iid(character.k('i'))
|
||||
element.to_backup=False
|
||||
element.put()
|
||||
rpcs.append(backup_item(character,async=True))
|
||||
rpcs.append(backup_item(character,_async=True))
|
||||
rpcs.append(ndb.transaction_async(backup_transaction,retries=0))
|
||||
for rpc in rpcs: rpc.wait()
|
||||
|
||||
@@ -225,7 +229,7 @@ def all_process_cron(num):
|
||||
element=get_by_iid(character.k('i'))
|
||||
element.to_backup=False
|
||||
element.put()
|
||||
rpcs.append(backup_item(character,async=True))
|
||||
rpcs.append(backup_item(character,_async=True))
|
||||
rpcs.append(ndb.transaction_async(backup_transaction,retries=0))
|
||||
for rpc in rpcs: rpc.wait()
|
||||
|
||||
@@ -236,79 +240,80 @@ def all_ubackup_cron(num):
|
||||
element=get_by_iid(user.k('i'))
|
||||
element.to_backup=False
|
||||
element.put()
|
||||
rpcs.append(backup_item(user,async=True))
|
||||
rpcs.append(backup_item(user,_async=True))
|
||||
rpcs.append(ndb.transaction_async(backup_transaction,retries=0))
|
||||
for rpc in rpcs: rpc.wait()
|
||||
|
||||
class AllCron(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,mname):
|
||||
if mname=="user":
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_user_cron,n,_queue="important")
|
||||
if mname=="mail":
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_mail_cron,n,_queue="important")
|
||||
if mname=="character":
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_character_cron,n,_queue="important")
|
||||
if mname=="backups":
|
||||
#originally, backups were on-access, but they need to be all at the same time, so a reversal restores the ~whole state of the game [19/11/18]
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_ubackup_cron,n,_queue="important")
|
||||
deferred.defer(all_cbackup_cron,n,_queue="important")
|
||||
if mname=="process_backups":
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_process_cron,n,_queue="important")
|
||||
def post(self,mname): self.get(mname)
|
||||
@app.route('/cr/all/<mname>',methods=['GET','POST'])
|
||||
@ndb.toplevel
|
||||
def serve_all_cron(mname=""):
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not (user and getattr(user,"admin",False) or request.headers.get('X-AppEngine-Cron')): return "no permission"
|
||||
if mname=="user":
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_user_cron,n,_queue="important")
|
||||
if mname=="mail":
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_mail_cron,n,_queue="important")
|
||||
if mname=="character":
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_character_cron,n,_queue="important")
|
||||
if mname=="backups":
|
||||
#originally, backups were on-access, but they need to be all at the same time, so a reversal restores the ~whole state of the game [19/11/18]
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_ubackup_cron,n,_queue="important")
|
||||
deferred.defer(all_cbackup_cron,n,_queue="important")
|
||||
if mname=="process_backups":
|
||||
for n in range(1,101):
|
||||
deferred.defer(all_process_cron,n,_queue="important")
|
||||
return ""
|
||||
|
||||
class CheckServers(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self): check_servers()
|
||||
def post(self): self.get()
|
||||
@app.route('/cr/check_servers',methods=['GET','POST'])
|
||||
@ndb.toplevel
|
||||
def serve_server_checker():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not (user and getattr(user,"admin",False) or request.headers.get('X-AppEngine-Cron')): return "no permission"
|
||||
check_servers()
|
||||
return ""
|
||||
|
||||
class UnstuckPlayers(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
servers=get_servers()
|
||||
for server in servers:
|
||||
if msince(server.created)>10: #no widespread network issue
|
||||
characters=Character.query(Character.online==True, Character.server == server.k(), Character.last_sync < datetime.now()-timedelta(minutes=30)).fetch()
|
||||
for character in characters:
|
||||
m=msince(character.last_sync)
|
||||
character.online=False
|
||||
character.server=""
|
||||
character.put()
|
||||
send_email(gdi(),"kaansoral@gmail.com",html="Stuck for %s minutes"%m,title="UNSTUCK %s from %s"%(character.name,server.k()))
|
||||
@app.route('/cr/unstuck',methods=['GET','POST'])
|
||||
@ndb.toplevel
|
||||
def serve_unstuck():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not (user and getattr(user,"admin",False) or request.headers.get('X-AppEngine-Cron')): return "no permission"
|
||||
servers=get_servers()
|
||||
for server in servers:
|
||||
if msince(server.created)>10: #no widespread network issue
|
||||
characters=Character.query(Character.online==True, Character.server == server.k(), Character.last_sync < datetime.now()-timedelta(minutes=30)).fetch()
|
||||
for character in characters:
|
||||
m=msince(character.last_sync)
|
||||
character.online=False
|
||||
character.server=""
|
||||
character.put()
|
||||
send_email(gdi(),"kaansoral@gmail.com",html="Stuck for %s minutes"%m,title="UNSTUCK %s from %s"%(character.name,server.k()))
|
||||
return ""
|
||||
|
||||
def post(self): self.get()
|
||||
|
||||
class Hourly(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
deferred.defer(verify_steam_installs)
|
||||
return
|
||||
@app.route('/cr/hourly',methods=['GET','POST'])
|
||||
@ndb.toplevel
|
||||
def serve_hourly():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not (user and getattr(user,"admin",False) or request.headers.get('X-AppEngine-Cron')): return "no permission"
|
||||
deferred.defer(verify_steam_installs)
|
||||
return ""
|
||||
if random.randrange(0,20)==2:
|
||||
user=get_by_iid("user|%s"%get_character("Wizard").owner)
|
||||
if random.randrange(0,20)==2:
|
||||
user=get_by_iid("user|%s"%get_character("Wizard").owner)
|
||||
if random.randrange(0,20)==2:
|
||||
add_cash(user,100*random.randrange(1,50))
|
||||
else:
|
||||
add_cash(user,200)
|
||||
add_cash(user,100*random.randrange(1,50))
|
||||
else:
|
||||
add_cash(user,200)
|
||||
if random.randrange(0,20)==2:
|
||||
user=get_by_iid("user|%s"%get_character("Oragon").owner)
|
||||
if random.randrange(0,20)==2:
|
||||
user=get_by_iid("user|%s"%get_character("Oragon").owner)
|
||||
if random.randrange(0,20)==2:
|
||||
add_cash(user,100*random.randrange(1,50))
|
||||
else:
|
||||
add_cash(user,200)
|
||||
#user=get_by_iid("user|%s"%get_character("Trexnamedtod").owner)
|
||||
#add_cash(user,25)
|
||||
#user=get_by_iid("user|%s"%get_character("Emerald").owner)
|
||||
#add_cash(user,5)
|
||||
def post(self): self.get()
|
||||
|
||||
application = webapp.WSGIApplication([
|
||||
('/cr/check_servers', CheckServers),
|
||||
('/cr/hourly', Hourly),
|
||||
('/cr/unstuck', UnstuckPlayers),
|
||||
('/cr/all/([^/]*)/?', AllCron),
|
||||
],debug=is_sdk)
|
||||
add_cash(user,100*random.randrange(1,50))
|
||||
else:
|
||||
add_cash(user,200)
|
||||
#user=get_by_iid("user|%s"%get_character("Trexnamedtod").owner)
|
||||
#add_cash(user,25)
|
||||
#user=get_by_iid("user|%s"%get_character("Emerald").owner)
|
||||
#add_cash(user,5)
|
||||
return ""
|
||||
|
||||
@@ -538,7 +538,10 @@ animations={
|
||||
},
|
||||
}
|
||||
|
||||
from projectiles import projectiles
|
||||
try:
|
||||
from projectiles import projectiles
|
||||
except:
|
||||
from design.projectiles import projectiles
|
||||
for id in projectiles:
|
||||
if projectiles[id].has_key("animation") and animations[projectiles[id]["animation"]].has_key("speed"):
|
||||
if "animation" in projectiles[id] and "speed" in animations[projectiles[id]["animation"]]:
|
||||
animations[projectiles[id]["animation"]]["speed"]=projectiles[id]["speed"]
|
||||
+7
-4
@@ -1,5 +1,8 @@
|
||||
import copy
|
||||
from items import items
|
||||
try:
|
||||
from items import items
|
||||
except:
|
||||
from design.items import items
|
||||
|
||||
drops={
|
||||
"gold":{
|
||||
@@ -1222,7 +1225,7 @@ drops={
|
||||
}
|
||||
|
||||
for n,nm in [[1,25],[2,25],[3,25],[4,25],[5,22]]:
|
||||
for num in xrange(nm):
|
||||
for num in range(nm):
|
||||
if "%s%.2d"%(n,num) in ["122","203","404"]: continue
|
||||
drops["cosmo2"].append([1,"cx","hairdo%s%.2d"%(n,num)])
|
||||
|
||||
@@ -1231,7 +1234,7 @@ drops["cosmo2"].append([1.0/3,"cx","hairdo404"])
|
||||
drops["cosmo2"].append([1.0/10,"cx","hairdo203"])
|
||||
|
||||
for n,nm in [[1,16],[2,25],[3,24],[4,8]]:
|
||||
for num in xrange(nm):
|
||||
for num in range(nm):
|
||||
if "%s%.2d"%(n,num) in ["100","114","115","102","106","113","310","309","318","400","405"]: continue
|
||||
drops["cosmo3"].append([1,"cx","hat%s%.2d"%(n,num)])
|
||||
|
||||
@@ -1264,7 +1267,7 @@ for name in items:
|
||||
drops["glitch"].append([1,name])
|
||||
|
||||
for name in items:
|
||||
if not items[name].has_key("g"):
|
||||
if "g" not in items[name]:
|
||||
import logging
|
||||
logging.error(name)
|
||||
if not items[name].get("ignore") and not items[name].get("exclusive"):
|
||||
|
||||
+8
-8
@@ -1739,11 +1739,11 @@ for name in armor.keys():
|
||||
res_gains=[0,0.5,2.5,5.5,7.5]
|
||||
xtier=([0.5,0.5,2,3.4,4.5,6][ftier]+[0.5,0.5,2,4,5,6][ctier]+tier)/3.0
|
||||
#if not current.has_key("edge") and tier>1: current["edge"]=(tier-1)*2
|
||||
if tier<=1.25 and not current.has_key("grades"): current["grades"]=[7,9]
|
||||
elif tier<=1.5 and not current.has_key("grades"): current["grades"]=[4,8]
|
||||
elif tier<=2.4 and not current.has_key("grades"): current["grades"]=[0,7]
|
||||
elif tier<=2.75 and not current.has_key("grades"): current["grades"]=[0,5]
|
||||
elif not current.has_key("grades"): current["grades"]=[0,0]
|
||||
if tier<=1.25 and "grades" not in current: current["grades"]=[7,9]
|
||||
elif tier<=1.5 and "grades" not in current: current["grades"]=[4,8]
|
||||
elif tier<=2.4 and "grades" not in current: current["grades"]=[0,7]
|
||||
elif tier<=2.75 and "grades" not in current: current["grades"]=[0,5]
|
||||
elif "grades" not in current: current["grades"]=[0,0]
|
||||
if len(current["grades"])==2:
|
||||
current["grades"].append(10); current["grades"].append(12)
|
||||
if tier>=4:
|
||||
@@ -2583,7 +2583,7 @@ accessories={
|
||||
|
||||
for name in accessories.keys():
|
||||
current=accessories[name]
|
||||
if not current.has_key("grades"): current["grades"]=[3,5]
|
||||
if "grades" not in current: current["grades"]=[3,5]
|
||||
|
||||
#Ring of Mage PVP: 30 Armor, 10 Res. Piercing, 120HP
|
||||
#Ring of Warrior PVP: 20 Res, 10 Armor, 10 Armor. Piercing
|
||||
@@ -3839,8 +3839,8 @@ weapons={
|
||||
|
||||
for name in weapons.keys():
|
||||
current=weapons[name]; tier=current.get("tier",1)
|
||||
if not current.has_key("upgrade"): continue
|
||||
if not current.has_key("grades"):
|
||||
if "upgrade" not in current: continue
|
||||
if "grades" not in current:
|
||||
if tier<1: current["grades"]=[8,9]
|
||||
elif tier<=1: current["grades"]=[7,9]
|
||||
elif tier<=1.5: current["grades"]=[5,8]
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
# if 1:
|
||||
# if 1:
|
||||
# if 1:
|
||||
# for i in xrange(200):
|
||||
# for i in range(200):
|
||||
# new_xp=xp
|
||||
# while new_xp>=100: new_xp/=10
|
||||
# new_xp=int(new_xp)
|
||||
@@ -25,7 +25,7 @@
|
||||
# if 1:
|
||||
# if 1:
|
||||
# if 1:
|
||||
# for i in xrange(200):
|
||||
# for i in range(200):
|
||||
# new_xp=xp
|
||||
# while new_xp>=100: new_xp/=10
|
||||
# new_xp=int(new_xp)
|
||||
@@ -46,7 +46,7 @@
|
||||
# if 1:
|
||||
# if 1:
|
||||
# if 1:
|
||||
# for i in xrange(200):
|
||||
# for i in range(200):
|
||||
# new_xp=xp
|
||||
# while new_xp>=100: new_xp/=10
|
||||
# new_xp=int(new_xp)
|
||||
|
||||
+1
-1
@@ -1169,7 +1169,7 @@ skills={
|
||||
}
|
||||
}
|
||||
for name in skills:
|
||||
if skills[name].has_key("condition") and not skills[name].has_key("duration") and conditions.has_key(skills[name]["condition"]) and conditions[skills[name]["condition"]]:
|
||||
if "condition" in skills[name] and "duration" not in skills[name] and skills[name]["condition"] in conditions and conditions[skills[name]["condition"]]:
|
||||
try:
|
||||
skills[name]["duration"]=conditions[skills[name]["condition"]]["duration"]
|
||||
except:
|
||||
|
||||
+7
-7
@@ -1016,8 +1016,8 @@ for s in bodysets:
|
||||
}
|
||||
last=0
|
||||
nmap={0:"a",1:"b",2:"c",3:"d",4:"e",5:"f",6:"g",7:"h"}
|
||||
for i in xrange(2):
|
||||
for j in xrange(4):
|
||||
for i in range(2):
|
||||
for j in range(4):
|
||||
if last<s[3]:
|
||||
sprites[s[0]]["matrix"][i][j]="%s%s"%(s[0],nmap[last])
|
||||
last+=1
|
||||
@@ -1062,7 +1062,7 @@ for s in rowsets:
|
||||
"columns":s[2],
|
||||
"matrix":[[None]*s[2]],
|
||||
}
|
||||
for i in xrange(s[2]):
|
||||
for i in range(s[2]):
|
||||
name="%s%.2d"%(s[0],i)
|
||||
if s[1]=="hat": name=name.replace("hats","hat")
|
||||
if i<s[3]:
|
||||
@@ -1070,16 +1070,16 @@ for s in rowsets:
|
||||
else:
|
||||
sprites[s[0]]["matrix"][0][i]=None
|
||||
|
||||
for i in xrange(42):
|
||||
for i in range(42):
|
||||
sprites["makeup1"]["matrix"][0].append("makeup1%.2d"%i)
|
||||
|
||||
#for i in xrange(25):
|
||||
#for i in range(25):
|
||||
# sprites["hairdo2"]["matrix"][0].append("hair2%.2d"%i)
|
||||
|
||||
# for i in xrange(41):
|
||||
# for i in range(41):
|
||||
# sprites["hairs2"]["matrix"][0].append("hair2%.2d"%i)
|
||||
|
||||
# for i in xrange(41):
|
||||
# for i in range(41):
|
||||
# sprites["hairs3"]["matrix"][0].append("hair3%.2d"%i)
|
||||
|
||||
imagesets={
|
||||
|
||||
+145
-100
@@ -218,7 +218,7 @@ def process_map(map):
|
||||
if placement[1]+width>max_x: max_x=placement[1]+width
|
||||
if placement[2]+height>max_y: max_y=placement[2]+height
|
||||
for tile in data.get("tiles",[]):
|
||||
if not marked.has_key(current):
|
||||
if current not in marked:
|
||||
logging.info("%s is unused"%current)
|
||||
else:
|
||||
marked[current]=last
|
||||
@@ -259,8 +259,7 @@ def render_selection(self,user,domain,level=80,server=None):
|
||||
if domain.is_cli and (not user or not user.cli_time or user.cli_time<datetime.now()) and level>=70:
|
||||
domain.is_cli=False; domain.harakiri=True
|
||||
start=datetime.now(); logging.info("User data in: %s"%ssince(start))
|
||||
#if domain.no_html=="bot" and self.request.get("auth"): set_cookie(self,"auth",self.request.get("auth"))
|
||||
whtml(self,"htmls/index.html",domain=domain,user=user,user_data=data,server=server,servers=servers,total=total,characters=characters)
|
||||
return whtml(self,"htmls/index.html",domain=domain,user=user,user_data=data,server=server,servers=servers,total=total,characters=characters)
|
||||
|
||||
def render_comm(self,user,domain):
|
||||
servers=get_servers(); server=select_server(self,user,servers); total=0; characters=[]; data={}
|
||||
@@ -270,19 +269,19 @@ def render_comm(self,user,domain):
|
||||
characters=get_characters(user)
|
||||
domain.characters=characters_to_client(characters)
|
||||
data=get_user_data(user);
|
||||
whtml(self,"htmls/comm.html",domain=domain,user=user,user_data=data,server=server,servers=servers,total=total,characters=characters)
|
||||
return whtml(self,"htmls/comm.html",domain=domain,user=user,user_data=data,server=server,servers=servers,total=total,characters=characters)
|
||||
|
||||
def selection_info(self,user,domain):
|
||||
servers=get_servers(); server=select_server(self,user,servers)
|
||||
return {"type":"content","html":shtml("htmls/contents/selection.html",user=user,domain=domain,server=server,servers=servers,characters=get_characters(user))}
|
||||
|
||||
def security_threat(self,domain):
|
||||
referer=self.request.headers.get('Referer') or self.request.headers.get('Origin') or ""
|
||||
def security_threat(request,domain):
|
||||
referer=request.headers.get('Referer') or request.headers.get('Origin') or ""
|
||||
if not referer: return False
|
||||
|
||||
referer=urlparse(referer).hostname
|
||||
if not referer.endswith(domain.domain):
|
||||
self.response.out.write("Threat detected")
|
||||
request.response.set_data("Threat detected")
|
||||
return True
|
||||
|
||||
# if is_production and domain.cf_always_on and not is_cloudflare(self):
|
||||
@@ -299,7 +298,7 @@ def disable_email(email,logging=None):
|
||||
user.put()
|
||||
logging.info("Disabled emails for %s"%user)
|
||||
|
||||
def get_user(self=None,domain=None,email=None,phrase_check=False,api_override=None):
|
||||
def get_user(request=None,domain=None,email=None,phrase_check=False,api_override=None):
|
||||
if email:
|
||||
try:
|
||||
email=purify_email(email)
|
||||
@@ -311,11 +310,11 @@ def get_user(self=None,domain=None,email=None,phrase_check=False,api_override=No
|
||||
return User.query(User.email == email).get()
|
||||
except:
|
||||
logTrace()
|
||||
elif self:
|
||||
auth=get_cookie(self,"auth") or self.request.get("auth")
|
||||
elif request:
|
||||
auth=get_cookie(request,"auth") or request.values.get("auth")
|
||||
if auth:
|
||||
id,auth=auth.replace('"',"").split("-")
|
||||
get_user_data(id,async=True) #trigger the get
|
||||
get_user_data(id,_async=True) #trigger the get
|
||||
user=get_by_iid("user|%s"%id)
|
||||
if user and (api_override or auth in gf(user,"auths",[])):
|
||||
return user
|
||||
@@ -357,9 +356,9 @@ def ip_in_range(ip,net):
|
||||
log_trace()
|
||||
return False
|
||||
|
||||
def get_ip(self):
|
||||
ip=self.request.remote_addr
|
||||
cloudflare_ip=self.request.headers.get("CF-Connecting-IP")
|
||||
def get_ip(request):
|
||||
ip=request.remote_addr
|
||||
cloudflare_ip=request.headers.get("CF-Connecting-IP")
|
||||
cloudflare_ranges=[
|
||||
'103.21.244.0/22',
|
||||
'103.22.200.0/22',
|
||||
@@ -389,10 +388,10 @@ def get_ip(self):
|
||||
if ip.find(":")==-1 and ip_in_range(ip,crange): return cloudflare_ip
|
||||
for crange in cloudflare_ranges_v6:
|
||||
if ip.find(":")!=-1 and ip.startswith(crange[:7]): return cloudflare_ip #not sure 9 or 7 [25/08/13]
|
||||
return self.request.remote_addr
|
||||
return request.remote_addr
|
||||
|
||||
def get_country(self):
|
||||
return self.request.headers.get("Cf-Ipcountry") or self.request.headers.get("X-Appengine-Country") or "XX"
|
||||
def get_country(request):
|
||||
return request.headers.get("Cf-Ipcountry") or request.headers.get("X-Appengine-Country") or "XX"
|
||||
|
||||
def get_character(id,phrase_check=False):
|
||||
if id.isdigit() and get_by_iid("character|%s"%id): return get_by_iid("character|%s"%id)
|
||||
@@ -417,9 +416,9 @@ def process_user_data(user,data):
|
||||
calculate_tutorial_step(data)
|
||||
return data
|
||||
|
||||
def get_user_data(user,async=False):
|
||||
def get_user_data(user,_async=False):
|
||||
if hasattr(user,"k"): user=user.k()
|
||||
if async:
|
||||
if _async:
|
||||
return get_by_iid_async("infoelement|userdata-%s"%user)
|
||||
else:
|
||||
data=get_by_iid("infoelement|userdata-%s"%user)
|
||||
@@ -431,7 +430,7 @@ def delete_user_data(user):
|
||||
ndb.Key(InfoElement,"userdata-%s"%user).delete()
|
||||
|
||||
def reset_tutorial(user):
|
||||
data=get_user_data(user,async=False)
|
||||
data=get_user_data(user,_async=False)
|
||||
data.info.completed_tasks=[] #completed tutorial tasks
|
||||
data.info.tutorial_step=0 #tutorial step
|
||||
data.put()
|
||||
@@ -455,7 +454,7 @@ def remove_ip_exception(ip_a):
|
||||
ip.put()
|
||||
|
||||
def get_ip_info(ip):
|
||||
if type(ip) not in types.StringTypes: ip=get_ip(ip)
|
||||
if not is_string(ip): ip=get_ip(ip)
|
||||
info=get_by_iid("ip|%s"%ip)
|
||||
if not info: info=IP(key=ndb.Key(IP,ip),info=cGG(users=[],characters=[],metrics={},last_decay=datetime.now()))
|
||||
decay_ip_info(info)
|
||||
@@ -493,11 +492,11 @@ def servers_to_client(domain,servers_data):
|
||||
servers.append({"name":server.name,"region":server.region,"players":server.info.players,"key":server.k(),"addr":domain.https and server.ip or server.actual_ip,"port":server.port})
|
||||
return servers
|
||||
|
||||
def get_characters(user,async=False):
|
||||
def get_characters(user,_async=False):
|
||||
characters=[]
|
||||
for c in user.info.characters:
|
||||
characters.append(get_by_iid_async("character|%s"%c["id"]))
|
||||
if async: return characters
|
||||
if _async: return characters
|
||||
for i in xrange(len(characters)):
|
||||
characters[i]=characters[i].get_result()
|
||||
return characters
|
||||
@@ -526,7 +525,7 @@ def character_to_dict(character):
|
||||
data["map"]=character.info.map
|
||||
data["x"]=character.info.x
|
||||
data["y"]=character.info.y
|
||||
if gf(character,"p") and character.info.p.has_key("home"):
|
||||
if gf(character,"p") and "home" in character.info.p:
|
||||
data["home"]=character.info.p["home"]
|
||||
|
||||
return data
|
||||
@@ -628,7 +627,7 @@ def update_pids(character,data,owner):
|
||||
def character_to_info(character,user=None,ip=None,guild=None):
|
||||
drm=False
|
||||
drm_fail=False
|
||||
if user and user.created>datetime(2019,02,01,0,0) and not gf(user,"legacy_override"): drm=True
|
||||
if user and user.created>datetime(2019,2,1,0,0) and not gf(user,"legacy_override"): drm=True
|
||||
if gf(user,"drm_fail_pid","not")==character.pid: drm_fail=True
|
||||
info={
|
||||
"id":character.k(),
|
||||
@@ -740,13 +739,13 @@ def pretty_timeleft(t):
|
||||
left=left+" %d minutes"%minutes
|
||||
return left
|
||||
|
||||
def gdpr_delete(self,user,logging=None):
|
||||
def gdpr_delete(request,user,logging=None):
|
||||
from api import delete_character_api
|
||||
if not logging: logging=globals()["logging"]
|
||||
if not hasattr(user,"k"): user=get_user(email=user)
|
||||
for c in gf(user,"characters",[]):
|
||||
user.info.last_delete=really_old
|
||||
delete_character_api(user=user,self=self,domain=gdi(self),name=c["name"])
|
||||
delete_character_api(user=user,self=request,domain=gdi(request),name=c["name"])
|
||||
logging.info("Deleted %s"%c["name"])
|
||||
markedphrase=get_by_iid("markedphrase|%s"%dgt("email",user.info.email))
|
||||
if markedphrase: markedphrase.key.delete()
|
||||
@@ -902,12 +901,12 @@ def character_analysis(name,logging=None):
|
||||
|
||||
logging.info("%s[%s] %s"%(character.info.name,character.level,to_pretty_num(character.info.gold)))
|
||||
for h in gf(character,"p",{}).get("history",[]):
|
||||
if h.get("from") and not names.has_key(h.get("from")):
|
||||
if h.get("from") and h.get("from") not in names:
|
||||
e=froms.get(h["from"],[0,0])
|
||||
e[0]+=1
|
||||
e[1]+=h.get("amount",0) or h.get("item","") and item_value({"name":h["item"],"level":h.get("level",0)}) or 0
|
||||
froms[h["from"]]=e
|
||||
if h.get("to") and not names.has_key(h.get("to")):
|
||||
if h.get("to") and h.get("to") not in names:
|
||||
e=tos.get(h["to"],[0,0])
|
||||
e[0]+=1
|
||||
e[1]+=h.get("amount",0) or h.get("item","") and item_value({"name":h["item"],"level":h.get("level",0)}) or 0
|
||||
@@ -1180,7 +1179,7 @@ def select_server(self,user,servers):
|
||||
min_dist=99999999999; the_server=None; max_rank=-99999; u_server=""
|
||||
if user and len(gf(user,"characters",[])):
|
||||
for c in gf(user,"characters",[]):
|
||||
if c.has_key("home"):
|
||||
if "home" in c:
|
||||
u_server=c["home"]
|
||||
break;
|
||||
logging.info(u_server)
|
||||
@@ -1282,7 +1281,7 @@ def refactor_item(current):
|
||||
current["level"]=0
|
||||
if current and items[current["name"]].get("s",""):
|
||||
current["q"]=current.get("quantity",current.get("q",1))
|
||||
if current.has_key("quantity"): del current["quantity"]
|
||||
if "quantity" in current: del current["quantity"]
|
||||
|
||||
def refactor_character_items(character):
|
||||
for i in range(0,len(character.info.items)):
|
||||
@@ -1314,23 +1313,29 @@ def download_map(name,sdk_name=""):
|
||||
def download_maps():
|
||||
if not is_sdk: return
|
||||
for m in maps:
|
||||
element=download_by_iid("map|%s"%m)
|
||||
if element: Map(key=ndb.Key(Map,m),info=element.info).put()
|
||||
element=download_by_iid("map|%s"%maps[m]["key"])
|
||||
if element: Map(key=ndb.Key(Map,maps[m]["key"]),info=element.info).put()
|
||||
|
||||
def empty_fill_maps():
|
||||
if not is_sdk: return
|
||||
for m in maps:
|
||||
element=get_by_iid("map|%s"%maps[m]["key"])
|
||||
if not element: Map(key=ndb.Key(Map,maps[m]["key"]),info=cGG(data={"tiles":[],"placements":[]})).put()
|
||||
|
||||
def copy_map(fr,to):
|
||||
fr=get_by_iid("map|%s"%fr)
|
||||
m=Map(key=ndb.Key(Map,to),info=fr.info); m.put()
|
||||
|
||||
def get_server(self,domain):
|
||||
auth=self.request.get("server_auth")
|
||||
def get_server(request,domain):
|
||||
auth=request.values.get("server_auth")
|
||||
if auth:
|
||||
logging.info("get_server auth: %s"%auth)
|
||||
id,auth=auth.split("-")
|
||||
server=get_by_iid("server|%s"%id)
|
||||
if server and gf(server,"auth")==auth: return server
|
||||
|
||||
def get_referrer(self,ip):
|
||||
referrer=get_cookie(self,"referrer") or ip.referrer
|
||||
def get_referrer(request,ip):
|
||||
referrer=get_cookie(request,"referrer") or ip.referrer
|
||||
if referrer and referrer.replace('"',"")[0] in ["0","1","2","3","4","5","6","7","8","9"]: referrer=get_by_iid("user|%s"%referrer.replace('"',""))
|
||||
elif referrer: referrer=get_owner(referrer.replace('"',""))
|
||||
return referrer
|
||||
@@ -1362,7 +1367,7 @@ def increase_characterth():
|
||||
try: main.put()
|
||||
except: logTrace()
|
||||
|
||||
def get_new_auth(self,user,domain):
|
||||
def get_new_auth(request,user,domain):
|
||||
auth=randomStr(20)
|
||||
user.info.auths=gf(user,"auths",[])
|
||||
user.info.last_auth=datetime.now()
|
||||
@@ -1372,7 +1377,7 @@ def get_new_auth(self,user,domain):
|
||||
return auth
|
||||
|
||||
def download_by_iid(iid):
|
||||
result=urlfetch.fetch(url="https://twodimensionalgame.appspot.com/tasks/download",payload=urllib.urlencode({"password":ELEMENT_PASSWORD,"iid":iid}),
|
||||
result=urlfetch.fetch(url="https://twodimensionalgame.appspot.com/tasks/download",payload=urlencode({"password":ELEMENT_PASSWORD,"iid":iid}),
|
||||
method=urlfetch.POST,headers={'Content-Type':'application/x-www-form-urlencoded'},validate_certificate=False)
|
||||
return cPickle.loads(result.content)
|
||||
|
||||
@@ -1382,7 +1387,7 @@ def post_task(task,element=None,element2=None,element3=None,logging=None):
|
||||
element=element and cPickle.dumps(element) or ""
|
||||
element2=element2 and cPickle.dumps(element2) or ""
|
||||
element3=element3 and cPickle.dumps(element3) or ""
|
||||
result=urlfetch.fetch(url="https://twodimensionalgame.appspot.com/tasks/post",payload=urllib.urlencode({"p":SDK_UPLOAD_PASSWORD,"operation":"upload","obj1":element,"obj2":element2,"obj3":element3,"task_code":task}),
|
||||
result=urlfetch.fetch(url="https://twodimensionalgame.appspot.com/tasks/post",payload=urlencode({"p":SDK_UPLOAD_PASSWORD,"operation":"upload","obj1":element,"obj2":element2,"obj3":element3,"task_code":task}),
|
||||
method=urlfetch.POST,headers={'Content-Type': 'application/x-www-form-urlencoded'},validate_certificate=False)
|
||||
result=cPickle.loads(str(result.content))
|
||||
logging.info("post_task result: %s"%result)
|
||||
@@ -1394,10 +1399,10 @@ def safe_commit(element):
|
||||
def domain_routine(domain):
|
||||
pass #GTODO: Implement
|
||||
|
||||
def delete_phrase_mark(type,phrase,async=False):
|
||||
def delete_phrase_mark(type,phrase,_async=False):
|
||||
ndb.Key(MarkedPhrase,dgt(type,phrase)).delete()
|
||||
|
||||
def mark_phrase(owner,phrase_type,phrase,async=False):
|
||||
def mark_phrase(owner,phrase_type,phrase,_async=False):
|
||||
MarkedPhrase(key=ndb.Key(MarkedPhrase,dgt(phrase_type,phrase)),type=phrase_type,phrase=str_or_unicode(phrase),owner=to_string_key(owner)).put()
|
||||
|
||||
def marker_check(id):
|
||||
@@ -1407,7 +1412,7 @@ def marker_check(id):
|
||||
return True
|
||||
return ndb.transaction(marker_transaction,xg=True,retries=12)
|
||||
|
||||
def whtml(self,path,**dct):
|
||||
def whtml(request,path,**dct):
|
||||
#path = os.path.join(os.path.dirname(__file__), pth)
|
||||
start_time=datetime.now()
|
||||
template = j2.get_template(path)
|
||||
@@ -1418,16 +1423,21 @@ def whtml(self,path,**dct):
|
||||
response=response.replace('="/','="%s/'%dct["domain"].secure_base_url).replace("='/","='%s/"%dct["domain"].secure_base_url)
|
||||
else:
|
||||
response=response.replace('="/','="%s/'%dct["domain"].base_url).replace("='/","='%s/"%dct["domain"].base_url)
|
||||
self.response.out.write(response)
|
||||
request.response.set_data(response)
|
||||
return request.response
|
||||
|
||||
def shtml(path,**dct):
|
||||
#path = os.path.join(os.path.dirname(__file__), pth)
|
||||
start_time=datetime.now()
|
||||
template = j2.get_template(path)
|
||||
if mssince(start_time)>250: logging.warning("JINJA2 WARNING %s took %s ms"%(path,mssince(start_time)))
|
||||
#html=template.render(dct)
|
||||
#if dct.pop("convert_onclicks",""): html=html.replace('onclick="','ontap="') #experimental [28/05/15]
|
||||
return template.render(dct)
|
||||
response=template.render(dct)
|
||||
if dct.get("domain","") and dct["domain"].electron:
|
||||
if dct["domain"].https:
|
||||
response=response.replace('="/','="%s/'%dct["domain"].secure_base_url).replace("='/","='%s/"%dct["domain"].secure_base_url)
|
||||
else:
|
||||
response=response.replace('="/','="%s/'%dct["domain"].base_url).replace("='/","='%s/"%dct["domain"].base_url)
|
||||
return response
|
||||
|
||||
def pre_put_hook(self):
|
||||
try:
|
||||
@@ -1449,10 +1459,10 @@ def arr_arr_same(ar1,ar2):
|
||||
if not d.get(e): return False
|
||||
return True
|
||||
|
||||
def delete_phrase_mark(type,phrase,async=False):
|
||||
def delete_phrase_mark(type,phrase,_async=False):
|
||||
ndb.Key(MarkedPhrase,dgt(type,phrase)).delete()
|
||||
|
||||
def mark_phrase(owner,phrase_type,phrase,async=False):
|
||||
def mark_phrase(owner,phrase_type,phrase,_async=False):
|
||||
MarkedPhrase(key=ndb.Key(MarkedPhrase,dgt(phrase_type,phrase)),type=phrase_type,phrase=str_or_unicode(phrase),owner=to_string_key(owner)).put()
|
||||
|
||||
def to_id(id):
|
||||
@@ -1468,7 +1478,7 @@ def to_id(id):
|
||||
def k_factory(self,t=""):
|
||||
if t=="h":
|
||||
the_key=self.key.id()
|
||||
if type(the_key) in [types.IntType,types.LongType]: return the_key
|
||||
if is_int(the_key): return the_key
|
||||
return string_to_int(the_key)
|
||||
if t=="e": return "%s"%has_key(self) or "-1" #as a placeholder mainly for the StuffHandler routines [28/08/14]
|
||||
if t=="s": the_key=has_key(self)
|
||||
@@ -1476,11 +1486,14 @@ def k_factory(self,t=""):
|
||||
try: u"%s"%the_key
|
||||
except: the_key=the_key.decode("utf-8")
|
||||
if t in ["i","s",1]: return dmt(model_name(self),the_key)
|
||||
return unicode(the_key)
|
||||
try:
|
||||
return unicode(the_key)
|
||||
except:
|
||||
return str(the_key) #python3 [27/01/24]
|
||||
|
||||
def to_model(string):
|
||||
d=globals()
|
||||
if d.has_key(string.title()): return d[string.title()]
|
||||
if string.title() in d: return d[string.title()]
|
||||
for e in d.keys():
|
||||
try:
|
||||
if len(e) and e[0].isupper() and e.lower()==string.lower(): return d[e]
|
||||
@@ -1489,30 +1502,30 @@ def to_model(string):
|
||||
def dgt(*list,**dct):
|
||||
lst=[]
|
||||
for i in range(0,len(list)): lst.append(to_str(list[i]))
|
||||
if dct.has_key("sort"): lst.sort()
|
||||
if "sort" in dct: lst.sort()
|
||||
return "-".join(lst)
|
||||
|
||||
def dge(*list,**dct):
|
||||
lst=[]
|
||||
for i in range(0,len(list)): lst.append(to_str(list[i]))
|
||||
if dct.has_key("sort"): lst.sort()
|
||||
if "sort" in dct: lst.sort()
|
||||
return "".join(lst)
|
||||
|
||||
def dse(*list,**dct):
|
||||
lst=[]
|
||||
for i in range(0,len(list)): lst.append(to_str(list[i]))
|
||||
if dct.has_key("sort"): lst.sort()
|
||||
if "sort" in dct: lst.sort()
|
||||
return " ".join(lst)
|
||||
|
||||
def dmt(*list,**dct):
|
||||
lst=[]
|
||||
for i in range(0,len(list)): lst.append(to_str(list[i]))
|
||||
if dct.has_key("sort"): lst.sort()
|
||||
if "sort" in dct: lst.sort()
|
||||
return "|".join(lst)
|
||||
|
||||
def to_string_key(element):
|
||||
if type(element) in [types.IntType,types.LongType]: return str(element)
|
||||
if type(element) in types.StringTypes: return element
|
||||
if is_int(element): return str(element)
|
||||
if is_string(element): return element
|
||||
return element.k()
|
||||
|
||||
def str_or_unicode(s):
|
||||
@@ -1527,6 +1540,18 @@ def model_name(item):
|
||||
return item.get("base_type",item.get("type",""))
|
||||
return item._class_name().lower()
|
||||
|
||||
def is_int(i):
|
||||
if 1/2 == 0:
|
||||
return type(i) in [types.IntType,types.LongType]
|
||||
else:
|
||||
return isinstance(i,int)
|
||||
|
||||
def is_string(s):
|
||||
if 1/2 == 0:
|
||||
return isinstance(s, basestring)
|
||||
else:
|
||||
return isinstance(s, str)
|
||||
|
||||
def is_array(a):
|
||||
if hasattr(a, "__len__"): return True
|
||||
|
||||
@@ -1585,7 +1610,7 @@ def calculate_tutorial_step(user_data):
|
||||
for i in xrange(len(docs["tutorial"])):
|
||||
done=True
|
||||
for key in docs["tutorial"][i]["tasks"]:
|
||||
if not marked.has_key(key): done=False
|
||||
if key not in marked: done=False
|
||||
if not done and user_data.info.tutorial_step>i:
|
||||
user_data.info.tutorial_step=i
|
||||
break
|
||||
@@ -1640,11 +1665,11 @@ def to_str(s):
|
||||
def split_iid(s):
|
||||
return s.split("|",1)
|
||||
|
||||
def get_by_iid(iid,async=False,no_cache=False):
|
||||
def get_by_iid(iid,_async=False,no_cache=False):
|
||||
mname,id=split_iid(iid)
|
||||
try:
|
||||
k=ndb.Key(to_model(mname),to_id(id))
|
||||
if async: return k.get_async()
|
||||
if _async: return k.get_async()
|
||||
else:
|
||||
if no_cache: return k.get(use_cache=False)
|
||||
return k.get()
|
||||
@@ -1653,7 +1678,7 @@ def get_by_iid(iid,async=False,no_cache=False):
|
||||
return None
|
||||
|
||||
def get_by_iid_async(iid):
|
||||
return get_by_iid(iid,async=True)
|
||||
return get_by_iid(iid,_async=True)
|
||||
|
||||
def purify_email(email,check=True):
|
||||
email=email.replace(" ","").replace("\t","").replace("\n","").replace("\r","")
|
||||
@@ -1669,16 +1694,16 @@ def purify_email(email,check=True):
|
||||
return email
|
||||
|
||||
def gf(element,name,default=None): # as in getattr info fast :)
|
||||
if not hasattr(element,"info") or type(element.info)!=types.InstanceType: return getattr(element,name,default)
|
||||
if not hasattr(element,"info") or type(element.info)!=type(GG()): return getattr(element,name,default)
|
||||
return getattr(element.info,name,default)
|
||||
|
||||
def gt(element,name,default=None):
|
||||
return getattr(element,name,default)
|
||||
|
||||
def gdmul(self,*lst):
|
||||
def gdmul(request,*lst):
|
||||
gg=[]
|
||||
for l in lst:
|
||||
gg.append(self.request.get(l))
|
||||
gg.append(request.values.get(l))
|
||||
if len(gg)==1: return gg[0]
|
||||
return gg
|
||||
|
||||
@@ -1714,14 +1739,15 @@ def jsuccess(self,message,duration=0):
|
||||
if not getattr(self,"_cjsons",0): self._cjsons=[]
|
||||
self._cjsons.append({"type":"success","message":message,"duration":duration})
|
||||
|
||||
def jhtml(self,jsn=[]):
|
||||
if not self: return
|
||||
if getattr(self,"_cjsons",0):
|
||||
self._cjsons.extend(jsn)
|
||||
def jhtml(request,jsn=[]):
|
||||
if not request: return
|
||||
if getattr(request,"_cjsons",0):
|
||||
request._cjsons.extend(jsn)
|
||||
#logging.info("CJSONS %s"%self._cjsons)
|
||||
self.response.out.write(json.dumps(self._cjsons))
|
||||
request.response.set_data(json.dumps(self._cjsons))
|
||||
else:
|
||||
self.response.out.write(json.dumps(jsn))
|
||||
request.response.set_data(json.dumps(jsn))
|
||||
return request.response
|
||||
|
||||
def jhtmle(self,err):
|
||||
if not self: return
|
||||
@@ -1789,25 +1815,25 @@ def log_trace(place="",logger=None):
|
||||
logger.error("\n\n<<<<<<<<<< log_trace %s %s>>>>>>>>>>"%(exc_type,place),exc_info=sys.exc_info())
|
||||
logger.error("\n")
|
||||
|
||||
def get_domain(self=None):
|
||||
def get_domain(request=None):
|
||||
if not is_sdk:
|
||||
return live_domain
|
||||
else:
|
||||
if self:
|
||||
return (urlparse(self.request.url)).hostname
|
||||
if request:
|
||||
return (urlparse(request.url)).hostname
|
||||
else:
|
||||
return sdk_domain
|
||||
|
||||
def get_cookie(self,name):
|
||||
return self.request.cookies.get(name)
|
||||
def get_cookie(request,name):
|
||||
return request.cookies.get(name)
|
||||
|
||||
def set_cookie(self,name,value):
|
||||
hostname=get_domain(self)
|
||||
self.response.set_cookie(name,to_str(value),max_age=86400*365*5, path='/',domain='.%s'%(hostname),secure=secure_cookies)
|
||||
def set_cookie(request,name,value):
|
||||
hostname=get_domain(request)
|
||||
request.response.set_cookie(name,to_str(value),max_age=86400*365*5, path='/',domain='.%s'%(hostname),secure=secure_cookies)
|
||||
|
||||
def delete_cookie(self,name):
|
||||
hostname=get_domain(self)
|
||||
self.response.delete_cookie(name,path='/',domain='.%s'%(hostname))
|
||||
def delete_cookie(request,name):
|
||||
hostname=get_domain(request)
|
||||
request.response.delete_cookie(name,path='/',domain='.%s'%(hostname))
|
||||
|
||||
class StrLogHandler(logging.Handler):
|
||||
def __init__(self, output):
|
||||
@@ -1872,9 +1898,9 @@ def randomStr(length,digits_only=False,lowercase_only=False):
|
||||
for i in range(0,length+1): s+=chars[random.randrange(0,len(chars))]
|
||||
return s
|
||||
|
||||
def add_event(element,type,tags,info=None,backup=False,async=False,self=None,rowner=None,selfic=None):
|
||||
def add_event(element,type,tags,info=None,backup=False,_async=False,self=None,rowner=None,selfic=None):
|
||||
logging.info("add_event %s %s %s"%(element and element.k('i'),type,tags))
|
||||
if backup and element: backup=backup_item(element,async=True)
|
||||
if backup and element: backup=backup_item(element,_async=True)
|
||||
else: backup=None
|
||||
if not info: info=GG()
|
||||
if type not in tags: tags.append(type)
|
||||
@@ -1888,13 +1914,13 @@ def add_event(element,type,tags,info=None,backup=False,async=False,self=None,row
|
||||
event.item_id=element.k('i')
|
||||
if hasattr(element,"region"): event.info.e_name="%s %s"%(element.region,element.name)
|
||||
elif hasattr(element,"name"): event.info.e_name=element.name
|
||||
if async: return event.put_async()
|
||||
if _async: return event.put_async()
|
||||
else:
|
||||
if backup: backup.wait()
|
||||
event.put()
|
||||
return event
|
||||
|
||||
def backup_item(element,rkey=None,async=False):
|
||||
def backup_item(element,rkey=None,_async=False):
|
||||
logging.info("backup_item %s"%element.k('i'))
|
||||
#if not has_key(element): logging.error("Backup: Element doesn't have a key"); return
|
||||
if rkey: backup=Backup(key=ndb.Key(Backup,rkey))
|
||||
@@ -1909,7 +1935,7 @@ def backup_item(element,rkey=None,async=False):
|
||||
setattr(backup,k,i)
|
||||
backup.backup_info=cGG(original_properties=element._properties)
|
||||
backup.backup_created=datetime.now()
|
||||
if async: return backup.put_async()
|
||||
if _async: return backup.put_async()
|
||||
else:
|
||||
backup.put()
|
||||
return backup
|
||||
@@ -1948,7 +1974,10 @@ _js_escapes = (_base_js_escapes +
|
||||
@jrf
|
||||
def escapejs(value):
|
||||
"""Hex encodes characters for use in JavaScript strings."""
|
||||
if not isinstance(value, basestring):
|
||||
base=str
|
||||
if 1/2 == 0:
|
||||
base=basestring
|
||||
if not isinstance(value, base):
|
||||
value = str(value)
|
||||
|
||||
for bad, good in _js_escapes:
|
||||
@@ -2140,7 +2169,7 @@ def fetch_url(url_u,**dct):
|
||||
else: url_u="https://adventure.land"+url_u
|
||||
if dct or dct.pop("use_post",""):
|
||||
encode_unicodes(dct)
|
||||
data = urllib.urlencode(dct)
|
||||
data = urlencode(dct)
|
||||
return urlfetch.fetch(url=url_u,payload=data,method=urlfetch.POST,validate_certificate=is_production).content
|
||||
else:
|
||||
return urlfetch.fetch(url=url_u,method=urlfetch.GET,validate_certificate=is_production).content
|
||||
@@ -2148,9 +2177,9 @@ def fetch_url(url_u,**dct):
|
||||
def fetch_url_async(url_u,**dct):
|
||||
rpc=urlfetch.create_rpc(deadline=40)
|
||||
if dct.pop("use_get",""):
|
||||
urlfetch.make_fetch_call(rpc,url_u+"?"+urllib.urlencode(dct),method=urlfetch.GET,validate_certificate=False)
|
||||
urlfetch.make_fetch_call(rpc,url_u+"?"+urlencode(dct),method=urlfetch.GET,validate_certificate=False)
|
||||
else:
|
||||
data = urllib.urlencode(dct)
|
||||
data = urlencode(dct)
|
||||
urlfetch.make_fetch_call(rpc,url_u,payload=data,method=urlfetch.POST,headers={'Content-Type': 'application/x-www-form-urlencoded'},validate_certificate=False)
|
||||
return rpc
|
||||
|
||||
@@ -2165,7 +2194,7 @@ def send_email(domain,email="kaansoral@gmail.com",title="Default Title",html="De
|
||||
ses=amazon_ses.AmazonSES(secrets.amazon_ses_user,secrets.amazon_ses_key)
|
||||
#logging.info(ses.listVerifiedEmailAddresses().members)
|
||||
try: ses.sendEmail("pr@createandspread.com","kaansoral@gmail.com",message)
|
||||
except amazon_ses.AmazonError,e:
|
||||
except amazon_ses.AmazonError as e:
|
||||
logging.info(e.errorType); logging.info(e.code); logging.info(e.message);
|
||||
log_trace()
|
||||
elif always_amazon_ses:
|
||||
@@ -2176,7 +2205,7 @@ def send_email(domain,email="kaansoral@gmail.com",title="Default Title",html="De
|
||||
ses=amazon_ses.AmazonSES(secrets.amazon_ses_user,secrets.amazon_ses_key)
|
||||
#logging.info(ses.listVerifiedEmailAddresses().members)
|
||||
try: ses.sendEmail("hello@adventure.land",email,message)
|
||||
except amazon_ses.AmazonError,e:
|
||||
except amazon_ses.AmazonError as e:
|
||||
logging.info(e.errorType); logging.info(e.code); logging.info(e.message);
|
||||
log_trace()
|
||||
else:
|
||||
@@ -2187,13 +2216,20 @@ def send_email(domain,email="kaansoral@gmail.com",title="Default Title",html="De
|
||||
import hmac,hashlib
|
||||
from struct import Struct
|
||||
from operator import xor
|
||||
from itertools import izip, starmap
|
||||
from itertools import starmap
|
||||
try:
|
||||
from itertools import izip
|
||||
except:
|
||||
izip=zip
|
||||
_pack_int = Struct('>I').pack
|
||||
|
||||
#https://code.google.com/p/googleappengine/issues/detail?id=5303 and https://github.com/mitsuhiko/python-pbkdf2/blob/master/pbkdf2.py
|
||||
def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc=None):
|
||||
"""Like :func:`pbkdf2_bin` but returns a hex encoded string."""
|
||||
return pbkdf2_bin(data, salt, iterations, keylen, hashfunc).encode('hex')
|
||||
if 1/2==0:
|
||||
return pbkdf2_bin(data, salt, iterations, keylen, hashfunc).encode('hex')
|
||||
else:
|
||||
pbkdf2_bin(data, salt, iterations, keylen, hashfunc).encode("utf-8").hex()
|
||||
|
||||
def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
|
||||
"""Returns a binary digest for the PBKDF2 hash algorithm of `data`
|
||||
@@ -2206,13 +2242,22 @@ def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
|
||||
def _pseudorandom(x, mac=mac):
|
||||
h = mac.copy()
|
||||
h.update(x)
|
||||
return map(ord, h.digest())
|
||||
if 1/2==0:
|
||||
return map(ord, h.digest())
|
||||
else:
|
||||
return map(lambda x:x, h.digest())
|
||||
buf = []
|
||||
for block in xrange(1, -(-keylen // mac.digest_size) + 1):
|
||||
rv = u = _pseudorandom(salt + _pack_int(block))
|
||||
for i in xrange(iterations - 1):
|
||||
u = _pseudorandom(''.join(map(chr, u)))
|
||||
rv = starmap(xor, izip(rv, u))
|
||||
if 1/2 == 0:
|
||||
rv = u = _pseudorandom(salt + _pack_int(block))
|
||||
for i in xrange(iterations - 1):
|
||||
u = _pseudorandom(''.join(map(chr, u)))
|
||||
rv = starmap(xor, izip(rv, u))
|
||||
else:
|
||||
rv = u = _pseudorandom(salt.encode(encoding = 'UTF-8', errors = 'strict') + _pack_int(block))
|
||||
for i in xrange(iterations - 1):
|
||||
u = _pseudorandom(''.join(map(chr, u)).encode(encoding = 'UTF-8', errors = 'strict'))
|
||||
rv = starmap(xor, izip(rv, u))
|
||||
buf.extend(rv)
|
||||
return ''.join(map(chr, buf))[:keylen]
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import httplib
|
||||
try:
|
||||
import httplib
|
||||
except:
|
||||
import http.client as httplib #for python3
|
||||
import urllib
|
||||
import hashlib
|
||||
import hmac
|
||||
@@ -7,6 +10,8 @@ import base64
|
||||
from datetime import datetime
|
||||
from xml.etree.ElementTree import XML
|
||||
|
||||
if 1/2 != 0: basestring=str
|
||||
|
||||
def encodeUnicodez(args):
|
||||
if args and type(args)==type({}):
|
||||
for key,value in args.items():
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
try:
|
||||
import http.client
|
||||
except:
|
||||
import http.client as httplib #for python3
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
import hashlib
|
||||
import hmac
|
||||
import logging
|
||||
import base64
|
||||
from datetime import datetime
|
||||
from xml.etree.ElementTree import XML
|
||||
|
||||
if 1/2 != 0: str=str
|
||||
|
||||
def encodeUnicodez(args):
|
||||
if args and type(args)==type({}):
|
||||
for key,value in list(args.items()):
|
||||
if type(value)==type(""):
|
||||
args[key]=value.encode("utf-8")
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class AmazonSES:
|
||||
def __init__(self, accessKeyID, secretAccessKey):
|
||||
self._accessKeyID = accessKeyID
|
||||
self._secretAccessKey = secretAccessKey
|
||||
self._responseParser = AmazonResponseParser()
|
||||
|
||||
def _getSignature(self, dateValue):
|
||||
h = hmac.new(key=self._secretAccessKey, msg=dateValue, digestmod=hashlib.sha256)
|
||||
return base64.b64encode(h.digest()).decode()
|
||||
|
||||
def _getHeaders(self,oparams,params):
|
||||
#headers = { 'Content-type': 'application/x-www-form-urlencoded' }
|
||||
#d = datetime.utcnow()
|
||||
#dateValue = d.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||
#headers['Date'] = dateValue
|
||||
#signature = self._getSignature(dateValue)
|
||||
#headers['X-Amzn-Authorization'] = 'AWS3-HTTPS AWSAccessKeyId=%s, Algorithm=HMACSHA256, Signature=%s' % (self._accessKeyID, signature)
|
||||
|
||||
def sign(key, msg):
|
||||
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
|
||||
|
||||
def getSignatureKey(key, dateStamp, regionName, serviceName):
|
||||
kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
|
||||
kRegion = sign(kDate, regionName)
|
||||
kService = sign(kRegion, serviceName)
|
||||
kSigning = sign(kService, 'aws4_request')
|
||||
return kSigning
|
||||
|
||||
# Read AWS access key from env. variables or configuration file. Best practice is NOT
|
||||
# to embed credentials in code.
|
||||
access_key = self._accessKeyID
|
||||
secret_key = self._secretAccessKey
|
||||
|
||||
# Create a date for headers and the credential string
|
||||
t = datetime.utcnow()
|
||||
amzdate = t.strftime('%Y%m%dT%H%M%SZ')
|
||||
datestamp = t.strftime('%Y%m%d') # Date w/o time, used in credential scope
|
||||
|
||||
|
||||
# ************* TASK 1: CREATE A CANONICAL REQUEST *************
|
||||
# http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
|
||||
# Step 1 is to define the verb (GET, POST, etc.)--already done.
|
||||
|
||||
# Step 2: Create canonical URI--the part of the URI from domain to query
|
||||
# string (use '/' if no path)
|
||||
content_type='application/x-www-form-urlencoded'
|
||||
service = 'ec2'; service='email'
|
||||
host = 'email.us-east-1.amazonaws.com'
|
||||
region = 'us-east-1'
|
||||
endpoint = 'https://email.us-east-1.amazonaws.com'
|
||||
canonical_uri = '/'
|
||||
method='POST'
|
||||
|
||||
# Step 3: Create the canonical query string. In this example (a GET request),
|
||||
# request parameters are in the query string. Query string values must
|
||||
# be URL-encoded (space=%20). The parameters must be sorted by name.
|
||||
# For this example, the query string is pre-formatted in the request_parameters variable.
|
||||
#canonical_querystring = request_parameters = 'Action=%s'%oparams['Action']
|
||||
canonical_querystring=params
|
||||
canonical_querystring=''
|
||||
|
||||
# Step 4: Create the canonical headers and signed headers. Header names
|
||||
# must be trimmed and lowercase, and sorted in code point order from
|
||||
# low to high. Note that there is a trailing \n.
|
||||
canonical_headers = 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n'
|
||||
|
||||
# Step 5: Create the list of signed headers. This lists the headers
|
||||
# in the canonical_headers list, delimited with ";" and in alpha order.
|
||||
# Note: The request can include any headers; canonical_headers and
|
||||
# signed_headers lists those that you want to be included in the
|
||||
# hash of the request. "Host" and "x-amz-date" are always required.
|
||||
signed_headers = 'host;x-amz-date'
|
||||
|
||||
# Step 6: Create payload hash (hash of the request body content). For GET
|
||||
# requests, the payload is an empty string ("").
|
||||
payload_hash = hashlib.sha256((params).encode('utf-8')).hexdigest()
|
||||
|
||||
# Step 7: Combine elements to create canonical request
|
||||
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
|
||||
|
||||
|
||||
# ************* TASK 2: CREATE THE STRING TO SIGN*************
|
||||
# Match the algorithm to the hashing algorithm you use, either SHA-1 or
|
||||
# SHA-256 (recommended)
|
||||
algorithm = 'AWS4-HMAC-SHA256'
|
||||
credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
|
||||
string_to_sign = algorithm + '\n' + amzdate + '\n' + credential_scope + '\n' + hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
|
||||
logging.info(string_to_sign)
|
||||
|
||||
# ************* TASK 3: CALCULATE THE SIGNATURE *************
|
||||
# Create the signing key using the function defined above.
|
||||
signing_key = getSignatureKey(secret_key, datestamp, region, service)
|
||||
|
||||
# Sign the string_to_sign using the signing_key
|
||||
signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()
|
||||
|
||||
authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
|
||||
headers = {'Content-Type':content_type,
|
||||
#'X-Amz-Algorithm':'AWS4-HMAC-SHA256',
|
||||
'X-Amz-Date':amzdate,
|
||||
'Authorization':authorization_header}
|
||||
return headers
|
||||
|
||||
def _performAction(self, actionName, params=None):
|
||||
if not params:
|
||||
params = {}
|
||||
params['Action'] = actionName
|
||||
oparams=params
|
||||
#https://email.us-east-1.amazonaws.com/
|
||||
conn = http.client.HTTPSConnection('email.us-east-1.amazonaws.com')
|
||||
encodeUnicodez(params)
|
||||
params = urllib.parse.urlencode(params)
|
||||
conn.request('POST', '/', params, self._getHeaders(oparams,params))
|
||||
response = conn.getresponse()
|
||||
responseResult = response.read()
|
||||
conn.close()
|
||||
return self._responseParser.parse(actionName, response.status, response.reason, responseResult)
|
||||
|
||||
def verifyEmailAddress(self, emailAddress):
|
||||
params = { 'EmailAddress': emailAddress }
|
||||
return self._performAction('VerifyEmailAddress', params)
|
||||
|
||||
def deleteVerifiedEmailAddress(self, emailAddress):
|
||||
params = { 'EmailAddress': emailAddress }
|
||||
return self._performAction('DeleteVerifiedEmailAddress', params)
|
||||
|
||||
def getSendQuota(self):
|
||||
return self._performAction('GetSendQuota')
|
||||
|
||||
def getSendStatistics(self):
|
||||
return self._performAction('GetSendStatistics')
|
||||
|
||||
def listVerifiedEmailAddresses(self):
|
||||
return self._performAction('ListVerifiedEmailAddresses')
|
||||
|
||||
def sendEmail(self, source, toAddresses, message, replyToAddresses=None, returnPath=None, ccAddresses=None, bccAddresses=None):
|
||||
params = { 'Source': source }
|
||||
for objName, addresses in zip(["ToAddresses", "CcAddresses", "BccAddresses"], [toAddresses, ccAddresses, bccAddresses]):
|
||||
if addresses:
|
||||
if not isinstance(addresses, str) and getattr(addresses, '__iter__', False):
|
||||
for i, address in enumerate(addresses, 1):
|
||||
params['Destination.%s.member.%d' % (objName, i)] = address
|
||||
else:
|
||||
params['Destination.%s.member.1' % objName] = addresses
|
||||
if not returnPath:
|
||||
returnPath = source
|
||||
params['ReturnPath'] = returnPath
|
||||
params['Message.Subject.Charset'] = message.charset
|
||||
params['Message.Subject.Data'] = message.subject
|
||||
if message.bodyText:
|
||||
params['Message.Body.Text.Charset'] = message.charset
|
||||
params['Message.Body.Text.Data'] = message.bodyText
|
||||
if message.bodyHtml:
|
||||
params['Message.Body.Html.Charset'] = message.charset
|
||||
params['Message.Body.Html.Data'] = message.bodyHtml
|
||||
return self._performAction('SendEmail', params)
|
||||
|
||||
|
||||
|
||||
class EmailMessage:
|
||||
def __init__(self):
|
||||
self.charset = 'UTF-8'
|
||||
self.subject = None
|
||||
self.bodyHtml = None
|
||||
self.bodyText = None
|
||||
|
||||
|
||||
|
||||
class AmazonError(Exception):
|
||||
def __init__(self, errorType, code, message):
|
||||
self.errorType = errorType
|
||||
self.code = code
|
||||
self.message = message
|
||||
logging.info(message)
|
||||
|
||||
class AmazonAPIError(Exception):
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
|
||||
|
||||
class AmazonResult:
|
||||
def __init__(self, requestId):
|
||||
self.requestId = requestId
|
||||
|
||||
class AmazonSendEmailResult(AmazonResult):
|
||||
def __init__(self, requestId, messageId):
|
||||
self.requestId = requestId
|
||||
self.messageId = messageId
|
||||
|
||||
class AmazonSendQuota(AmazonResult):
|
||||
def __init__(self, requestId, max24HourSend, maxSendRate, sentLast24Hours):
|
||||
self.requestId = requestId
|
||||
self.max24HourSend = max24HourSend
|
||||
self.maxSendRate = maxSendRate
|
||||
self.sentLast24Hours = sentLast24Hours
|
||||
|
||||
class AmazonSendDataPoint:
|
||||
def __init__(self, bounces, complaints, deliveryAttempts, rejects, timestamp):
|
||||
self.bounces = bounces
|
||||
self.complaints = complaints
|
||||
self.deliveryAttempts = deliveryAttempts
|
||||
self.rejects = rejects
|
||||
self.timestamp = timestamp
|
||||
|
||||
class AmazonSendStatistics(AmazonResult):
|
||||
def __init__(self, requestId):
|
||||
self.requestId = requestId
|
||||
self.members = []
|
||||
|
||||
class AmazonVerifiedEmails(AmazonSendStatistics):
|
||||
pass
|
||||
|
||||
class AmazonResponseParser:
|
||||
class XmlResponse:
|
||||
def __init__(self, str):
|
||||
self._rootElement = XML(str)
|
||||
self._namespace = self._rootElement.tag[1:].split("}")[0]
|
||||
|
||||
def checkResponseName(self, name):
|
||||
if self._rootElement.tag == self._fixTag(self._namespace, name):
|
||||
return True
|
||||
else:
|
||||
raise AmazonAPIError('ErrorResponse is invalid.')
|
||||
|
||||
def checkActionName(self, actionName):
|
||||
if self._rootElement.tag == self._fixTag(self._namespace, ('%sResponse' % actionName)):
|
||||
return True
|
||||
else:
|
||||
raise AmazonAPIError('Response of action "%s" is invalid.' % actionName)
|
||||
|
||||
def getChild(self, *itemPath):
|
||||
node = self._findNode(self._rootElement, self._namespace, *itemPath)
|
||||
if node != None:
|
||||
return node
|
||||
else:
|
||||
raise AmazonAPIError('Node with the specified path was not found.')
|
||||
|
||||
def getChildText(self, *itemPath):
|
||||
node = self.getChild(*itemPath)
|
||||
return node.text
|
||||
|
||||
def _fixTag(self, namespace, tag):
|
||||
return '{%s}%s' % (namespace, tag)
|
||||
|
||||
def _findNode(self, rootElement, namespace, *args):
|
||||
match = '.'
|
||||
for s in args:
|
||||
match += '/{%s}%s' % (namespace, s)
|
||||
return rootElement.find(match)
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self._simpleResultActions = ['DeleteVerifiedEmailAddress', 'VerifyEmailAddress']
|
||||
|
||||
def _parseSimpleResult(self, actionName, xmlResponse):
|
||||
if xmlResponse.checkActionName(actionName):
|
||||
requestId = xmlResponse.getChildText('ResponseMetadata', 'RequestId')
|
||||
return AmazonResult(requestId)
|
||||
|
||||
def _parseSendQuota(self, actionName, xmlResponse):
|
||||
if xmlResponse.checkActionName(actionName):
|
||||
requestId = xmlResponse.getChildText('ResponseMetadata', 'RequestId')
|
||||
value = xmlResponse.getChildText('GetSendQuotaResult', 'Max24HourSend')
|
||||
max24HourSend = float(value)
|
||||
value = xmlResponse.getChildText('GetSendQuotaResult', 'MaxSendRate')
|
||||
maxSendRate = float(value)
|
||||
value = xmlResponse.getChildText('GetSendQuotaResult', 'SentLast24Hours')
|
||||
sentLast24Hours = float(value)
|
||||
return AmazonSendQuota(requestId, max24HourSend, maxSendRate, sentLast24Hours)
|
||||
|
||||
#def _parseSendStatistics(self, actionName, xmlResponse):
|
||||
# if xmlResponse.checkActionName(actionName):
|
||||
# requestId = xmlResponse.getChildText('ResponseMetadata', 'RequestId')
|
||||
|
||||
def _parseListVerifiedEmails(self, actionName, xmlResponse):
|
||||
if xmlResponse.checkActionName(actionName):
|
||||
requestId = xmlResponse.getChildText('ResponseMetadata', 'RequestId')
|
||||
node = xmlResponse.getChild('ListVerifiedEmailAddressesResult', 'VerifiedEmailAddresses')
|
||||
result = AmazonVerifiedEmails(requestId)
|
||||
for addr in node:
|
||||
result.members.append(addr.text)
|
||||
return result
|
||||
|
||||
def _parseSendEmail(self, actionName, xmlResponse):
|
||||
if xmlResponse.checkActionName(actionName):
|
||||
requestId = xmlResponse.getChildText('ResponseMetadata', 'RequestId')
|
||||
messageId = xmlResponse.getChildText('SendEmailResult', 'MessageId')
|
||||
return AmazonSendEmailResult(requestId, messageId)
|
||||
|
||||
def _raiseError(self, xmlResponse):
|
||||
if xmlResponse.checkResponseName('ErrorResponse'):
|
||||
errorType = xmlResponse.getChildText('Error', 'Type')
|
||||
code = xmlResponse.getChildText('Error', 'Code')
|
||||
message = xmlResponse.getChildText('Error', 'Message')
|
||||
raise AmazonError(errorType, code, message)
|
||||
|
||||
def parse(self, actionName, statusCode, reason, responseResult):
|
||||
xmlResponse = self.XmlResponse(responseResult)
|
||||
log.info('Response status code: %s, reason: %s', statusCode, reason)
|
||||
log.debug(responseResult)
|
||||
|
||||
result = None
|
||||
if statusCode != 200:
|
||||
self._raiseError(xmlResponse)
|
||||
else:
|
||||
if actionName in self._simpleResultActions:
|
||||
result = self._parseSimpleResult(actionName, xmlResponse)
|
||||
elif actionName in ['SendEmail']:
|
||||
result = self._parseSendEmail(actionName, xmlResponse)
|
||||
elif actionName == 'GetSendQuota':
|
||||
result = self._parseSendQuota(actionName, xmlResponse)
|
||||
#elif actionName == 'GetSendStatistics':
|
||||
# result = self._parseSendStatistics(actionName, xmlResponse)
|
||||
elif actionName == 'ListVerifiedEmailAddresses':
|
||||
result = self._parseListVerifiedEmails(actionName, xmlResponse)
|
||||
else:
|
||||
raise AmazonAPIError('Action %s is not supported. Please contact: vladimir@tagmask.com' % (actionName,))
|
||||
return result
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function
|
||||
|
||||
"""
|
||||
|
||||
get_image_size.py
|
||||
|
||||
@@ -2,8 +2,8 @@ import calendar
|
||||
import datetime
|
||||
import platform
|
||||
import time
|
||||
import urllib
|
||||
import urlparse
|
||||
#import urllib
|
||||
#import urlparse
|
||||
import warnings
|
||||
|
||||
import libraries.stripe
|
||||
|
||||
@@ -4,6 +4,8 @@ import textwrap
|
||||
import warnings
|
||||
import email
|
||||
|
||||
if 1/2 != 0: basestring=str
|
||||
|
||||
from libraries.stripe import error, util
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ import urllib
|
||||
import warnings
|
||||
import sys
|
||||
|
||||
if 1/2 != 0: basestring=str
|
||||
|
||||
from libraries.stripe import api_requestor, error, util, upload_api_base
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import string
|
||||
import sys
|
||||
import unittest2
|
||||
|
||||
if 1/2 != 0: basestring=str
|
||||
|
||||
from mock import patch, Mock
|
||||
|
||||
import libraries.stripe
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import sys
|
||||
import unittest2
|
||||
|
||||
if 1/2 != 0: basestring=str
|
||||
|
||||
from mock import Mock, patch
|
||||
|
||||
import libraries.stripe
|
||||
|
||||
@@ -4,6 +4,8 @@ import sys
|
||||
import unittest2
|
||||
import libraries.stripe
|
||||
|
||||
if 1/2 != 0: basestring=str
|
||||
|
||||
from mock import patch
|
||||
from libraries.stripe.test.helper import (StripeTestCase, NOW, DUMMY_CHARGE, DUMMY_CARD)
|
||||
|
||||
|
||||
@@ -10,13 +10,19 @@ try:
|
||||
# When cStringIO is available
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
try:
|
||||
import StringIO
|
||||
except:
|
||||
from io import StringIO #for Python 3
|
||||
|
||||
try:
|
||||
from urlparse import parse_qsl
|
||||
except ImportError:
|
||||
# Python < 2.6
|
||||
from cgi import parse_qsl
|
||||
try:
|
||||
from cgi import parse_qsl
|
||||
except:
|
||||
from urllib.parse import parse_qsl #for Python 3
|
||||
|
||||
try:
|
||||
import json
|
||||
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
# Stripe Python bindings
|
||||
# API docs at http://stripe.com/docs/api
|
||||
# Authors:
|
||||
# Patrick Collison <patrick@stripe.com>
|
||||
# Greg Brockman <gdb@stripe.com>
|
||||
# Andrew Metcalf <andrew@stripe.com>
|
||||
|
||||
# Configuration variables
|
||||
|
||||
api_key = None
|
||||
api_base = 'https://api.stripe.com'
|
||||
upload_api_base = 'https://uploads.stripe.com'
|
||||
api_version = None
|
||||
verify_ssl_certs = True
|
||||
default_http_client = None
|
||||
|
||||
# Resource
|
||||
from libraries.stripe.resource import ( # noqa
|
||||
Account,
|
||||
AlipayAccount,
|
||||
ApplicationFee,
|
||||
Balance,
|
||||
BalanceTransaction,
|
||||
BankAccount,
|
||||
BitcoinReceiver,
|
||||
BitcoinTransaction,
|
||||
Card,
|
||||
Charge,
|
||||
CountrySpec,
|
||||
Coupon,
|
||||
Customer,
|
||||
Dispute,
|
||||
Event,
|
||||
FileUpload,
|
||||
Invoice,
|
||||
InvoiceItem,
|
||||
Order,
|
||||
OrderReturn,
|
||||
Plan,
|
||||
Product,
|
||||
Recipient,
|
||||
Refund,
|
||||
SKU,
|
||||
Subscription,
|
||||
ThreeDSecure,
|
||||
Token,
|
||||
Transfer)
|
||||
|
||||
# Error imports. Note that we may want to move these out of the root
|
||||
# namespace in the future and you should prefer to access them via
|
||||
# the fully qualified `stripe.error` module.
|
||||
|
||||
from libraries.stripe.error import ( # noqa
|
||||
APIConnectionError,
|
||||
APIError,
|
||||
AuthenticationError,
|
||||
RateLimitError,
|
||||
CardError,
|
||||
InvalidRequestError,
|
||||
StripeError)
|
||||
|
||||
# DEPRECATED: These imports will be moved out of the root stripe namespace
|
||||
# in version 2.0
|
||||
|
||||
from libraries.stripe.version import VERSION # noqa
|
||||
from libraries.stripe.api_requestor import APIRequestor # noqa
|
||||
from libraries.stripe.resource import ( # noqa
|
||||
APIResource,
|
||||
CreateableAPIResource,
|
||||
DeletableAPIResource,
|
||||
ListObject,
|
||||
ListableAPIResource,
|
||||
SingletonAPIResource,
|
||||
StripeObject,
|
||||
StripeObjectEncoder,
|
||||
UpdateableAPIResource,
|
||||
convert_to_stripe_object)
|
||||
from libraries.stripe.util import json, logger # noqa
|
||||
Executable
+342
@@ -0,0 +1,342 @@
|
||||
import calendar
|
||||
import datetime
|
||||
import platform
|
||||
import time
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
import urllib.parse
|
||||
import warnings
|
||||
|
||||
import libraries.stripe
|
||||
from libraries.stripe import error, http_client, version, util
|
||||
from libraries.stripe.multipart_data_generator import MultipartDataGenerator
|
||||
|
||||
|
||||
def _encode_datetime(dttime):
|
||||
if dttime.tzinfo and dttime.tzinfo.utcoffset(dttime) is not None:
|
||||
utc_timestamp = calendar.timegm(dttime.utctimetuple())
|
||||
else:
|
||||
utc_timestamp = time.mktime(dttime.timetuple())
|
||||
|
||||
return int(utc_timestamp)
|
||||
|
||||
|
||||
def _encode_nested_dict(key, data, fmt='%s[%s]'):
|
||||
d = {}
|
||||
for subkey, subvalue in data.items():
|
||||
d[fmt % (key, subkey)] = subvalue
|
||||
return d
|
||||
|
||||
|
||||
def _api_encode(data):
|
||||
for key, value in data.items():
|
||||
key = util.utf8(key)
|
||||
if value is None:
|
||||
continue
|
||||
elif hasattr(value, 'stripe_id'):
|
||||
yield (key, value.stripe_id)
|
||||
elif isinstance(value, list) or isinstance(value, tuple):
|
||||
for sv in value:
|
||||
if isinstance(sv, dict):
|
||||
subdict = _encode_nested_dict(key, sv, fmt='%s[][%s]')
|
||||
for k, v in _api_encode(subdict):
|
||||
yield (k, v)
|
||||
else:
|
||||
yield ("%s[]" % (key,), util.utf8(sv))
|
||||
elif isinstance(value, dict):
|
||||
subdict = _encode_nested_dict(key, value)
|
||||
for subkey, subvalue in _api_encode(subdict):
|
||||
yield (subkey, subvalue)
|
||||
elif isinstance(value, datetime.datetime):
|
||||
yield (key, _encode_datetime(value))
|
||||
else:
|
||||
yield (key, util.utf8(value))
|
||||
|
||||
|
||||
def _build_api_url(url, query):
|
||||
scheme, netloc, path, base_query, fragment = urllib.parse.urlsplit(url)
|
||||
|
||||
if base_query:
|
||||
query = '%s&%s' % (base_query, query)
|
||||
|
||||
return urllib.parse.urlunsplit((scheme, netloc, path, query, fragment))
|
||||
|
||||
|
||||
class APIRequestor(object):
|
||||
|
||||
def __init__(self, key=None, client=None, api_base=None, account=None):
|
||||
self.api_base = api_base or libraries.stripe.api_base
|
||||
self.api_key = key
|
||||
self.stripe_account = account
|
||||
|
||||
from libraries.stripe import verify_ssl_certs as verify
|
||||
|
||||
self._client = client or libraries.stripe.default_http_client or \
|
||||
http_client.new_default_http_client(verify_ssl_certs=verify)
|
||||
|
||||
@classmethod
|
||||
def api_url(cls, url=''):
|
||||
warnings.warn(
|
||||
'The `api_url` class method of APIRequestor is '
|
||||
'deprecated and will be removed in version 2.0.'
|
||||
'If you need public access to this function, please email us '
|
||||
'at support@stripe.com.',
|
||||
DeprecationWarning)
|
||||
return '%s%s' % (stripe.api_base, url)
|
||||
|
||||
@classmethod
|
||||
def _deprecated_encode(cls, stk, key, value):
|
||||
warnings.warn(
|
||||
'The encode_* class methods of APIRequestor are deprecated and '
|
||||
'will be removed in version 2.0. '
|
||||
'If you need public access to this function, please email us '
|
||||
'at support@stripe.com.',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
stk.extend(_api_encode({key: value}))
|
||||
|
||||
@classmethod
|
||||
def encode_dict(cls, stk, key, value):
|
||||
cls._deprecated_encode(stk, key, value)
|
||||
|
||||
@classmethod
|
||||
def encode_list(cls, stk, key, value):
|
||||
cls._deprecated_encode(stk, key, value)
|
||||
|
||||
@classmethod
|
||||
def encode_datetime(cls, stk, key, value):
|
||||
cls._deprecated_encode(stk, key, value)
|
||||
|
||||
@classmethod
|
||||
def encode_none(cls, stk, key, value):
|
||||
cls._deprecated_encode(stk, key, value)
|
||||
|
||||
@classmethod
|
||||
def encode(cls, d):
|
||||
"""
|
||||
Internal: encode a string for url representation
|
||||
"""
|
||||
warnings.warn(
|
||||
'The `encode` class method of APIRequestor is deprecated and '
|
||||
'will be removed in version 2.0.'
|
||||
'If you need public access to this function, please email us '
|
||||
'at support@stripe.com.',
|
||||
DeprecationWarning)
|
||||
return urllib.parse.urlencode(list(_api_encode(d)))
|
||||
|
||||
@classmethod
|
||||
def build_url(cls, url, params):
|
||||
warnings.warn(
|
||||
'The `build_url` class method of APIRequestor is deprecated and '
|
||||
'will be removed in version 2.0.'
|
||||
'If you need public access to this function, please email us '
|
||||
'at support@stripe.com.',
|
||||
DeprecationWarning)
|
||||
return _build_api_url(url, cls.encode(params))
|
||||
|
||||
def request(self, method, url, params=None, headers=None):
|
||||
rbody, rcode, rheaders, my_api_key = self.request_raw(
|
||||
method.lower(), url, params, headers)
|
||||
resp = self.interpret_response(rbody, rcode, rheaders)
|
||||
return resp, my_api_key
|
||||
|
||||
def handle_api_error(self, rbody, rcode, resp, rheaders):
|
||||
try:
|
||||
err = resp['error']
|
||||
except (KeyError, TypeError):
|
||||
raise error.APIError(
|
||||
"Invalid response object from API: %r (HTTP response code "
|
||||
"was %d)" % (rbody, rcode),
|
||||
rbody, rcode, resp)
|
||||
|
||||
# Rate limits were previously coded as 400's with code 'rate_limit'
|
||||
if rcode == 429 or (rcode == 400 and err.get('code') == 'rate_limit'):
|
||||
raise error.RateLimitError(
|
||||
err.get('message'), rbody, rcode, resp, rheaders)
|
||||
elif rcode in [400, 404]:
|
||||
raise error.InvalidRequestError(
|
||||
err.get('message'), err.get('param'),
|
||||
rbody, rcode, resp, rheaders)
|
||||
elif rcode == 401:
|
||||
raise error.AuthenticationError(
|
||||
err.get('message'), rbody, rcode, resp,
|
||||
rheaders)
|
||||
elif rcode == 402:
|
||||
raise error.CardError(err.get('message'), err.get('param'),
|
||||
err.get('code'), rbody, rcode, resp,
|
||||
rheaders)
|
||||
else:
|
||||
raise error.APIError(err.get('message'), rbody, rcode, resp,
|
||||
rheaders)
|
||||
|
||||
def request_raw(self, method, url, params=None, supplied_headers=None):
|
||||
"""
|
||||
Mechanism for issuing an API call
|
||||
"""
|
||||
from libraries.stripe import api_version
|
||||
|
||||
if self.api_key:
|
||||
my_api_key = self.api_key
|
||||
else:
|
||||
from libraries.stripe import api_key
|
||||
my_api_key = api_key
|
||||
|
||||
if my_api_key is None:
|
||||
raise error.AuthenticationError(
|
||||
'No API key provided. (HINT: set your API key using '
|
||||
'"stripe.api_key = <API-KEY>"). You can generate API keys '
|
||||
'from the Stripe web interface. See https://stripe.com/api '
|
||||
'for details, or email support@stripe.com if you have any '
|
||||
'questions.')
|
||||
|
||||
abs_url = '%s%s' % (self.api_base, url)
|
||||
|
||||
encoded_params = urllib.parse.urlencode(list(_api_encode(params or {})))
|
||||
|
||||
if method == 'get' or method == 'delete':
|
||||
if params:
|
||||
abs_url = _build_api_url(abs_url, encoded_params)
|
||||
post_data = None
|
||||
elif method == 'post':
|
||||
if supplied_headers is not None and \
|
||||
supplied_headers.get("Content-Type") == \
|
||||
"multipart/form-data":
|
||||
generator = MultipartDataGenerator()
|
||||
generator.add_params(params or {})
|
||||
post_data = generator.get_post_data()
|
||||
supplied_headers["Content-Type"] = \
|
||||
"multipart/form-data; boundary=%s" % (generator.boundary,)
|
||||
else:
|
||||
post_data = encoded_params
|
||||
else:
|
||||
raise error.APIConnectionError(
|
||||
'Unrecognized HTTP method %r. This may indicate a bug in the '
|
||||
'Stripe bindings. Please contact support@stripe.com for '
|
||||
'assistance.' % (method,))
|
||||
|
||||
ua = {
|
||||
'bindings_version': version.VERSION,
|
||||
'lang': 'python',
|
||||
'publisher': 'stripe',
|
||||
'httplib': self._client.name,
|
||||
}
|
||||
for attr, func in [['lang_version', platform.python_version],
|
||||
['platform', platform.platform],
|
||||
['uname', lambda: ' '.join(platform.uname())]]:
|
||||
try:
|
||||
val = func()
|
||||
except Exception as e:
|
||||
val = "!! %s" % (e,)
|
||||
ua[attr] = val
|
||||
|
||||
headers = {
|
||||
'X-Stripe-Client-User-Agent': util.json.dumps(ua),
|
||||
'User-Agent': 'Stripe/v1 PythonBindings/%s' % (version.VERSION,),
|
||||
'Authorization': 'Bearer %s' % (my_api_key,)
|
||||
}
|
||||
|
||||
if self.stripe_account:
|
||||
headers['Stripe-Account'] = self.stripe_account
|
||||
|
||||
if method == 'post':
|
||||
headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
||||
|
||||
if api_version is not None:
|
||||
headers['Stripe-Version'] = api_version
|
||||
|
||||
if supplied_headers is not None:
|
||||
for key, value in list(supplied_headers.items()):
|
||||
headers[key] = value
|
||||
|
||||
rbody, rcode, rheaders = self._client.request(
|
||||
method, abs_url, headers, post_data)
|
||||
|
||||
util.logger.info('%s %s %d', method.upper(), abs_url, rcode)
|
||||
util.logger.debug(
|
||||
'API request to %s returned (response code, response body) of '
|
||||
'(%d, %r)',
|
||||
abs_url, rcode, rbody)
|
||||
return rbody, rcode, rheaders, my_api_key
|
||||
|
||||
def interpret_response(self, rbody, rcode, rheaders):
|
||||
try:
|
||||
if hasattr(rbody, 'decode'):
|
||||
rbody = rbody.decode('utf-8')
|
||||
resp = util.json.loads(rbody)
|
||||
except Exception:
|
||||
raise error.APIError(
|
||||
"Invalid response body from API: %s "
|
||||
"(HTTP response code was %d)" % (rbody, rcode),
|
||||
rbody, rcode, rheaders)
|
||||
if not (200 <= rcode < 300):
|
||||
self.handle_api_error(rbody, rcode, resp, rheaders)
|
||||
return resp
|
||||
|
||||
# Deprecated request handling. Will all be removed in 2.0
|
||||
def _deprecated_request(self, impl, method, url, headers, params):
|
||||
warnings.warn(
|
||||
'The *_request functions of APIRequestor are deprecated and '
|
||||
'will be removed in version 2.0. Please use the client classes '
|
||||
' in `stripe.http_client` instead',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
|
||||
method = method.lower()
|
||||
|
||||
if method == 'get' or method == 'delete':
|
||||
if params:
|
||||
url = self.build_url(url, params)
|
||||
post_data = None
|
||||
elif method == 'post':
|
||||
post_data = self.encode(params)
|
||||
else:
|
||||
raise error.APIConnectionError(
|
||||
'Unrecognized HTTP method %r. This may indicate a bug in the '
|
||||
'Stripe bindings. Please contact support@stripe.com for '
|
||||
'assistance.' % (method,))
|
||||
|
||||
client = impl(verify_ssl_certs=self._client._verify_ssl_certs)
|
||||
return client.request(method, url, headers, post_data)
|
||||
|
||||
def _deprecated_handle_error(self, impl, *args):
|
||||
warnings.warn(
|
||||
'The handle_*_error functions of APIRequestor are deprecated and '
|
||||
'will be removed in version 2.0. Please use the client classes '
|
||||
' in `stripe.http_client` instead',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
|
||||
client = impl(verify_ssl_certs=self._client._verify_ssl_certs)
|
||||
return client._handle_request_error(*args)
|
||||
|
||||
def requests_request(self, meth, abs_url, headers, params):
|
||||
from libraries.stripe.http_client import RequestsClient
|
||||
return self._deprecated_request(RequestsClient, meth, abs_url,
|
||||
headers, params)
|
||||
|
||||
def handle_requests_error(self, err):
|
||||
from libraries.stripe.http_client import RequestsClient
|
||||
return self._deprecated_handle_error(RequestsClient, err)
|
||||
|
||||
def pycurl_request(self, meth, abs_url, headers, params):
|
||||
from libraries.stripe.http_client import PycurlClient
|
||||
return self._deprecated_request(PycurlClient, meth, abs_url,
|
||||
headers, params)
|
||||
|
||||
def handle_pycurl_error(self, err):
|
||||
from libraries.stripe.http_client import PycurlClient
|
||||
return self._deprecated_handle_error(PycurlClient, err)
|
||||
|
||||
def urlfetch_request(self, meth, abs_url, headers, params):
|
||||
from libraries.stripe.http_client import UrlFetchClient
|
||||
return self._deprecated_request(UrlFetchClient, meth, abs_url,
|
||||
headers, params)
|
||||
|
||||
def handle_urlfetch_error(self, err, abs_url):
|
||||
from libraries.stripe.http_client import UrlFetchClient
|
||||
return self._deprecated_handle_error(UrlFetchClient, err, abs_url)
|
||||
|
||||
def urllib2_request(self, meth, abs_url, headers, params):
|
||||
from libraries.stripe.http_client import Urllib2Client
|
||||
return self._deprecated_request(Urllib2Client, meth, abs_url,
|
||||
headers, params)
|
||||
|
||||
def handle_urllib2_error(self, err, abs_url):
|
||||
from libraries.stripe.http_client import Urllib2Client
|
||||
return self._deprecated_handle_error(Urllib2Client, err)
|
||||
Executable
+3919
File diff suppressed because it is too large
Load Diff
Executable
+74
@@ -0,0 +1,74 @@
|
||||
# Exceptions
|
||||
import sys
|
||||
|
||||
|
||||
class StripeError(Exception):
|
||||
|
||||
def __init__(self, message=None, http_body=None, http_status=None,
|
||||
json_body=None, headers=None):
|
||||
super(StripeError, self).__init__(message)
|
||||
|
||||
if http_body and hasattr(http_body, 'decode'):
|
||||
try:
|
||||
http_body = http_body.decode('utf-8')
|
||||
except:
|
||||
http_body = ('<Could not decode body as utf-8. '
|
||||
'Please report to support@stripe.com>')
|
||||
|
||||
self._message = message
|
||||
self.http_body = http_body
|
||||
self.http_status = http_status
|
||||
self.json_body = json_body
|
||||
self.headers = headers or {}
|
||||
self.request_id = self.headers.get('request-id', None)
|
||||
|
||||
def __unicode__(self):
|
||||
if self.request_id is not None:
|
||||
msg = self._message or "<empty message>"
|
||||
return "Request {0}: {1}".format(self.request_id, msg)
|
||||
else:
|
||||
return self._message
|
||||
|
||||
if sys.version_info > (3, 0):
|
||||
def __str__(self):
|
||||
return self.__unicode__()
|
||||
else:
|
||||
def __str__(self):
|
||||
return str(self).encode('utf-8')
|
||||
|
||||
|
||||
class APIError(StripeError):
|
||||
pass
|
||||
|
||||
|
||||
class APIConnectionError(StripeError):
|
||||
pass
|
||||
|
||||
|
||||
class CardError(StripeError):
|
||||
|
||||
def __init__(self, message, param, code, http_body=None,
|
||||
http_status=None, json_body=None, headers=None):
|
||||
super(CardError, self).__init__(
|
||||
message, http_body, http_status, json_body,
|
||||
headers)
|
||||
self.param = param
|
||||
self.code = code
|
||||
|
||||
|
||||
class InvalidRequestError(StripeError):
|
||||
|
||||
def __init__(self, message, param, http_body=None,
|
||||
http_status=None, json_body=None, headers=None):
|
||||
super(InvalidRequestError, self).__init__(
|
||||
message, http_body, http_status, json_body,
|
||||
headers)
|
||||
self.param = param
|
||||
|
||||
|
||||
class AuthenticationError(StripeError):
|
||||
pass
|
||||
|
||||
|
||||
class RateLimitError(StripeError):
|
||||
pass
|
||||
Executable
+297
@@ -0,0 +1,297 @@
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
import warnings
|
||||
import email
|
||||
|
||||
if 1/2 != 0: str=str
|
||||
|
||||
from libraries.stripe import error, util
|
||||
|
||||
|
||||
# - Requests is the preferred HTTP library
|
||||
# - Google App Engine has urlfetch
|
||||
# - Use Pycurl if it's there (at least it verifies SSL certs)
|
||||
# - Fall back to urllib2 with a warning if needed
|
||||
try:
|
||||
import urllib.request, urllib.error, urllib.parse
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import pycurl
|
||||
except ImportError:
|
||||
pycurl = None
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
requests = None
|
||||
else:
|
||||
try:
|
||||
# Require version 0.8.8, but don't want to depend on distutils
|
||||
version = requests.__version__
|
||||
major, minor, patch = [int(i) for i in version.split('.')]
|
||||
except Exception:
|
||||
# Probably some new-fangled version, so it should support verify
|
||||
pass
|
||||
else:
|
||||
if (major, minor, patch) < (0, 8, 8):
|
||||
sys.stderr.write(
|
||||
'Warning: the Stripe library requires that your Python '
|
||||
'"requests" library be newer than version 0.8.8, but your '
|
||||
'"requests" library is version %s. Stripe will fall back to '
|
||||
'an alternate HTTP library so everything should work. We '
|
||||
'recommend upgrading your "requests" library. If you have any '
|
||||
'questions, please contact support@stripe.com. (HINT: running '
|
||||
'"pip install -U requests" should upgrade your requests '
|
||||
'library to the latest version.)' % (version,))
|
||||
requests = None
|
||||
|
||||
try:
|
||||
from google.appengine.api import urlfetch
|
||||
except ImportError:
|
||||
urlfetch = None
|
||||
|
||||
|
||||
def new_default_http_client(*args, **kwargs):
|
||||
if urlfetch:
|
||||
impl = UrlFetchClient
|
||||
elif requests:
|
||||
impl = RequestsClient
|
||||
elif pycurl:
|
||||
impl = PycurlClient
|
||||
else:
|
||||
impl = Urllib2Client
|
||||
warnings.warn(
|
||||
"Warning: the Stripe library is falling back to urllib2/urllib "
|
||||
"because neither requests nor pycurl are installed. "
|
||||
"urllib2's SSL implementation doesn't verify server "
|
||||
"certificates. For improved security, we suggest installing "
|
||||
"requests.")
|
||||
|
||||
return impl(*args, **kwargs)
|
||||
|
||||
|
||||
class HTTPClient(object):
|
||||
|
||||
def __init__(self, verify_ssl_certs=True):
|
||||
self._verify_ssl_certs = verify_ssl_certs
|
||||
|
||||
def request(self, method, url, headers, post_data=None):
|
||||
raise NotImplementedError(
|
||||
'HTTPClient subclasses must implement `request`')
|
||||
|
||||
|
||||
class RequestsClient(HTTPClient):
|
||||
name = 'requests'
|
||||
|
||||
def request(self, method, url, headers, post_data=None):
|
||||
kwargs = {}
|
||||
|
||||
if self._verify_ssl_certs:
|
||||
kwargs['verify'] = os.path.join(
|
||||
os.path.dirname(__file__), 'data/ca-certificates.crt')
|
||||
else:
|
||||
kwargs['verify'] = False
|
||||
|
||||
try:
|
||||
try:
|
||||
result = requests.request(method,
|
||||
url,
|
||||
headers=headers,
|
||||
data=post_data,
|
||||
timeout=80,
|
||||
**kwargs)
|
||||
except TypeError as e:
|
||||
raise TypeError(
|
||||
'Warning: It looks like your installed version of the '
|
||||
'"requests" library is not compatible with Stripe\'s '
|
||||
'usage thereof. (HINT: The most likely cause is that '
|
||||
'your "requests" library is out of date. You can fix '
|
||||
'that by running "pip install -U requests".) The '
|
||||
'underlying error was: %s' % (e,))
|
||||
|
||||
# This causes the content to actually be read, which could cause
|
||||
# e.g. a socket timeout. TODO: The other fetch methods probably
|
||||
# are susceptible to the same and should be updated.
|
||||
content = result.content
|
||||
status_code = result.status_code
|
||||
except Exception as e:
|
||||
# Would catch just requests.exceptions.RequestException, but can
|
||||
# also raise ValueError, RuntimeError, etc.
|
||||
self._handle_request_error(e)
|
||||
return content, status_code, result.headers
|
||||
|
||||
def _handle_request_error(self, e):
|
||||
if isinstance(e, requests.exceptions.RequestException):
|
||||
msg = ("Unexpected error communicating with Stripe. "
|
||||
"If this problem persists, let us know at "
|
||||
"support@stripe.com.")
|
||||
err = "%s: %s" % (type(e).__name__, str(e))
|
||||
else:
|
||||
msg = ("Unexpected error communicating with Stripe. "
|
||||
"It looks like there's probably a configuration "
|
||||
"issue locally. If this problem persists, let us "
|
||||
"know at support@stripe.com.")
|
||||
err = "A %s was raised" % (type(e).__name__,)
|
||||
if str(e):
|
||||
err += " with error message %s" % (str(e),)
|
||||
else:
|
||||
err += " with no error message"
|
||||
msg = textwrap.fill(msg) + "\n\n(Network error: %s)" % (err,)
|
||||
raise error.APIConnectionError(msg)
|
||||
|
||||
|
||||
class UrlFetchClient(HTTPClient):
|
||||
name = 'urlfetch'
|
||||
|
||||
def __init__(self, verify_ssl_certs=True, deadline=55):
|
||||
self._verify_ssl_certs = verify_ssl_certs
|
||||
# GAE requests time out after 60 seconds, so make sure to default
|
||||
# to 55 seconds to allow for a slow Stripe
|
||||
self._deadline = deadline
|
||||
|
||||
def request(self, method, url, headers, post_data=None):
|
||||
try:
|
||||
result = urlfetch.fetch(
|
||||
url=url,
|
||||
method=method,
|
||||
headers=headers,
|
||||
# Google App Engine doesn't let us specify our own cert bundle.
|
||||
# However, that's ok because the CA bundle they use recognizes
|
||||
# api.stripe.com.
|
||||
validate_certificate=self._verify_ssl_certs,
|
||||
deadline=self._deadline,
|
||||
payload=post_data
|
||||
)
|
||||
except urlfetch.Error as e:
|
||||
self._handle_request_error(e, url)
|
||||
|
||||
return result.content, result.status_code, result.headers
|
||||
|
||||
def _handle_request_error(self, e, url):
|
||||
if isinstance(e, urlfetch.InvalidURLError):
|
||||
msg = ("The Stripe library attempted to fetch an "
|
||||
"invalid URL (%r). This is likely due to a bug "
|
||||
"in the Stripe Python bindings. Please let us know "
|
||||
"at support@stripe.com." % (url,))
|
||||
elif isinstance(e, urlfetch.DownloadError):
|
||||
msg = "There was a problem retrieving data from Stripe."
|
||||
elif isinstance(e, urlfetch.ResponseTooLargeError):
|
||||
msg = ("There was a problem receiving all of your data from "
|
||||
"Stripe. This is likely due to a bug in Stripe. "
|
||||
"Please let us know at support@stripe.com.")
|
||||
else:
|
||||
msg = ("Unexpected error communicating with Stripe. If this "
|
||||
"problem persists, let us know at support@stripe.com.")
|
||||
|
||||
msg = textwrap.fill(msg) + "\n\n(Network error: " + str(e) + ")"
|
||||
raise error.APIConnectionError(msg)
|
||||
|
||||
|
||||
class PycurlClient(HTTPClient):
|
||||
name = 'pycurl'
|
||||
|
||||
def parse_headers(self, data):
|
||||
if '\r\n' not in data:
|
||||
return {}
|
||||
raw_headers = data.split('\r\n', 1)[1]
|
||||
headers = email.message_from_string(raw_headers)
|
||||
return dict((k.lower(), v) for k, v in dict(headers).items())
|
||||
|
||||
def request(self, method, url, headers, post_data=None):
|
||||
s = util.StringIO.StringIO()
|
||||
rheaders = util.StringIO.StringIO()
|
||||
curl = pycurl.Curl()
|
||||
|
||||
if method == 'get':
|
||||
curl.setopt(pycurl.HTTPGET, 1)
|
||||
elif method == 'post':
|
||||
curl.setopt(pycurl.POST, 1)
|
||||
curl.setopt(pycurl.POSTFIELDS, post_data)
|
||||
else:
|
||||
curl.setopt(pycurl.CUSTOMREQUEST, method.upper())
|
||||
|
||||
# pycurl doesn't like unicode URLs
|
||||
curl.setopt(pycurl.URL, util.utf8(url))
|
||||
|
||||
curl.setopt(pycurl.WRITEFUNCTION, s.write)
|
||||
curl.setopt(pycurl.HEADERFUNCTION, rheaders.write)
|
||||
curl.setopt(pycurl.NOSIGNAL, 1)
|
||||
curl.setopt(pycurl.CONNECTTIMEOUT, 30)
|
||||
curl.setopt(pycurl.TIMEOUT, 80)
|
||||
curl.setopt(pycurl.HTTPHEADER, ['%s: %s' % (k, v)
|
||||
for k, v in headers.items()])
|
||||
if self._verify_ssl_certs:
|
||||
curl.setopt(pycurl.CAINFO, os.path.join(
|
||||
os.path.dirname(__file__), 'data/ca-certificates.crt'))
|
||||
else:
|
||||
curl.setopt(pycurl.SSL_VERIFYHOST, False)
|
||||
|
||||
try:
|
||||
curl.perform()
|
||||
except pycurl.error as e:
|
||||
self._handle_request_error(e)
|
||||
rbody = s.getvalue()
|
||||
rcode = curl.getinfo(pycurl.RESPONSE_CODE)
|
||||
|
||||
return rbody, rcode, self.parse_headers(rheaders.getvalue())
|
||||
|
||||
def _handle_request_error(self, e):
|
||||
if e[0] in [pycurl.E_COULDNT_CONNECT,
|
||||
pycurl.E_COULDNT_RESOLVE_HOST,
|
||||
pycurl.E_OPERATION_TIMEOUTED]:
|
||||
msg = ("Could not connect to Stripe. Please check your "
|
||||
"internet connection and try again. If this problem "
|
||||
"persists, you should check Stripe's service status at "
|
||||
"https://twitter.com/stripestatus, or let us know at "
|
||||
"support@stripe.com.")
|
||||
elif (e[0] in [pycurl.E_SSL_CACERT,
|
||||
pycurl.E_SSL_PEER_CERTIFICATE]):
|
||||
msg = ("Could not verify Stripe's SSL certificate. Please make "
|
||||
"sure that your network is not intercepting certificates. "
|
||||
"If this problem persists, let us know at "
|
||||
"support@stripe.com.")
|
||||
else:
|
||||
msg = ("Unexpected error communicating with Stripe. If this "
|
||||
"problem persists, let us know at support@stripe.com.")
|
||||
|
||||
msg = textwrap.fill(msg) + "\n\n(Network error: " + e[1] + ")"
|
||||
raise error.APIConnectionError(msg)
|
||||
|
||||
|
||||
class Urllib2Client(HTTPClient):
|
||||
if sys.version_info >= (3, 0):
|
||||
name = 'urllib.request'
|
||||
else:
|
||||
name = 'urllib2'
|
||||
|
||||
def request(self, method, url, headers, post_data=None):
|
||||
if sys.version_info >= (3, 0) and isinstance(post_data, str):
|
||||
post_data = post_data.encode('utf-8')
|
||||
|
||||
req = urllib.request.Request(url, post_data, headers)
|
||||
|
||||
if method not in ('get', 'post'):
|
||||
req.get_method = lambda: method.upper()
|
||||
|
||||
try:
|
||||
response = urllib.request.urlopen(req)
|
||||
rbody = response.read()
|
||||
rcode = response.code
|
||||
headers = dict(response.info())
|
||||
except urllib.error.HTTPError as e:
|
||||
rcode = e.code
|
||||
rbody = e.read()
|
||||
headers = dict(e.info())
|
||||
except (urllib.error.URLError, ValueError) as e:
|
||||
self._handle_request_error(e)
|
||||
lh = dict((k.lower(), v) for k, v in dict(headers).items())
|
||||
return rbody, rcode, lh
|
||||
|
||||
def _handle_request_error(self, e):
|
||||
msg = ("Unexpected error communicating with Stripe. "
|
||||
"If this problem persists, let us know at support@stripe.com.")
|
||||
msg = textwrap.fill(msg) + "\n\n(Network error: " + str(e) + ")"
|
||||
raise error.APIConnectionError(msg)
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
import warnings
|
||||
|
||||
warnings.warn("The importers module is deprecated and will be removed in "
|
||||
"version 2.0. Check the `util` module for json imports",
|
||||
DeprecationWarning)
|
||||
|
||||
|
||||
def import_json():
|
||||
warnings.warn(
|
||||
"'import_json function is deprecated and will be removed in version "
|
||||
"2.0 of the Stripe python bindings. Please use"
|
||||
"`from importer import json` instead'",
|
||||
DeprecationWarning)
|
||||
|
||||
from libraries.stripe.util import json
|
||||
return json
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
import random
|
||||
import sys
|
||||
import io
|
||||
|
||||
|
||||
class MultipartDataGenerator(object):
|
||||
def __init__(self, chunk_size=1028):
|
||||
self.data = io.BytesIO()
|
||||
self.line_break = "\r\n"
|
||||
self.boundary = self._initialize_boundary()
|
||||
self.chunk_size = chunk_size
|
||||
|
||||
def add_params(self, params):
|
||||
for key, value in params.items():
|
||||
if value is None:
|
||||
continue
|
||||
|
||||
self._write(self.param_header())
|
||||
self._write(self.line_break)
|
||||
if hasattr(value, 'read'):
|
||||
self._write("Content-Disposition: form-data; name=\"")
|
||||
self._write(key)
|
||||
self._write("\"; filename=\"")
|
||||
self._write(value.name)
|
||||
self._write("\"")
|
||||
self._write(self.line_break)
|
||||
self._write("Content-Type: application/octet-stream")
|
||||
self._write(self.line_break)
|
||||
self._write(self.line_break)
|
||||
|
||||
self._write_file(value)
|
||||
else:
|
||||
self._write("Content-Disposition: form-data; name=\"")
|
||||
self._write(key)
|
||||
self._write("\"")
|
||||
self._write(self.line_break)
|
||||
self._write(self.line_break)
|
||||
self._write(value)
|
||||
|
||||
self._write(self.line_break)
|
||||
|
||||
def param_header(self):
|
||||
return "--%s" % self.boundary
|
||||
|
||||
def get_post_data(self):
|
||||
self._write("--%s--" % (self.boundary,))
|
||||
self._write(self.line_break)
|
||||
return self.data.getvalue()
|
||||
|
||||
def _write(self, value):
|
||||
if sys.version_info < (3,):
|
||||
binary_type = str
|
||||
text_type = str
|
||||
else:
|
||||
binary_type = bytes
|
||||
text_type = str
|
||||
|
||||
if isinstance(value, binary_type):
|
||||
array = bytearray(value)
|
||||
elif isinstance(value, text_type):
|
||||
array = bytearray(value, encoding='utf-8')
|
||||
else:
|
||||
raise TypeError("unexpected type: {value_type}"
|
||||
.format(value_type=type(value)))
|
||||
|
||||
self.data.write(array)
|
||||
|
||||
def _write_file(self, f):
|
||||
while True:
|
||||
file_contents = f.read(self.chunk_size)
|
||||
if not file_contents:
|
||||
break
|
||||
self._write(file_contents)
|
||||
|
||||
def _initialize_boundary(self):
|
||||
return random.randint(0, 2**63)
|
||||
Executable
+979
@@ -0,0 +1,979 @@
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
import warnings
|
||||
import sys
|
||||
|
||||
if 1/2 != 0: str=str
|
||||
|
||||
from libraries.stripe import api_requestor, error, util, upload_api_base
|
||||
|
||||
|
||||
def convert_to_stripe_object(resp, api_key, account):
|
||||
types = {
|
||||
'account': Account,
|
||||
'alipay_account': AlipayAccount,
|
||||
'application_fee': ApplicationFee,
|
||||
'bank_account': BankAccount,
|
||||
'bitcoin_receiver': BitcoinReceiver,
|
||||
'bitcoin_transaction': BitcoinTransaction,
|
||||
'card': Card,
|
||||
'charge': Charge,
|
||||
'country_spec': CountrySpec,
|
||||
'coupon': Coupon,
|
||||
'customer': Customer,
|
||||
'dispute': Dispute,
|
||||
'event': Event,
|
||||
'fee_refund': ApplicationFeeRefund,
|
||||
'file_upload': FileUpload,
|
||||
'invoice': Invoice,
|
||||
'invoiceitem': InvoiceItem,
|
||||
'list': ListObject,
|
||||
'plan': Plan,
|
||||
'recipient': Recipient,
|
||||
'refund': Refund,
|
||||
'subscription': Subscription,
|
||||
'three_d_secure': ThreeDSecure,
|
||||
'token': Token,
|
||||
'transfer': Transfer,
|
||||
'transfer_reversal': Reversal,
|
||||
'product': Product,
|
||||
'sku': SKU,
|
||||
'order': Order,
|
||||
'order_return': OrderReturn
|
||||
}
|
||||
|
||||
if isinstance(resp, list):
|
||||
return [convert_to_stripe_object(i, api_key, account) for i in resp]
|
||||
elif isinstance(resp, dict) and not isinstance(resp, StripeObject):
|
||||
resp = resp.copy()
|
||||
klass_name = resp.get('object')
|
||||
if isinstance(klass_name, str):
|
||||
klass = types.get(klass_name, StripeObject)
|
||||
else:
|
||||
klass = StripeObject
|
||||
return klass.construct_from(resp, api_key, stripe_account=account)
|
||||
else:
|
||||
return resp
|
||||
|
||||
|
||||
def populate_headers(idempotency_key):
|
||||
if idempotency_key is not None:
|
||||
return {"Idempotency-Key": idempotency_key}
|
||||
return None
|
||||
|
||||
|
||||
def _compute_diff(current, previous):
|
||||
if isinstance(current, dict):
|
||||
previous = previous or {}
|
||||
diff = current.copy()
|
||||
for key in set(previous.keys()) - set(diff.keys()):
|
||||
diff[key] = ""
|
||||
return diff
|
||||
return current if current is not None else ""
|
||||
|
||||
|
||||
def _serialize_list(array, previous):
|
||||
array = array or []
|
||||
previous = previous or []
|
||||
params = {}
|
||||
|
||||
for i, v in enumerate(array):
|
||||
previous_item = previous[i] if len(previous) > i else None
|
||||
if hasattr(v, 'serialize'):
|
||||
params[str(i)] = v.serialize(previous_item)
|
||||
else:
|
||||
params[str(i)] = _compute_diff(v, previous_item)
|
||||
|
||||
return params
|
||||
|
||||
|
||||
class StripeObject(dict):
|
||||
def __init__(self, id=None, api_key=None, stripe_account=None, **params):
|
||||
super(StripeObject, self).__init__()
|
||||
|
||||
self._unsaved_values = set()
|
||||
self._transient_values = set()
|
||||
|
||||
self._retrieve_params = params
|
||||
self._previous = None
|
||||
|
||||
object.__setattr__(self, 'api_key', api_key)
|
||||
object.__setattr__(self, 'stripe_account', stripe_account)
|
||||
|
||||
if id:
|
||||
self['id'] = id
|
||||
|
||||
def update(self, update_dict):
|
||||
for k in update_dict:
|
||||
self._unsaved_values.add(k)
|
||||
|
||||
return super(StripeObject, self).update(update_dict)
|
||||
|
||||
def __setattr__(self, k, v):
|
||||
if k[0] == '_' or k in self.__dict__:
|
||||
return super(StripeObject, self).__setattr__(k, v)
|
||||
else:
|
||||
self[k] = v
|
||||
|
||||
def __getattr__(self, k):
|
||||
if k[0] == '_':
|
||||
raise AttributeError(k)
|
||||
|
||||
try:
|
||||
return self[k]
|
||||
except KeyError as err:
|
||||
raise AttributeError(*err.args)
|
||||
|
||||
def __delattr__(self, k):
|
||||
if k[0] == '_' or k in self.__dict__:
|
||||
return super(StripeObject, self).__delattr__(k)
|
||||
else:
|
||||
del self[k]
|
||||
|
||||
def __setitem__(self, k, v):
|
||||
if v == "":
|
||||
raise ValueError(
|
||||
"You cannot set %s to an empty string. "
|
||||
"We interpret empty strings as None in requests."
|
||||
"You may set %s.%s = None to delete the property" % (
|
||||
k, str(self), k))
|
||||
|
||||
super(StripeObject, self).__setitem__(k, v)
|
||||
|
||||
# Allows for unpickling in Python 3.x
|
||||
if not hasattr(self, '_unsaved_values'):
|
||||
self._unsaved_values = set()
|
||||
|
||||
self._unsaved_values.add(k)
|
||||
|
||||
def __getitem__(self, k):
|
||||
try:
|
||||
return super(StripeObject, self).__getitem__(k)
|
||||
except KeyError as err:
|
||||
if k in self._transient_values:
|
||||
raise KeyError(
|
||||
"%r. HINT: The %r attribute was set in the past."
|
||||
"It was then wiped when refreshing the object with "
|
||||
"the result returned by Stripe's API, probably as a "
|
||||
"result of a save(). The attributes currently "
|
||||
"available on this object are: %s" %
|
||||
(k, k, ', '.join(list(self.keys()))))
|
||||
else:
|
||||
raise err
|
||||
|
||||
def __delitem__(self, k):
|
||||
super(StripeObject, self).__delitem__(k)
|
||||
|
||||
# Allows for unpickling in Python 3.x
|
||||
if hasattr(self, '_unsaved_values'):
|
||||
self._unsaved_values.remove(k)
|
||||
|
||||
@classmethod
|
||||
def construct_from(cls, values, key, stripe_account=None):
|
||||
instance = cls(values.get('id'), api_key=key,
|
||||
stripe_account=stripe_account)
|
||||
instance.refresh_from(values, api_key=key,
|
||||
stripe_account=stripe_account)
|
||||
return instance
|
||||
|
||||
def refresh_from(self, values, api_key=None, partial=False,
|
||||
stripe_account=None):
|
||||
self.api_key = api_key or getattr(values, 'api_key', None)
|
||||
self.stripe_account = \
|
||||
stripe_account or getattr(values, 'stripe_account', None)
|
||||
|
||||
# Wipe old state before setting new. This is useful for e.g.
|
||||
# updating a customer, where there is no persistent card
|
||||
# parameter. Mark those values which don't persist as transient
|
||||
if partial:
|
||||
self._unsaved_values = (self._unsaved_values - set(values))
|
||||
else:
|
||||
removed = set(self.keys()) - set(values)
|
||||
self._transient_values = self._transient_values | removed
|
||||
self._unsaved_values = set()
|
||||
self.clear()
|
||||
|
||||
self._transient_values = self._transient_values - set(values)
|
||||
|
||||
for k, v in values.items():
|
||||
super(StripeObject, self).__setitem__(
|
||||
k, convert_to_stripe_object(v, api_key, stripe_account))
|
||||
|
||||
self._previous = values
|
||||
|
||||
@classmethod
|
||||
def api_base(cls):
|
||||
return None
|
||||
|
||||
def request(self, method, url, params=None, headers=None):
|
||||
if params is None:
|
||||
params = self._retrieve_params
|
||||
requestor = api_requestor.APIRequestor(
|
||||
key=self.api_key, api_base=self.api_base(),
|
||||
account=self.stripe_account)
|
||||
response, api_key = requestor.request(method, url, params, headers)
|
||||
|
||||
return convert_to_stripe_object(response, api_key, self.stripe_account)
|
||||
|
||||
def __repr__(self):
|
||||
ident_parts = [type(self).__name__]
|
||||
|
||||
if isinstance(self.get('object'), str):
|
||||
ident_parts.append(self.get('object'))
|
||||
|
||||
if isinstance(self.get('id'), str):
|
||||
ident_parts.append('id=%s' % (self.get('id'),))
|
||||
|
||||
unicode_repr = '<%s at %s> JSON: %s' % (
|
||||
' '.join(ident_parts), hex(id(self)), str(self))
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
return unicode_repr.encode('utf-8')
|
||||
else:
|
||||
return unicode_repr
|
||||
|
||||
def __str__(self):
|
||||
return util.json.dumps(self, sort_keys=True, indent=2)
|
||||
|
||||
def to_dict(self):
|
||||
warnings.warn(
|
||||
'The `to_dict` method is deprecated and will be removed in '
|
||||
'version 2.0 of the Stripe bindings. The StripeObject is '
|
||||
'itself now a subclass of `dict`.',
|
||||
DeprecationWarning)
|
||||
|
||||
return dict(self)
|
||||
|
||||
@property
|
||||
def stripe_id(self):
|
||||
return self.id
|
||||
|
||||
def serialize(self, previous):
|
||||
params = {}
|
||||
unsaved_keys = self._unsaved_values or set()
|
||||
previous = previous or self._previous or {}
|
||||
|
||||
for k, v in list(self.items()):
|
||||
if k == 'id' or (isinstance(k, str) and k.startswith('_')):
|
||||
continue
|
||||
elif isinstance(v, APIResource):
|
||||
continue
|
||||
elif hasattr(v, 'serialize'):
|
||||
params[k] = v.serialize(previous.get(k, None))
|
||||
elif k in unsaved_keys:
|
||||
params[k] = _compute_diff(v, previous.get(k, None))
|
||||
elif k == 'additional_owners' and v is not None:
|
||||
params[k] = _serialize_list(v, previous.get(k, None))
|
||||
|
||||
return params
|
||||
|
||||
|
||||
class StripeObjectEncoder(util.json.JSONEncoder):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
warnings.warn(
|
||||
'`StripeObjectEncoder` is deprecated and will be removed in '
|
||||
'version 2.0 of the Stripe bindings. StripeObject is now a '
|
||||
'subclass of `dict` and is handled natively by the built-in '
|
||||
'json library.',
|
||||
DeprecationWarning)
|
||||
super(StripeObjectEncoder, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class APIResource(StripeObject):
|
||||
|
||||
@classmethod
|
||||
def retrieve(cls, id, api_key=None, **params):
|
||||
instance = cls(id, api_key, **params)
|
||||
instance.refresh()
|
||||
return instance
|
||||
|
||||
def refresh(self):
|
||||
self.refresh_from(self.request('get', self.instance_url()))
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def class_name(cls):
|
||||
if cls == APIResource:
|
||||
raise NotImplementedError(
|
||||
'APIResource is an abstract class. You should perform '
|
||||
'actions on its subclasses (e.g. Charge, Customer)')
|
||||
return str(urllib.parse.quote_plus(cls.__name__.lower()))
|
||||
|
||||
@classmethod
|
||||
def class_url(cls):
|
||||
cls_name = cls.class_name()
|
||||
return "/v1/%ss" % (cls_name,)
|
||||
|
||||
def instance_url(self):
|
||||
id = self.get('id')
|
||||
if not id:
|
||||
raise error.InvalidRequestError(
|
||||
'Could not determine which URL to request: %s instance '
|
||||
'has invalid ID: %r' % (type(self).__name__, id), 'id')
|
||||
id = util.utf8(id)
|
||||
base = self.class_url()
|
||||
extn = urllib.parse.quote_plus(id)
|
||||
return "%s/%s" % (base, extn)
|
||||
|
||||
|
||||
class ListObject(StripeObject):
|
||||
|
||||
def list(self, **params):
|
||||
return self.request('get', self['url'], params)
|
||||
|
||||
def all(self, **params):
|
||||
warnings.warn("The `all` method is deprecated and will"
|
||||
"be removed in future versions. Please use the "
|
||||
"`list` method instead",
|
||||
DeprecationWarning)
|
||||
return self.list(**params)
|
||||
|
||||
def auto_paging_iter(self):
|
||||
page = self
|
||||
params = dict(self._retrieve_params)
|
||||
|
||||
while True:
|
||||
item_id = None
|
||||
for item in page:
|
||||
item_id = item.get('id', None)
|
||||
yield item
|
||||
|
||||
if not getattr(page, 'has_more', False) or item_id is None:
|
||||
return
|
||||
|
||||
params['starting_after'] = item_id
|
||||
page = self.list(**params)
|
||||
|
||||
def create(self, idempotency_key=None, **params):
|
||||
headers = populate_headers(idempotency_key)
|
||||
return self.request('post', self['url'], params, headers)
|
||||
|
||||
def retrieve(self, id, **params):
|
||||
base = self.get('url')
|
||||
id = util.utf8(id)
|
||||
extn = urllib.parse.quote_plus(id)
|
||||
url = "%s/%s" % (base, extn)
|
||||
|
||||
return self.request('get', url, params)
|
||||
|
||||
def __iter__(self):
|
||||
return getattr(self, 'data', []).__iter__()
|
||||
|
||||
|
||||
class SingletonAPIResource(APIResource):
|
||||
|
||||
@classmethod
|
||||
def retrieve(cls, **params):
|
||||
return super(SingletonAPIResource, cls).retrieve(None, **params)
|
||||
|
||||
@classmethod
|
||||
def class_url(cls):
|
||||
cls_name = cls.class_name()
|
||||
return "/v1/%s" % (cls_name,)
|
||||
|
||||
def instance_url(self):
|
||||
return self.class_url()
|
||||
|
||||
|
||||
# Classes of API operations
|
||||
|
||||
|
||||
class ListableAPIResource(APIResource):
|
||||
|
||||
@classmethod
|
||||
def all(cls, *args, **params):
|
||||
warnings.warn("The `all` class method is deprecated and will"
|
||||
"be removed in future versions. Please use the "
|
||||
"`list` class method instead",
|
||||
DeprecationWarning)
|
||||
return cls.list(*args, **params)
|
||||
|
||||
@classmethod
|
||||
def auto_paging_iter(self, *args, **params):
|
||||
return self.list(*args, **params).auto_paging_iter()
|
||||
|
||||
@classmethod
|
||||
def list(cls, api_key=None, idempotency_key=None,
|
||||
stripe_account=None, **params):
|
||||
requestor = api_requestor.APIRequestor(api_key,
|
||||
api_base=cls.api_base(),
|
||||
account=stripe_account)
|
||||
url = cls.class_url()
|
||||
response, api_key = requestor.request('get', url, params)
|
||||
stripe_object = convert_to_stripe_object(response, api_key,
|
||||
stripe_account)
|
||||
stripe_object._retrieve_params = params
|
||||
return stripe_object
|
||||
|
||||
|
||||
class CreateableAPIResource(APIResource):
|
||||
|
||||
@classmethod
|
||||
def create(cls, api_key=None, idempotency_key=None,
|
||||
stripe_account=None, **params):
|
||||
requestor = api_requestor.APIRequestor(api_key, account=stripe_account)
|
||||
url = cls.class_url()
|
||||
headers = populate_headers(idempotency_key)
|
||||
response, api_key = requestor.request('post', url, params, headers)
|
||||
return convert_to_stripe_object(response, api_key, stripe_account)
|
||||
|
||||
|
||||
class UpdateableAPIResource(APIResource):
|
||||
|
||||
@classmethod
|
||||
def _modify(cls, url, api_key=None, idempotency_key=None,
|
||||
stripe_account=None, **params):
|
||||
requestor = api_requestor.APIRequestor(api_key, account=stripe_account)
|
||||
headers = populate_headers(idempotency_key)
|
||||
response, api_key = requestor.request('post', url, params, headers)
|
||||
return convert_to_stripe_object(response, api_key, stripe_account)
|
||||
|
||||
@classmethod
|
||||
def modify(cls, sid, **params):
|
||||
url = "%s/%s" % (cls.class_url(), urllib.parse.quote_plus(util.utf8(sid)))
|
||||
return cls._modify(url, **params)
|
||||
|
||||
def save(self, idempotency_key=None):
|
||||
updated_params = self.serialize(None)
|
||||
headers = populate_headers(idempotency_key)
|
||||
|
||||
if updated_params:
|
||||
self.refresh_from(self.request('post', self.instance_url(),
|
||||
updated_params, headers))
|
||||
else:
|
||||
util.logger.debug("Trying to save already saved object %r", self)
|
||||
return self
|
||||
|
||||
|
||||
class DeletableAPIResource(APIResource):
|
||||
|
||||
def delete(self, **params):
|
||||
self.refresh_from(self.request('delete', self.instance_url(), params))
|
||||
return self
|
||||
|
||||
|
||||
# API objects
|
||||
class Account(CreateableAPIResource, ListableAPIResource,
|
||||
UpdateableAPIResource, DeletableAPIResource):
|
||||
@classmethod
|
||||
def retrieve(cls, id=None, api_key=None, **params):
|
||||
instance = cls(id, api_key, **params)
|
||||
instance.refresh()
|
||||
return instance
|
||||
|
||||
@classmethod
|
||||
def modify(cls, id=None, **params):
|
||||
return cls._modify(cls._build_instance_url(id), **params)
|
||||
|
||||
@classmethod
|
||||
def _build_instance_url(cls, sid):
|
||||
if not sid:
|
||||
return "/v1/account"
|
||||
sid = util.utf8(sid)
|
||||
base = cls.class_url()
|
||||
extn = urllib.parse.quote_plus(sid)
|
||||
return "%s/%s" % (base, extn)
|
||||
|
||||
def instance_url(self):
|
||||
return self._build_instance_url(self.get('id'))
|
||||
|
||||
def reject(self, reason=None, idempotency_key=None):
|
||||
url = self.instance_url() + '/reject'
|
||||
headers = populate_headers(idempotency_key)
|
||||
if reason:
|
||||
params = {"reason": reason}
|
||||
else:
|
||||
params = {}
|
||||
self.refresh_from(
|
||||
self.request('post', url, params, headers)
|
||||
)
|
||||
return self
|
||||
|
||||
|
||||
class AlipayAccount(UpdateableAPIResource, DeletableAPIResource):
|
||||
|
||||
@classmethod
|
||||
def _build_instance_url(cls, customer, sid):
|
||||
token = util.utf8(sid)
|
||||
extn = urllib.parse.quote_plus(token)
|
||||
customer = util.utf8(customer)
|
||||
|
||||
base = Customer.class_url()
|
||||
owner_extn = urllib.parse.quote_plus(customer)
|
||||
|
||||
return "%s/%s/sources/%s" % (base, owner_extn, extn)
|
||||
|
||||
def instance_url(self):
|
||||
return self._build_instance_url(self.customer, self.id)
|
||||
|
||||
@classmethod
|
||||
def modify(cls, customer, id, **params):
|
||||
url = cls._build_instance_url(customer, id)
|
||||
return cls._modify(url, **params)
|
||||
|
||||
@classmethod
|
||||
def retrieve(cls, id, api_key=None, stripe_account=None, **params):
|
||||
raise NotImplementedError(
|
||||
"Can't retrieve an Alipay account without a customer ID. "
|
||||
"Use customer.sources.retrieve('alipay_account_id') instead.")
|
||||
|
||||
|
||||
class Balance(SingletonAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class BalanceTransaction(ListableAPIResource):
|
||||
|
||||
@classmethod
|
||||
def class_url(cls):
|
||||
return '/v1/balance/history'
|
||||
|
||||
|
||||
class Card(UpdateableAPIResource, DeletableAPIResource):
|
||||
|
||||
def instance_url(self):
|
||||
token = util.utf8(self.id)
|
||||
extn = urllib.parse.quote_plus(token)
|
||||
if (hasattr(self, 'customer')):
|
||||
customer = util.utf8(self.customer)
|
||||
|
||||
base = Customer.class_url()
|
||||
owner_extn = urllib.parse.quote_plus(customer)
|
||||
class_base = "sources"
|
||||
|
||||
elif (hasattr(self, 'recipient')):
|
||||
recipient = util.utf8(self.recipient)
|
||||
|
||||
base = Recipient.class_url()
|
||||
owner_extn = urllib.parse.quote_plus(recipient)
|
||||
class_base = "cards"
|
||||
|
||||
elif (hasattr(self, 'account')):
|
||||
account = util.utf8(self.account)
|
||||
|
||||
base = Account.class_url()
|
||||
owner_extn = urllib.parse.quote_plus(account)
|
||||
class_base = "external_accounts"
|
||||
|
||||
else:
|
||||
raise error.InvalidRequestError(
|
||||
"Could not determine whether card_id %s is "
|
||||
"attached to a customer, recipient, or "
|
||||
"account." % token, 'id')
|
||||
|
||||
return "%s/%s/%s/%s" % (base, owner_extn, class_base, extn)
|
||||
|
||||
@classmethod
|
||||
def modify(cls, sid, **params):
|
||||
raise NotImplementedError(
|
||||
"Can't modify a card without a customer, recipient or account "
|
||||
"ID. Call save on customer.sources.retrieve('card_id'), "
|
||||
"recipient.cards.retrieve('card_id'), or "
|
||||
"account.external_accounts.retrieve('card_id') instead.")
|
||||
|
||||
@classmethod
|
||||
def retrieve(cls, id, api_key=None, stripe_account=None, **params):
|
||||
raise NotImplementedError(
|
||||
"Can't retrieve a card without a customer, recipient or account "
|
||||
"ID. Use customer.sources.retrieve('card_id'), "
|
||||
"recipient.cards.retrieve('card_id'), or "
|
||||
"account.external_accounts.retrieve('card_id') instead.")
|
||||
|
||||
|
||||
class VerifyMixin(object):
|
||||
|
||||
def verify(self, idempotency_key=None, **params):
|
||||
url = self.instance_url() + '/verify'
|
||||
headers = populate_headers(idempotency_key)
|
||||
self.refresh_from(self.request('post', url, params, headers))
|
||||
return self
|
||||
|
||||
|
||||
class BankAccount(UpdateableAPIResource, DeletableAPIResource, VerifyMixin):
|
||||
|
||||
def instance_url(self):
|
||||
token = util.utf8(self.id)
|
||||
extn = urllib.parse.quote_plus(token)
|
||||
if (hasattr(self, 'customer')):
|
||||
customer = util.utf8(self.customer)
|
||||
|
||||
base = Customer.class_url()
|
||||
owner_extn = urllib.parse.quote_plus(customer)
|
||||
class_base = "sources"
|
||||
|
||||
elif (hasattr(self, 'account')):
|
||||
account = util.utf8(self.account)
|
||||
|
||||
base = Account.class_url()
|
||||
owner_extn = urllib.parse.quote_plus(account)
|
||||
class_base = "external_accounts"
|
||||
|
||||
else:
|
||||
raise error.InvalidRequestError(
|
||||
"Could not determine whether bank_account_id %s is "
|
||||
"attached to a customer or an account." % token, 'id')
|
||||
|
||||
return "%s/%s/%s/%s" % (base, owner_extn, class_base, extn)
|
||||
|
||||
@classmethod
|
||||
def modify(cls, sid, **params):
|
||||
raise NotImplementedError(
|
||||
"Can't modify a bank account without a customer or account ID. "
|
||||
"Call save on customer.sources.retrieve('bank_account_id') or "
|
||||
"account.external_accounts.retrieve('bank_account_id') instead.")
|
||||
|
||||
@classmethod
|
||||
def retrieve(cls, id, api_key=None, stripe_account=None, **params):
|
||||
raise NotImplementedError(
|
||||
"Can't retrieve a bank account without a customer or account ID. "
|
||||
"Use customer.sources.retrieve('bank_account_id') or "
|
||||
"account.external_accounts.retrieve('bank_account_id') instead.")
|
||||
|
||||
|
||||
class Charge(CreateableAPIResource, ListableAPIResource,
|
||||
UpdateableAPIResource):
|
||||
|
||||
def refund(self, idempotency_key=None, **params):
|
||||
url = self.instance_url() + '/refund'
|
||||
headers = populate_headers(idempotency_key)
|
||||
self.refresh_from(self.request('post', url, params, headers))
|
||||
return self
|
||||
|
||||
def capture(self, idempotency_key=None, **params):
|
||||
url = self.instance_url() + '/capture'
|
||||
headers = populate_headers(idempotency_key)
|
||||
self.refresh_from(self.request('post', url, params, headers))
|
||||
return self
|
||||
|
||||
def update_dispute(self, idempotency_key=None, **params):
|
||||
requestor = api_requestor.APIRequestor(self.api_key,
|
||||
account=self.stripe_account)
|
||||
url = self.instance_url() + '/dispute'
|
||||
headers = populate_headers(idempotency_key)
|
||||
response, api_key = requestor.request('post', url, params, headers)
|
||||
self.refresh_from({'dispute': response}, api_key, True)
|
||||
return self.dispute
|
||||
|
||||
def close_dispute(self, idempotency_key=None):
|
||||
requestor = api_requestor.APIRequestor(self.api_key,
|
||||
account=self.stripe_account)
|
||||
url = self.instance_url() + '/dispute/close'
|
||||
headers = populate_headers(idempotency_key)
|
||||
response, api_key = requestor.request('post', url, {}, headers)
|
||||
self.refresh_from({'dispute': response}, api_key, True)
|
||||
return self.dispute
|
||||
|
||||
def mark_as_fraudulent(self, idempotency_key=None):
|
||||
params = {
|
||||
'fraud_details': {'user_report': 'fraudulent'}
|
||||
}
|
||||
url = self.instance_url()
|
||||
headers = populate_headers(idempotency_key)
|
||||
self.refresh_from(self.request('post', url, params, headers))
|
||||
return self
|
||||
|
||||
def mark_as_safe(self, idempotency_key=None):
|
||||
params = {
|
||||
'fraud_details': {'user_report': 'safe'}
|
||||
}
|
||||
url = self.instance_url()
|
||||
headers = populate_headers(idempotency_key)
|
||||
self.refresh_from(self.request('post', url, params, headers))
|
||||
return self
|
||||
|
||||
|
||||
class Dispute(CreateableAPIResource, ListableAPIResource,
|
||||
UpdateableAPIResource):
|
||||
|
||||
def close(self, idempotency_key=None):
|
||||
url = self.instance_url() + '/close'
|
||||
headers = populate_headers(idempotency_key)
|
||||
self.refresh_from(self.request('post', url, {}, headers))
|
||||
return self
|
||||
|
||||
|
||||
class Customer(CreateableAPIResource, UpdateableAPIResource,
|
||||
ListableAPIResource, DeletableAPIResource):
|
||||
|
||||
def add_invoice_item(self, idempotency_key=None, **params):
|
||||
params['customer'] = self.id
|
||||
ii = InvoiceItem.create(self.api_key,
|
||||
idempotency_key=idempotency_key, **params)
|
||||
return ii
|
||||
|
||||
def invoices(self, **params):
|
||||
params['customer'] = self.id
|
||||
invoices = Invoice.list(self.api_key, **params)
|
||||
return invoices
|
||||
|
||||
def invoice_items(self, **params):
|
||||
params['customer'] = self.id
|
||||
iis = InvoiceItem.list(self.api_key, **params)
|
||||
return iis
|
||||
|
||||
def charges(self, **params):
|
||||
params['customer'] = self.id
|
||||
charges = Charge.list(self.api_key, **params)
|
||||
return charges
|
||||
|
||||
def update_subscription(self, idempotency_key=None, **params):
|
||||
warnings.warn(
|
||||
'The `update_subscription` method is deprecated. Instead, use the '
|
||||
'`subscriptions` resource on the customer object to update a '
|
||||
'subscription',
|
||||
DeprecationWarning)
|
||||
requestor = api_requestor.APIRequestor(self.api_key,
|
||||
account=self.stripe_account)
|
||||
url = self.instance_url() + '/subscription'
|
||||
headers = populate_headers(idempotency_key)
|
||||
response, api_key = requestor.request('post', url, params, headers)
|
||||
self.refresh_from({'subscription': response}, api_key, True)
|
||||
return self.subscription
|
||||
|
||||
def cancel_subscription(self, idempotency_key=None, **params):
|
||||
warnings.warn(
|
||||
'The `cancel_subscription` method is deprecated. Instead, use the '
|
||||
'`subscriptions` resource on the customer object to cancel a '
|
||||
'subscription',
|
||||
DeprecationWarning)
|
||||
requestor = api_requestor.APIRequestor(self.api_key,
|
||||
account=self.stripe_account)
|
||||
url = self.instance_url() + '/subscription'
|
||||
headers = populate_headers(idempotency_key)
|
||||
response, api_key = requestor.request('delete', url, params, headers)
|
||||
self.refresh_from({'subscription': response}, api_key, True)
|
||||
return self.subscription
|
||||
|
||||
def delete_discount(self, **params):
|
||||
requestor = api_requestor.APIRequestor(self.api_key,
|
||||
account=self.stripe_account)
|
||||
url = self.instance_url() + '/discount'
|
||||
_, api_key = requestor.request('delete', url)
|
||||
self.refresh_from({'discount': None}, api_key, True)
|
||||
|
||||
|
||||
class Invoice(CreateableAPIResource, ListableAPIResource,
|
||||
UpdateableAPIResource):
|
||||
|
||||
def pay(self, idempotency_key=None):
|
||||
headers = populate_headers(idempotency_key)
|
||||
return self.request('post', self.instance_url() + '/pay', {}, headers)
|
||||
|
||||
@classmethod
|
||||
def upcoming(cls, api_key=None, stripe_account=None, **params):
|
||||
requestor = api_requestor.APIRequestor(api_key,
|
||||
account=stripe_account)
|
||||
url = cls.class_url() + '/upcoming'
|
||||
response, api_key = requestor.request('get', url, params)
|
||||
return convert_to_stripe_object(response, api_key, stripe_account)
|
||||
|
||||
|
||||
class InvoiceItem(CreateableAPIResource, UpdateableAPIResource,
|
||||
ListableAPIResource, DeletableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class Plan(CreateableAPIResource, DeletableAPIResource,
|
||||
UpdateableAPIResource, ListableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class Subscription(CreateableAPIResource, DeletableAPIResource,
|
||||
UpdateableAPIResource, ListableAPIResource):
|
||||
|
||||
def delete_discount(self, **params):
|
||||
requestor = api_requestor.APIRequestor(self.api_key,
|
||||
account=self.stripe_account)
|
||||
url = self.instance_url() + '/discount'
|
||||
_, api_key = requestor.request('delete', url)
|
||||
self.refresh_from({'discount': None}, api_key, True)
|
||||
|
||||
|
||||
class Refund(CreateableAPIResource, ListableAPIResource,
|
||||
UpdateableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class Token(CreateableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class Coupon(CreateableAPIResource, UpdateableAPIResource,
|
||||
DeletableAPIResource, ListableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class Event(ListableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class Transfer(CreateableAPIResource, UpdateableAPIResource,
|
||||
ListableAPIResource):
|
||||
|
||||
def cancel(self):
|
||||
self.refresh_from(self.request('post',
|
||||
self.instance_url() + '/cancel'))
|
||||
|
||||
|
||||
class Reversal(UpdateableAPIResource):
|
||||
|
||||
def instance_url(self):
|
||||
token = util.utf8(self.id)
|
||||
transfer = util.utf8(self.transfer)
|
||||
base = Transfer.class_url()
|
||||
cust_extn = urllib.parse.quote_plus(transfer)
|
||||
extn = urllib.parse.quote_plus(token)
|
||||
return "%s/%s/reversals/%s" % (base, cust_extn, extn)
|
||||
|
||||
@classmethod
|
||||
def modify(cls, sid, **params):
|
||||
raise NotImplementedError(
|
||||
"Can't modify a reversal without a transfer"
|
||||
"ID. Call save on transfer.reversals.retrieve('reversal_id')")
|
||||
|
||||
@classmethod
|
||||
def retrieve(cls, id, api_key=None, **params):
|
||||
raise NotImplementedError(
|
||||
"Can't retrieve a reversal without a transfer"
|
||||
"ID. Use transfer.reversals.retrieve('reversal_id')")
|
||||
|
||||
|
||||
class Recipient(CreateableAPIResource, UpdateableAPIResource,
|
||||
ListableAPIResource, DeletableAPIResource):
|
||||
|
||||
def transfers(self, **params):
|
||||
params['recipient'] = self.id
|
||||
transfers = Transfer.list(self.api_key, **params)
|
||||
return transfers
|
||||
|
||||
|
||||
class FileUpload(ListableAPIResource):
|
||||
@classmethod
|
||||
def api_base(cls):
|
||||
return upload_api_base
|
||||
|
||||
@classmethod
|
||||
def class_name(cls):
|
||||
return 'file'
|
||||
|
||||
@classmethod
|
||||
def create(cls, api_key=None, stripe_account=None, **params):
|
||||
requestor = api_requestor.APIRequestor(
|
||||
api_key, api_base=cls.api_base(), account=stripe_account)
|
||||
url = cls.class_url()
|
||||
supplied_headers = {
|
||||
"Content-Type": "multipart/form-data"
|
||||
}
|
||||
response, api_key = requestor.request(
|
||||
'post', url, params=params, headers=supplied_headers)
|
||||
return convert_to_stripe_object(response, api_key, stripe_account)
|
||||
|
||||
|
||||
class ApplicationFee(ListableAPIResource):
|
||||
@classmethod
|
||||
def class_name(cls):
|
||||
return 'application_fee'
|
||||
|
||||
def refund(self, idempotency_key=None, **params):
|
||||
headers = populate_headers(idempotency_key)
|
||||
url = self.instance_url() + '/refund'
|
||||
self.refresh_from(self.request('post', url, params, headers))
|
||||
return self
|
||||
|
||||
|
||||
class ApplicationFeeRefund(UpdateableAPIResource):
|
||||
|
||||
@classmethod
|
||||
def _build_instance_url(cls, fee, sid):
|
||||
fee = util.utf8(fee)
|
||||
sid = util.utf8(sid)
|
||||
base = ApplicationFee.class_url()
|
||||
cust_extn = urllib.parse.quote_plus(fee)
|
||||
extn = urllib.parse.quote_plus(sid)
|
||||
return "%s/%s/refunds/%s" % (base, cust_extn, extn)
|
||||
|
||||
@classmethod
|
||||
def modify(cls, fee, sid, **params):
|
||||
url = cls._build_instance_url(fee, sid)
|
||||
return cls._modify(url, **params)
|
||||
|
||||
def instance_url(self):
|
||||
return self._build_instance_url(self.fee, self.id)
|
||||
|
||||
@classmethod
|
||||
def retrieve(cls, id, api_key=None, **params):
|
||||
raise NotImplementedError(
|
||||
"Can't retrieve a refund without an application fee ID. "
|
||||
"Use application_fee.refunds.retrieve('refund_id') instead.")
|
||||
|
||||
|
||||
class BitcoinReceiver(CreateableAPIResource, UpdateableAPIResource,
|
||||
DeletableAPIResource, ListableAPIResource):
|
||||
|
||||
def instance_url(self):
|
||||
token = util.utf8(self.id)
|
||||
extn = urllib.parse.quote_plus(token)
|
||||
|
||||
if (hasattr(self, 'customer')):
|
||||
customer = util.utf8(self.customer)
|
||||
base = Customer.class_url()
|
||||
cust_extn = urllib.parse.quote_plus(customer)
|
||||
return "%s/%s/sources/%s" % (base, cust_extn, extn)
|
||||
else:
|
||||
base = BitcoinReceiver.class_url()
|
||||
return "%s/%s" % (base, extn)
|
||||
|
||||
@classmethod
|
||||
def class_url(cls):
|
||||
return '/v1/bitcoin/receivers'
|
||||
|
||||
|
||||
class BitcoinTransaction(StripeObject):
|
||||
pass
|
||||
|
||||
|
||||
class Product(CreateableAPIResource, UpdateableAPIResource,
|
||||
ListableAPIResource, DeletableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class SKU(CreateableAPIResource, UpdateableAPIResource,
|
||||
ListableAPIResource, DeletableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class Order(CreateableAPIResource, UpdateableAPIResource,
|
||||
ListableAPIResource):
|
||||
def pay(self, idempotency_key=None, **params):
|
||||
headers = populate_headers(idempotency_key)
|
||||
return self.request(
|
||||
'post', self.instance_url() + '/pay', params, headers)
|
||||
|
||||
def return_order(self, idempotency_key=None, **params):
|
||||
headers = populate_headers(idempotency_key)
|
||||
return self.request(
|
||||
'post', self.instance_url() + '/returns', params, headers)
|
||||
|
||||
|
||||
class OrderReturn(ListableAPIResource):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def class_url(cls):
|
||||
return '/v1/order_returns'
|
||||
|
||||
|
||||
class CountrySpec(ListableAPIResource):
|
||||
@classmethod
|
||||
def class_name(cls):
|
||||
return 'country_spec'
|
||||
|
||||
|
||||
class ThreeDSecure(CreateableAPIResource):
|
||||
@classmethod
|
||||
def class_url(cls):
|
||||
return '/v1/3d_secure'
|
||||
|
||||
@classmethod
|
||||
def retrieve(cls, id, api_key=None, stripe_account=None, **params):
|
||||
raise NotImplementedError("Can't retrieve 3D Secure objects.")
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
import os
|
||||
import unittest2
|
||||
|
||||
|
||||
def all():
|
||||
path = os.path.dirname(os.path.realpath(__file__))
|
||||
return unittest2.defaultTestLoader.discover(path)
|
||||
|
||||
|
||||
def resources():
|
||||
path = os.path.dirname(os.path.realpath(__file__))
|
||||
return unittest2.defaultTestLoader.discover(
|
||||
os.path.join(path, "resources"))
|
||||
Executable
+240
@@ -0,0 +1,240 @@
|
||||
import datetime
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import unittest2
|
||||
|
||||
if 1/2 != 0: str=str
|
||||
|
||||
from mock import patch, Mock
|
||||
|
||||
import libraries.stripe
|
||||
|
||||
NOW = datetime.datetime.now()
|
||||
|
||||
DUMMY_CARD = {
|
||||
'number': '4242424242424242',
|
||||
'exp_month': NOW.month,
|
||||
'exp_year': NOW.year + 4
|
||||
}
|
||||
DUMMY_DEBIT_CARD = {
|
||||
'number': '4000056655665556',
|
||||
'exp_month': NOW.month,
|
||||
'exp_year': NOW.year + 4
|
||||
}
|
||||
DUMMY_CHARGE = {
|
||||
'amount': 100,
|
||||
'currency': 'usd',
|
||||
'card': DUMMY_CARD
|
||||
}
|
||||
|
||||
DUMMY_DISPUTE = {
|
||||
'status': 'needs_response',
|
||||
'currency': 'usd',
|
||||
'metadata': {}
|
||||
}
|
||||
|
||||
DUMMY_PLAN = {
|
||||
'amount': 2000,
|
||||
'interval': 'month',
|
||||
'name': 'Amazing Gold Plan',
|
||||
'currency': 'usd',
|
||||
'id': ('stripe-test-gold-' +
|
||||
''.join(random.choice(string.ascii_lowercase) for x in range(10)))
|
||||
}
|
||||
|
||||
DUMMY_COUPON = {
|
||||
'percent_off': 25,
|
||||
'duration': 'repeating',
|
||||
'duration_in_months': 5,
|
||||
'metadata': {}
|
||||
}
|
||||
|
||||
DUMMY_RECIPIENT = {
|
||||
'name': 'John Doe',
|
||||
'type': 'individual'
|
||||
}
|
||||
|
||||
DUMMY_TRANSFER = {
|
||||
'amount': 400,
|
||||
'currency': 'usd',
|
||||
'recipient': 'self'
|
||||
}
|
||||
|
||||
DUMMY_INVOICE_ITEM = {
|
||||
'amount': 456,
|
||||
'currency': 'usd',
|
||||
}
|
||||
|
||||
SAMPLE_INVOICE = libraries.stripe.util.json.loads("""
|
||||
{
|
||||
"amount_due": 1305,
|
||||
"attempt_count": 0,
|
||||
"attempted": true,
|
||||
"charge": "ch_wajkQ5aDTzFs5v",
|
||||
"closed": true,
|
||||
"customer": "cus_osllUe2f1BzrRT",
|
||||
"date": 1338238728,
|
||||
"discount": null,
|
||||
"ending_balance": 0,
|
||||
"id": "in_t9mHb2hpK7mml1",
|
||||
"livemode": false,
|
||||
"next_payment_attempt": null,
|
||||
"object": "invoice",
|
||||
"paid": true,
|
||||
"period_end": 1338238728,
|
||||
"period_start": 1338238716,
|
||||
"starting_balance": -8695,
|
||||
"subtotal": 10000,
|
||||
"total": 10000,
|
||||
"lines": {
|
||||
"invoiceitems": [],
|
||||
"prorations": [],
|
||||
"subscriptions": [
|
||||
{
|
||||
"plan": {
|
||||
"interval": "month",
|
||||
"object": "plan",
|
||||
"identifier": "expensive",
|
||||
"currency": "usd",
|
||||
"livemode": false,
|
||||
"amount": 10000,
|
||||
"name": "Expensive Plan",
|
||||
"trial_period_days": null,
|
||||
"id": "expensive"
|
||||
},
|
||||
"period": {
|
||||
"end": 1340917128,
|
||||
"start": 1338238728
|
||||
},
|
||||
"amount": 10000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
class StripeTestCase(unittest2.TestCase):
|
||||
RESTORE_ATTRIBUTES = ('api_version', 'api_key')
|
||||
|
||||
def setUp(self):
|
||||
super(StripeTestCase, self).setUp()
|
||||
|
||||
self._stripe_original_attributes = {}
|
||||
|
||||
for attr in self.RESTORE_ATTRIBUTES:
|
||||
self._stripe_original_attributes[attr] = getattr(stripe, attr)
|
||||
|
||||
api_base = os.environ.get('STRIPE_API_BASE')
|
||||
if api_base:
|
||||
libraries.stripe.api_base = api_base
|
||||
libraries.stripe.api_key = os.environ.get(
|
||||
'STRIPE_API_KEY', 'tGN0bIwXnHdwOa85VABjPdSn8nWY7G7I')
|
||||
|
||||
def tearDown(self):
|
||||
super(StripeTestCase, self).tearDown()
|
||||
|
||||
for attr in self.RESTORE_ATTRIBUTES:
|
||||
setattr(stripe, attr, self._stripe_original_attributes[attr])
|
||||
|
||||
# Python < 2.7 compatibility
|
||||
def assertRaisesRegexp(self, exception, regexp, callable, *args, **kwargs):
|
||||
try:
|
||||
callable(*args, **kwargs)
|
||||
except exception as err:
|
||||
if regexp is None:
|
||||
return True
|
||||
|
||||
if isinstance(regexp, str):
|
||||
regexp = re.compile(regexp)
|
||||
if not regexp.search(str(err)):
|
||||
raise self.failureException('"%s" does not match "%s"' %
|
||||
(regexp.pattern, str(err)))
|
||||
else:
|
||||
raise self.failureException(
|
||||
'%s was not raised' % (exception.__name__,))
|
||||
|
||||
|
||||
class StripeUnitTestCase(StripeTestCase):
|
||||
REQUEST_LIBRARIES = ['urlfetch', 'requests', 'pycurl']
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
REQUEST_LIBRARIES.append('urllib.request')
|
||||
else:
|
||||
REQUEST_LIBRARIES.append('urllib2')
|
||||
|
||||
def setUp(self):
|
||||
super(StripeUnitTestCase, self).setUp()
|
||||
|
||||
self.request_patchers = {}
|
||||
self.request_mocks = {}
|
||||
for lib in self.REQUEST_LIBRARIES:
|
||||
patcher = patch("stripe.http_client.%s" % (lib,))
|
||||
|
||||
self.request_mocks[lib] = patcher.start()
|
||||
self.request_patchers[lib] = patcher
|
||||
|
||||
def tearDown(self):
|
||||
super(StripeUnitTestCase, self).tearDown()
|
||||
|
||||
for patcher in self.request_patchers.values():
|
||||
patcher.stop()
|
||||
|
||||
|
||||
class StripeApiTestCase(StripeTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(StripeApiTestCase, self).setUp()
|
||||
|
||||
self.requestor_patcher = patch('stripe.api_requestor.APIRequestor')
|
||||
requestor_class_mock = self.requestor_patcher.start()
|
||||
self.requestor_mock = requestor_class_mock.return_value
|
||||
|
||||
def tearDown(self):
|
||||
super(StripeApiTestCase, self).tearDown()
|
||||
|
||||
self.requestor_patcher.stop()
|
||||
|
||||
def mock_response(self, res):
|
||||
self.requestor_mock.request = Mock(return_value=(res, 'reskey'))
|
||||
|
||||
|
||||
class StripeResourceTest(StripeApiTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(StripeResourceTest, self).setUp()
|
||||
self.mock_response({})
|
||||
|
||||
|
||||
class MyResource(stripe.resource.APIResource):
|
||||
pass
|
||||
|
||||
|
||||
class MySingleton(stripe.resource.SingletonAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class MyListable(stripe.resource.ListableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class MyCreatable(stripe.resource.CreateableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class MyUpdateable(stripe.resource.UpdateableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class MyDeletable(stripe.resource.DeletableAPIResource):
|
||||
pass
|
||||
|
||||
|
||||
class MyComposite(stripe.resource.ListableAPIResource,
|
||||
libraries.stripe.resource.CreateableAPIResource,
|
||||
libraries.stripe.resource.UpdateableAPIResource,
|
||||
libraries.stripe.resource.DeletableAPIResource):
|
||||
pass
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class AccountTest(StripeResourceTest):
|
||||
|
||||
def test_retrieve_account_deprecated(self):
|
||||
libraries.stripe.Account.retrieve()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/account',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_retrieve_account(self):
|
||||
libraries.stripe.Account.retrieve('acct_foo')
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/accounts/acct_foo',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_list_accounts(self):
|
||||
libraries.stripe.Account.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/accounts',
|
||||
{}
|
||||
)
|
||||
|
||||
def test_create_account(self):
|
||||
pii = {
|
||||
'type': 'individual',
|
||||
'first_name': 'Joe',
|
||||
'last_name': 'Smith',
|
||||
}
|
||||
libraries.stripe.Account.create(legal_entity=pii)
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/accounts',
|
||||
{
|
||||
'legal_entity': pii,
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
||||
def test_update_account(self):
|
||||
acct = libraries.stripe.Account.construct_from({
|
||||
'id': 'acct_update',
|
||||
'legal_entity': {'first_name': 'Joe'},
|
||||
}, 'api_key')
|
||||
acct.legal_entity['first_name'] = 'Bob'
|
||||
acct.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/accounts/acct_update',
|
||||
{
|
||||
'legal_entity': {
|
||||
'first_name': 'Bob',
|
||||
},
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
||||
def test_account_delete_bank_account(self):
|
||||
source = libraries.stripe.BankAccount.construct_from({
|
||||
'account': 'acc_delete_ba',
|
||||
'id': 'ba_delete_ba',
|
||||
}, 'api_key')
|
||||
source.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/accounts/acc_delete_ba/external_accounts/ba_delete_ba',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_reject_account(self):
|
||||
self.mock_response({
|
||||
'id': 'acct_reject',
|
||||
'verification': {
|
||||
'disabled_reason': 'rejected.fraud'
|
||||
},
|
||||
})
|
||||
|
||||
obj = libraries.stripe.Account.construct_from({
|
||||
'id': 'acct_reject'
|
||||
}, 'mykey')
|
||||
|
||||
self.assertTrue(obj is obj.reject(reason='fraud'))
|
||||
self.assertEqual('rejected.fraud', obj.verification['disabled_reason'])
|
||||
self.assertEqual('acct_reject', obj.id)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/accounts/acct_reject/reject',
|
||||
{'reason': 'fraud'},
|
||||
None
|
||||
)
|
||||
|
||||
def test_reject_account_without_reason(self):
|
||||
self.mock_response({
|
||||
'id': 'acct_reject',
|
||||
'verification': {
|
||||
'disabled_reason': 'rejected.fraud'
|
||||
},
|
||||
})
|
||||
|
||||
obj = libraries.stripe.Account.construct_from({
|
||||
'id': 'acct_reject'
|
||||
}, 'mykey')
|
||||
|
||||
self.assertTrue(obj is obj.reject())
|
||||
self.assertEqual('rejected.fraud', obj.verification['disabled_reason'])
|
||||
self.assertEqual('acct_reject', obj.id)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/accounts/acct_reject/reject',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_verify_additional_owner(self):
|
||||
acct = libraries.stripe.Account.construct_from({
|
||||
'id': 'acct_update',
|
||||
'additional_owners': [{
|
||||
'first_name': 'Alice',
|
||||
'verification': {},
|
||||
}]
|
||||
}, 'api_key')
|
||||
owner = acct.additional_owners[0]
|
||||
owner.verification.document = 'file_foo'
|
||||
acct.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/accounts/acct_update',
|
||||
{
|
||||
'additional_owners': {
|
||||
'0': {
|
||||
'verification': {
|
||||
'document': 'file_foo',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
None,
|
||||
)
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeApiTestCase, MyResource, MySingleton
|
||||
)
|
||||
|
||||
|
||||
class APIResourceTests(StripeApiTestCase):
|
||||
|
||||
def test_retrieve_and_refresh(self):
|
||||
self.mock_response({
|
||||
'id': 'foo2',
|
||||
'bobble': 'scrobble',
|
||||
})
|
||||
|
||||
res = MyResource.retrieve('foo*', myparam=5)
|
||||
|
||||
url = '/v1/myresources/foo%2A'
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get', url, {'myparam': 5}, None
|
||||
)
|
||||
|
||||
self.assertEqual('scrobble', res.bobble)
|
||||
self.assertEqual('foo2', res.id)
|
||||
self.assertEqual('reskey', res.api_key)
|
||||
|
||||
self.mock_response({
|
||||
'frobble': 5,
|
||||
})
|
||||
|
||||
res = res.refresh()
|
||||
|
||||
url = '/v1/myresources/foo2'
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get', url, {'myparam': 5}, None
|
||||
)
|
||||
|
||||
self.assertEqual(5, res.frobble)
|
||||
self.assertRaises(KeyError, res.__getitem__, 'bobble')
|
||||
|
||||
def test_convert_to_stripe_object(self):
|
||||
sample = {
|
||||
'foo': 'bar',
|
||||
'adict': {
|
||||
'object': 'charge',
|
||||
'id': 42,
|
||||
'amount': 7,
|
||||
},
|
||||
'alist': [
|
||||
{
|
||||
'object': 'customer',
|
||||
'name': 'chilango'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
converted = libraries.stripe.resource.convert_to_stripe_object(
|
||||
sample, 'akey', None)
|
||||
|
||||
# Types
|
||||
self.assertTrue(isinstance(converted, libraries.stripe.resource.StripeObject))
|
||||
self.assertTrue(isinstance(converted.adict, libraries.stripe.Charge))
|
||||
self.assertEqual(1, len(converted.alist))
|
||||
self.assertTrue(isinstance(converted.alist[0], libraries.stripe.Customer))
|
||||
|
||||
# Values
|
||||
self.assertEqual('bar', converted.foo)
|
||||
self.assertEqual(42, converted.adict.id)
|
||||
self.assertEqual('chilango', converted.alist[0].name)
|
||||
|
||||
# Stripping
|
||||
# TODO: We should probably be stripping out this property
|
||||
# self.assertRaises(AttributeError, getattr, converted.adict, 'object')
|
||||
|
||||
|
||||
class SingletonAPIResourceTests(StripeApiTestCase):
|
||||
|
||||
def test_retrieve(self):
|
||||
self.mock_response({
|
||||
'single': 'ton'
|
||||
})
|
||||
res = MySingleton.retrieve()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get', '/v1/mysingleton', {}, None)
|
||||
|
||||
self.assertEqual('ton', res.single)
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class ApplicationFeeTest(StripeResourceTest):
|
||||
|
||||
def test_list_application_fees(self):
|
||||
libraries.stripe.ApplicationFee.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/application_fees',
|
||||
{}
|
||||
)
|
||||
|
||||
|
||||
class ApplicationFeeRefundTest(StripeResourceTest):
|
||||
|
||||
def test_fetch_refund(self):
|
||||
fee = libraries.stripe.ApplicationFee.construct_from({
|
||||
'id': 'fee_get_refund',
|
||||
'refunds': {
|
||||
'object': 'list',
|
||||
'url': '/v1/application_fees/fee_get_refund/refunds',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
fee.refunds.retrieve("ref_get")
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/application_fees/fee_get_refund/refunds/ref_get',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_list_refunds(self):
|
||||
fee = libraries.stripe.ApplicationFee.construct_from({
|
||||
'id': 'fee_get_refund',
|
||||
'refunds': {
|
||||
'object': 'list',
|
||||
'url': '/v1/application_fees/fee_get_refund/refunds',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
fee.refunds.list()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/application_fees/fee_get_refund/refunds',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_refund(self):
|
||||
def side_effect(*args):
|
||||
raise libraries.stripe.InvalidRequestError('invalid', 'foo')
|
||||
|
||||
self.requestor_mock.request.side_effect = side_effect
|
||||
|
||||
refund = libraries.stripe.resource.ApplicationFeeRefund.construct_from({
|
||||
'id': "ref_update",
|
||||
'fee': "fee_update",
|
||||
'metadata': {},
|
||||
}, 'api_key')
|
||||
|
||||
refund.metadata["key"] = "foo"
|
||||
|
||||
try:
|
||||
refund.save()
|
||||
except libraries.stripe.InvalidRequestError:
|
||||
pass
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/application_fees/fee_update/refunds/ref_update',
|
||||
{
|
||||
'metadata': {
|
||||
'key': 'foo',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
self.requestor_mock.request.side_effect = None
|
||||
|
||||
refund.metadata["key"] = "bar"
|
||||
refund.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/application_fees/fee_update/refunds/ref_update',
|
||||
{
|
||||
'metadata': {
|
||||
'key': 'bar',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_modify_refund(self):
|
||||
libraries.stripe.resource.ApplicationFeeRefund.modify("fee_update", "ref_update",
|
||||
metadata={'key': 'foo'},
|
||||
api_key='api_key')
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/application_fees/fee_update/refunds/ref_update',
|
||||
{
|
||||
'metadata': {
|
||||
'key': 'foo',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class BalanceTest(StripeResourceTest):
|
||||
|
||||
def test_retrieve_balance(self):
|
||||
libraries.stripe.Balance.retrieve()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/balance',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
|
||||
class BalanceTransactionTest(StripeResourceTest):
|
||||
|
||||
def test_list_balance_transactions(self):
|
||||
libraries.stripe.BalanceTransaction.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/balance/history',
|
||||
{}
|
||||
)
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class BitcoinReceiverTest(StripeResourceTest):
|
||||
|
||||
def test_retrieve_resource(self):
|
||||
libraries.stripe.BitcoinReceiver.retrieve("btcrcv_test_receiver")
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/bitcoin/receivers/btcrcv_test_receiver',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_list_receivers(self):
|
||||
libraries.stripe.BitcoinReceiver.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/bitcoin/receivers',
|
||||
{},
|
||||
)
|
||||
|
||||
def test_create_receiver(self):
|
||||
libraries.stripe.BitcoinReceiver.create(amount=100, description="some details",
|
||||
currency="usd",
|
||||
email="do+fill_now@stripe.com")
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/bitcoin/receivers',
|
||||
{
|
||||
'amount': 100,
|
||||
'description': 'some details',
|
||||
'currency': 'usd',
|
||||
'email': 'do+fill_now@stripe.com'
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_receiver_without_customer(self):
|
||||
params = {'id': 'receiver', 'amount': 100,
|
||||
'description': "some details", 'currency': "usd"}
|
||||
r = libraries.stripe.BitcoinReceiver.construct_from(params, 'api_key')
|
||||
r.description = "some other details"
|
||||
r.save()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/bitcoin/receivers/receiver',
|
||||
{
|
||||
'description': 'some other details',
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_receiver_with_customer(self):
|
||||
params = {'id': 'receiver', 'amount': 100,
|
||||
'description': "some details", 'currency': "usd",
|
||||
'customer': "cust"}
|
||||
r = libraries.stripe.BitcoinReceiver.construct_from(params, 'api_key')
|
||||
r.description = "some other details"
|
||||
r.save()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cust/sources/receiver',
|
||||
{
|
||||
'description': 'some other details',
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_delete_receiver_without_customer(self):
|
||||
params = {'id': 'receiver', 'amount': 100,
|
||||
'description': "some details", 'currency': "usd"}
|
||||
r = libraries.stripe.BitcoinReceiver.construct_from(params, 'api_key')
|
||||
r.delete()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/bitcoin/receivers/receiver',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_delete_receiver_with_customer(self):
|
||||
params = {'id': 'receiver', 'amount': 100,
|
||||
'description': "some details", 'currency': "usd",
|
||||
'customer': "cust"}
|
||||
r = libraries.stripe.BitcoinReceiver.construct_from(params, 'api_key')
|
||||
r.delete()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/customers/cust/sources/receiver',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_list_transactions(self):
|
||||
receiver = libraries.stripe.BitcoinReceiver.construct_from({
|
||||
'id': 'btcrcv_foo',
|
||||
'transactions': {
|
||||
'object': 'list',
|
||||
'url': '/v1/bitcoin/receivers/btcrcv_foo/transactions',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
receiver.transactions.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/bitcoin/receivers/btcrcv_foo/transactions',
|
||||
{},
|
||||
None
|
||||
)
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeResourceTest, NOW, DUMMY_CHARGE
|
||||
)
|
||||
|
||||
|
||||
class ChargeTest(StripeResourceTest):
|
||||
|
||||
def test_charge_list(self):
|
||||
libraries.stripe.Charge.list(created={'lt': NOW})
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/charges',
|
||||
{
|
||||
'created': {'lt': NOW},
|
||||
}
|
||||
)
|
||||
|
||||
def test_charge_create(self):
|
||||
libraries.stripe.Charge.create(idempotency_key='foo', **DUMMY_CHARGE)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges',
|
||||
DUMMY_CHARGE,
|
||||
{'Idempotency-Key': 'foo'},
|
||||
)
|
||||
|
||||
def test_charge_retrieve(self):
|
||||
libraries.stripe.Charge.retrieve('ch_test_id')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/charges/ch_test_id',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_charge_modify(self):
|
||||
libraries.stripe.Charge.modify('ch_test_id', refund=True)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_test_id',
|
||||
{
|
||||
'refund': True,
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_charge_update_dispute(self):
|
||||
charge = libraries.stripe.Charge(id='ch_update_id')
|
||||
charge.update_dispute(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_update_id/dispute',
|
||||
{},
|
||||
{'Idempotency-Key': 'foo'},
|
||||
)
|
||||
|
||||
def test_charge_close_dispute(self):
|
||||
charge = libraries.stripe.Charge(id='ch_update_id')
|
||||
charge.close_dispute(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_update_id/dispute/close',
|
||||
{},
|
||||
{'Idempotency-Key': 'foo'},
|
||||
)
|
||||
|
||||
def test_mark_as_fraudulent(self):
|
||||
charge = libraries.stripe.Charge(id='ch_update_id')
|
||||
charge.mark_as_fraudulent(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_update_id',
|
||||
{
|
||||
'fraud_details': {'user_report': 'fraudulent'}
|
||||
},
|
||||
{'Idempotency-Key': 'foo'},
|
||||
)
|
||||
|
||||
def test_mark_as_safe(self):
|
||||
charge = libraries.stripe.Charge(id='ch_update_id')
|
||||
charge.mark_as_safe(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_update_id',
|
||||
{
|
||||
'fraud_details': {'user_report': 'safe'}
|
||||
},
|
||||
{'Idempotency-Key': 'foo'},
|
||||
)
|
||||
|
||||
def test_create_with_source_param(self):
|
||||
libraries.stripe.Charge.create(amount=100, currency='usd',
|
||||
source='btcrcv_test_receiver')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges',
|
||||
{
|
||||
'amount': 100,
|
||||
'currency': 'usd',
|
||||
'source': 'btcrcv_test_receiver'
|
||||
},
|
||||
None,
|
||||
)
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class CountrySpecTest(StripeResourceTest):
|
||||
|
||||
def test_country_spec_list(self):
|
||||
libraries.stripe.CountrySpec.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/country_specs',
|
||||
{}
|
||||
)
|
||||
|
||||
def test_country_spec_retrieve(self):
|
||||
libraries.stripe.CountrySpec.retrieve('US')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/country_specs/US',
|
||||
{},
|
||||
None
|
||||
)
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeResourceTest, DUMMY_COUPON
|
||||
)
|
||||
|
||||
|
||||
class CouponTest(StripeResourceTest):
|
||||
|
||||
def test_create_coupon(self):
|
||||
libraries.stripe.Coupon.create(**DUMMY_COUPON)
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/coupons',
|
||||
DUMMY_COUPON,
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_coupon(self):
|
||||
coup = libraries.stripe.Coupon.construct_from({
|
||||
'id': 'cu_update',
|
||||
'metadata': {},
|
||||
}, 'api_key')
|
||||
coup.metadata["key"] = "value"
|
||||
coup.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
"/v1/coupons/cu_update",
|
||||
{
|
||||
'metadata': {
|
||||
'key': 'value',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_delete_coupon(self):
|
||||
c = libraries.stripe.Coupon(id='cu_delete')
|
||||
c.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/coupons/cu_delete',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_detach_coupon(self):
|
||||
customer = libraries.stripe.Customer(id="cus_delete_discount")
|
||||
customer.delete_discount()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/customers/cus_delete_discount/discount',
|
||||
)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeApiTestCase, MyCreatable
|
||||
)
|
||||
|
||||
|
||||
class CreateableAPIResourceTests(StripeApiTestCase):
|
||||
|
||||
def test_create(self):
|
||||
self.mock_response({
|
||||
'object': 'charge',
|
||||
'foo': 'bar',
|
||||
})
|
||||
|
||||
res = MyCreatable.create()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post', '/v1/mycreatables', {}, None)
|
||||
|
||||
self.assertTrue(isinstance(res, libraries.stripe.Charge))
|
||||
self.assertEqual('bar', res.foo)
|
||||
|
||||
def test_idempotent_create(self):
|
||||
self.mock_response({
|
||||
'object': 'charge',
|
||||
'foo': 'bar',
|
||||
})
|
||||
|
||||
res = MyCreatable.create(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post', '/v1/mycreatables', {}, {'Idempotency-Key': 'foo'})
|
||||
|
||||
self.assertTrue(isinstance(res, libraries.stripe.Charge))
|
||||
self.assertEqual('bar', res.foo)
|
||||
+370
@@ -0,0 +1,370 @@
|
||||
import datetime
|
||||
import time
|
||||
import warnings
|
||||
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeResourceTest, DUMMY_CARD, DUMMY_PLAN
|
||||
)
|
||||
|
||||
|
||||
class CustomerTest(StripeResourceTest):
|
||||
|
||||
def test_list_customers(self):
|
||||
libraries.stripe.Customer.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/customers',
|
||||
{},
|
||||
)
|
||||
|
||||
def test_create_customer(self):
|
||||
libraries.stripe.Customer.create(description="foo bar", card=DUMMY_CARD,
|
||||
coupon='cu_discount', idempotency_key='foo')
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers',
|
||||
{
|
||||
'coupon': 'cu_discount',
|
||||
'description': 'foo bar',
|
||||
'card': DUMMY_CARD
|
||||
},
|
||||
{'Idempotency-Key': 'foo'}
|
||||
)
|
||||
|
||||
def test_unset_description(self):
|
||||
customer = libraries.stripe.Customer(id="cus_unset_desc")
|
||||
customer.description = "Hey"
|
||||
customer.save(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_unset_desc',
|
||||
{
|
||||
'description': 'Hey',
|
||||
},
|
||||
{'Idempotency-Key': 'foo'}
|
||||
)
|
||||
|
||||
def test_del_coupon(self):
|
||||
customer = libraries.stripe.Customer(id="cus_unset_desc")
|
||||
customer.description = "bar"
|
||||
customer.coupon = "foo"
|
||||
del customer.coupon
|
||||
customer.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_unset_desc',
|
||||
{
|
||||
'description': 'bar'
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_cannot_set_empty_string(self):
|
||||
customer = libraries.stripe.Customer()
|
||||
self.assertRaises(ValueError, setattr, customer, "description", "")
|
||||
|
||||
def test_customer_add_card(self):
|
||||
customer = libraries.stripe.Customer.construct_from({
|
||||
'id': 'cus_add_card',
|
||||
'sources': {
|
||||
'object': 'list',
|
||||
'url': '/v1/customers/cus_add_card/sources',
|
||||
},
|
||||
}, 'api_key')
|
||||
customer.sources.create(card=DUMMY_CARD, idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_add_card/sources',
|
||||
{
|
||||
'card': DUMMY_CARD,
|
||||
},
|
||||
{'Idempotency-Key': 'foo'}
|
||||
)
|
||||
|
||||
def test_customer_add_source(self):
|
||||
customer = libraries.stripe.Customer.construct_from({
|
||||
'id': 'cus_add_source',
|
||||
'sources': {
|
||||
'object': 'list',
|
||||
'url': '/v1/customers/cus_add_source/sources',
|
||||
},
|
||||
}, 'api_key')
|
||||
customer.sources.create(source=DUMMY_CARD, idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_add_source/sources',
|
||||
{
|
||||
'source': DUMMY_CARD,
|
||||
},
|
||||
{'Idempotency-Key': 'foo'}
|
||||
)
|
||||
|
||||
def test_customer_update_card(self):
|
||||
card = libraries.stripe.Card.construct_from({
|
||||
'customer': 'cus_update_card',
|
||||
'id': 'ca_update_card',
|
||||
}, 'api_key')
|
||||
card.name = 'The Best'
|
||||
card.save(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_update_card/sources/ca_update_card',
|
||||
{
|
||||
'name': 'The Best',
|
||||
},
|
||||
{'Idempotency-Key': 'foo'}
|
||||
)
|
||||
|
||||
def test_customer_update_source(self):
|
||||
source = libraries.stripe.BitcoinReceiver.construct_from({
|
||||
'customer': 'cus_update_source',
|
||||
'id': 'btcrcv_update_source',
|
||||
}, 'api_key')
|
||||
source.name = 'The Best'
|
||||
source.save(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_update_source/sources/btcrcv_update_source',
|
||||
{
|
||||
'name': 'The Best',
|
||||
},
|
||||
{'Idempotency-Key': 'foo'}
|
||||
)
|
||||
|
||||
def test_customer_update_alipay_account(self):
|
||||
aa = libraries.stripe.AlipayAccount.construct_from({
|
||||
'customer': 'cus_update_alipay',
|
||||
'id': 'ali_update',
|
||||
}, 'api_key')
|
||||
aa.metadata = {'name': 'The Best'}
|
||||
aa.save(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_update_alipay/sources/ali_update',
|
||||
{
|
||||
'metadata': {'name': 'The Best'},
|
||||
},
|
||||
{'Idempotency-Key': 'foo'}
|
||||
)
|
||||
|
||||
def test_customer_delete_card(self):
|
||||
card = libraries.stripe.Card.construct_from({
|
||||
'customer': 'cus_delete_card',
|
||||
'id': 'ca_delete_card',
|
||||
}, 'api_key')
|
||||
card.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/customers/cus_delete_card/sources/ca_delete_card',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_customer_delete_source(self):
|
||||
source = libraries.stripe.BitcoinReceiver.construct_from({
|
||||
'customer': 'cus_delete_source',
|
||||
'id': 'btcrcv_delete_source',
|
||||
}, 'api_key')
|
||||
source.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/customers/cus_delete_source/sources/btcrcv_delete_source',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_customer_delete_alipay_account(self):
|
||||
aa = libraries.stripe.AlipayAccount.construct_from({
|
||||
'customer': 'cus_delete_alipay',
|
||||
'id': 'ali_delete',
|
||||
}, 'api_key')
|
||||
aa.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/customers/cus_delete_alipay/sources/ali_delete',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_customer_delete_bank_account(self):
|
||||
source = libraries.stripe.BankAccount.construct_from({
|
||||
'customer': 'cus_delete_source',
|
||||
'id': 'ba_delete_source',
|
||||
}, 'api_key')
|
||||
source.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/customers/cus_delete_source/sources/ba_delete_source',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_customer_verify_bank_account(self):
|
||||
source = libraries.stripe.BankAccount.construct_from({
|
||||
'customer': 'cus_verify_source',
|
||||
'id': 'ba_verify_source',
|
||||
}, 'api_key')
|
||||
source.verify()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_verify_source/sources/ba_verify_source/verify',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
|
||||
class CustomerPlanTest(StripeResourceTest):
|
||||
|
||||
def test_create_customer(self):
|
||||
libraries.stripe.Customer.create(plan=DUMMY_PLAN['id'], card=DUMMY_CARD)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers',
|
||||
{
|
||||
'card': DUMMY_CARD,
|
||||
'plan': DUMMY_PLAN['id'],
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_legacy_update_subscription(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
customer = libraries.stripe.Customer(id="cus_legacy_sub_update")
|
||||
customer.update_subscription(idempotency_key='foo',
|
||||
plan=DUMMY_PLAN['id'])
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_legacy_sub_update/subscription',
|
||||
{
|
||||
'plan': DUMMY_PLAN['id'],
|
||||
},
|
||||
{'Idempotency-Key': 'foo'}
|
||||
)
|
||||
|
||||
self.assertEqual(len(w), 1)
|
||||
self.assertTrue(issubclass(w[-1].category, DeprecationWarning))
|
||||
|
||||
def test_legacy_delete_subscription(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
customer = libraries.stripe.Customer(id="cus_legacy_sub_delete")
|
||||
customer.cancel_subscription()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/customers/cus_legacy_sub_delete/subscription',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
self.assertEqual(len(w), 1)
|
||||
self.assertTrue(issubclass(w[-1].category, DeprecationWarning))
|
||||
|
||||
def test_list_customer_subscriptions(self):
|
||||
customer = libraries.stripe.Customer.construct_from({
|
||||
'id': 'cus_foo',
|
||||
'subscriptions': {
|
||||
'object': 'list',
|
||||
'url': 'v1/customers/cus_foo/subscriptions',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
customer.subscriptions.all()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'v1/customers/cus_foo/subscriptions',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_create_customer_subscription(self):
|
||||
customer = libraries.stripe.Customer.construct_from({
|
||||
'id': 'cus_sub_create',
|
||||
'subscriptions': {
|
||||
'object': 'list',
|
||||
'url': '/v1/customers/cus_sub_create/subscriptions',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
customer.subscriptions.create(plan=DUMMY_PLAN['id'], coupon='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/customers/cus_sub_create/subscriptions',
|
||||
{
|
||||
'plan': DUMMY_PLAN['id'],
|
||||
'coupon': 'foo',
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_retrieve_customer_subscription(self):
|
||||
customer = libraries.stripe.Customer.construct_from({
|
||||
'id': 'cus_foo',
|
||||
'subscriptions': {
|
||||
'object': 'list',
|
||||
'url': '/v1/customers/cus_foo/subscriptions',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
customer.subscriptions.retrieve('sub_cus')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/customers/cus_foo/subscriptions/sub_cus',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_customer_subscription(self):
|
||||
subscription = libraries.stripe.Subscription.construct_from({
|
||||
'id': "sub_update",
|
||||
'customer': "cus_foo",
|
||||
}, 'api_key')
|
||||
|
||||
trial_end_dttm = datetime.datetime.now() + datetime.timedelta(days=15)
|
||||
trial_end_int = int(time.mktime(trial_end_dttm.timetuple()))
|
||||
|
||||
subscription.trial_end = trial_end_int
|
||||
subscription.plan = DUMMY_PLAN['id']
|
||||
subscription.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/subscriptions/sub_update',
|
||||
{
|
||||
'plan': DUMMY_PLAN['id'],
|
||||
'trial_end': trial_end_int,
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_delete_customer_subscription(self):
|
||||
subscription = libraries.stripe.Subscription.construct_from({
|
||||
'id': "sub_delete",
|
||||
'customer': "cus_foo",
|
||||
}, 'api_key')
|
||||
|
||||
subscription.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/subscriptions/sub_delete',
|
||||
{},
|
||||
None
|
||||
)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeApiTestCase, MyDeletable
|
||||
)
|
||||
|
||||
|
||||
class DeletableAPIResourceTests(StripeApiTestCase):
|
||||
|
||||
def test_delete(self):
|
||||
self.mock_response({
|
||||
'id': 'mid',
|
||||
'deleted': True,
|
||||
})
|
||||
|
||||
obj = MyDeletable.construct_from({
|
||||
'id': 'mid'
|
||||
}, 'mykey')
|
||||
|
||||
self.assertTrue(obj is obj.delete())
|
||||
|
||||
self.assertEqual(True, obj.deleted)
|
||||
self.assertEqual('mid', obj.id)
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeResourceTest, DUMMY_DISPUTE, NOW
|
||||
)
|
||||
|
||||
|
||||
class DisputeTest(StripeResourceTest):
|
||||
|
||||
def test_list_all_disputes(self):
|
||||
libraries.stripe.Dispute.list(created={'lt': NOW})
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/disputes',
|
||||
{
|
||||
'created': {'lt': NOW},
|
||||
}
|
||||
)
|
||||
|
||||
def test_create_dispute(self):
|
||||
libraries.stripe.Dispute.create(idempotency_key='foo', **DUMMY_DISPUTE)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/disputes',
|
||||
DUMMY_DISPUTE,
|
||||
{'Idempotency-Key': 'foo'},
|
||||
)
|
||||
|
||||
def test_retrieve_dispute(self):
|
||||
libraries.stripe.Dispute.retrieve('dp_test_id')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/disputes/dp_test_id',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_dispute(self):
|
||||
dispute = libraries.stripe.Dispute.construct_from({
|
||||
'id': 'dp_update_id',
|
||||
'evidence': {
|
||||
'product_description': 'description',
|
||||
},
|
||||
}, 'api_key')
|
||||
dispute.evidence['customer_name'] = 'customer'
|
||||
dispute.evidence['uncategorized_text'] = 'text'
|
||||
dispute.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/disputes/dp_update_id',
|
||||
{'evidence': {
|
||||
'customer_name': 'customer',
|
||||
'uncategorized_text': 'text',
|
||||
}},
|
||||
None
|
||||
)
|
||||
|
||||
def test_close_dispute(self):
|
||||
dispute = libraries.stripe.Dispute(id='dp_close_id')
|
||||
dispute.close(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/disputes/dp_close_id/close',
|
||||
{},
|
||||
{'Idempotency-Key': 'foo'},
|
||||
)
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
import tempfile
|
||||
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class FileUploadTest(StripeResourceTest):
|
||||
|
||||
def test_create_file_upload(self):
|
||||
test_file = tempfile.TemporaryFile()
|
||||
libraries.stripe.FileUpload.create(
|
||||
purpose='dispute_evidence',
|
||||
file=test_file
|
||||
)
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/files',
|
||||
params={
|
||||
'purpose': 'dispute_evidence',
|
||||
'file': test_file
|
||||
},
|
||||
headers={'Content-Type': 'multipart/form-data'}
|
||||
)
|
||||
|
||||
def test_fetch_file_upload(self):
|
||||
libraries.stripe.FileUpload.retrieve("fil_foo")
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/files/fil_foo',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_list_file_uploads(self):
|
||||
libraries.stripe.FileUpload.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/files',
|
||||
{}
|
||||
)
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeResourceTest, DUMMY_INVOICE_ITEM
|
||||
)
|
||||
|
||||
|
||||
class InvoiceTest(StripeResourceTest):
|
||||
|
||||
def test_add_invoice_item(self):
|
||||
customer = libraries.stripe.Customer(id="cus_invoice_items")
|
||||
customer.add_invoice_item(**DUMMY_INVOICE_ITEM)
|
||||
|
||||
expected = DUMMY_INVOICE_ITEM.copy()
|
||||
expected['customer'] = 'cus_invoice_items'
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/invoiceitems',
|
||||
expected,
|
||||
None,
|
||||
)
|
||||
|
||||
def test_retrieve_invoice_items(self):
|
||||
customer = libraries.stripe.Customer(id="cus_get_invoice_items")
|
||||
customer.invoice_items()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/invoiceitems',
|
||||
{'customer': 'cus_get_invoice_items'},
|
||||
)
|
||||
|
||||
def test_invoice_create(self):
|
||||
customer = libraries.stripe.Customer(id="cus_invoice")
|
||||
libraries.stripe.Invoice.create(customer=customer.id)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/invoices',
|
||||
{
|
||||
'customer': 'cus_invoice',
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_retrieve_customer_invoices(self):
|
||||
customer = libraries.stripe.Customer(id="cus_invoice_items")
|
||||
customer.invoices()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/invoices',
|
||||
{
|
||||
'customer': 'cus_invoice_items',
|
||||
},
|
||||
)
|
||||
|
||||
def test_pay_invoice(self):
|
||||
invoice = libraries.stripe.Invoice(id="ii_pay")
|
||||
invoice.pay()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/invoices/ii_pay/pay',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_upcoming_invoice(self):
|
||||
libraries.stripe.Invoice.upcoming()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/invoices/upcoming',
|
||||
{},
|
||||
)
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeApiTestCase
|
||||
|
||||
|
||||
class ListObjectTests(StripeApiTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ListObjectTests, self).setUp()
|
||||
|
||||
self.lo = libraries.stripe.resource.ListObject.construct_from({
|
||||
'id': 'me',
|
||||
'url': '/my/path',
|
||||
'data': ['foo'],
|
||||
}, 'mykey')
|
||||
|
||||
self.mock_response([{
|
||||
'object': 'charge',
|
||||
'foo': 'bar',
|
||||
}])
|
||||
|
||||
def assertResponse(self, res):
|
||||
self.assertTrue(isinstance(res[0], libraries.stripe.Charge))
|
||||
self.assertEqual('bar', res[0].foo)
|
||||
|
||||
def test_for_loop(self):
|
||||
seen = []
|
||||
|
||||
for item in self.lo:
|
||||
seen.append(item)
|
||||
|
||||
self.assertEqual(['foo'], seen)
|
||||
|
||||
def test_list(self):
|
||||
res = self.lo.list(myparam='you')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get', '/my/path', {'myparam': 'you'}, None)
|
||||
|
||||
self.assertResponse(res)
|
||||
|
||||
def test_create(self):
|
||||
res = self.lo.create(myparam='eter')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post', '/my/path', {'myparam': 'eter'}, None)
|
||||
|
||||
self.assertResponse(res)
|
||||
|
||||
def test_retrieve(self):
|
||||
res = self.lo.retrieve('myid', myparam='cow')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get', '/my/path/myid', {'myparam': 'cow'}, None)
|
||||
|
||||
self.assertResponse(res)
|
||||
|
||||
|
||||
class AutoPagingTests(StripeApiTestCase):
|
||||
|
||||
@staticmethod
|
||||
def pageable_model_response(ids, has_more):
|
||||
return {
|
||||
'object': 'list',
|
||||
'url': '/v1/pageablemodels',
|
||||
'data': [{'id': id, 'object': 'pageablemodel'} for id in ids],
|
||||
'has_more': has_more,
|
||||
}
|
||||
|
||||
def test_iter_one_page(self):
|
||||
lo = libraries.stripe.resource.ListObject.construct_from(
|
||||
self.pageable_model_response(['pm_123', 'pm_124'], False),
|
||||
'mykey'
|
||||
)
|
||||
|
||||
self.requestor_mock.request.assert_not_called()
|
||||
|
||||
seen = [item['id'] for item in lo.auto_paging_iter()]
|
||||
|
||||
self.assertEqual(['pm_123', 'pm_124'], seen)
|
||||
|
||||
def test_iter_two_pages(self):
|
||||
lo = libraries.stripe.resource.ListObject.construct_from(
|
||||
self.pageable_model_response(['pm_123', 'pm_124'], True),
|
||||
'mykey'
|
||||
)
|
||||
lo._retrieve_params = {'foo': 'bar'}
|
||||
|
||||
self.mock_response(
|
||||
self.pageable_model_response(['pm_125', 'pm_126'], False)
|
||||
)
|
||||
|
||||
seen = [item['id'] for item in lo.auto_paging_iter()]
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/pageablemodels',
|
||||
{
|
||||
'starting_after': 'pm_124',
|
||||
'foo': 'bar'
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
self.assertEqual(['pm_123', 'pm_124', 'pm_125', 'pm_126'], seen)
|
||||
|
||||
def test_class_method_two_pages(self):
|
||||
self.mock_response({
|
||||
'object': 'list',
|
||||
'data': [{'id': 'ch_001'}],
|
||||
'url': '/v1/charges',
|
||||
'has_more': False,
|
||||
})
|
||||
|
||||
seen = [item['id'] for item in libraries.stripe.Charge.auto_paging_iter(
|
||||
limit=25,
|
||||
foo='bar'
|
||||
)]
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get', '/v1/charges', {'limit': 25, 'foo': 'bar'}
|
||||
)
|
||||
|
||||
self.assertEqual(['ch_001'], seen)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeApiTestCase, MyListable
|
||||
)
|
||||
|
||||
|
||||
class ListableAPIResourceTests(StripeApiTestCase):
|
||||
|
||||
def test_all(self):
|
||||
self.mock_response({
|
||||
'object': 'list',
|
||||
'data': [
|
||||
{
|
||||
'object': 'charge',
|
||||
'name': 'jose',
|
||||
},
|
||||
{
|
||||
'object': 'charge',
|
||||
'name': 'curly',
|
||||
}
|
||||
],
|
||||
'url': '/v1/charges',
|
||||
'has_more': False,
|
||||
})
|
||||
|
||||
res = MyListable.list()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get', '/v1/mylistables', {})
|
||||
|
||||
self.assertEqual(2, len(res.data))
|
||||
self.assertTrue(all(isinstance(obj, libraries.stripe.Charge)
|
||||
for obj in res.data))
|
||||
self.assertEqual('jose', res.data[0].name)
|
||||
self.assertEqual('curly', res.data[1].name)
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class MetadataTest(StripeResourceTest):
|
||||
|
||||
def test_noop_metadata(self):
|
||||
charge = libraries.stripe.Charge(id='ch_foo')
|
||||
charge.description = 'test'
|
||||
charge.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_foo',
|
||||
{
|
||||
'description': 'test',
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_unset_metadata(self):
|
||||
charge = libraries.stripe.Charge(id='ch_foo')
|
||||
charge.metadata = {}
|
||||
charge.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_foo',
|
||||
{
|
||||
'metadata': {},
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_whole_update(self):
|
||||
charge = libraries.stripe.Charge(id='ch_foo')
|
||||
charge.metadata = {'whole': 'update'}
|
||||
charge.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_foo',
|
||||
{
|
||||
'metadata': {'whole': 'update'},
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_individual_delete(self):
|
||||
charge = libraries.stripe.Charge(id='ch_foo')
|
||||
charge.metadata = {'whole': None}
|
||||
charge.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_foo',
|
||||
{
|
||||
'metadata': {'whole': None},
|
||||
},
|
||||
None
|
||||
)
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeResourceTest, DUMMY_PLAN
|
||||
)
|
||||
|
||||
|
||||
class PlanTest(StripeResourceTest):
|
||||
|
||||
def test_create_plan(self):
|
||||
libraries.stripe.Plan.create(**DUMMY_PLAN)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/plans',
|
||||
DUMMY_PLAN,
|
||||
None
|
||||
)
|
||||
|
||||
def test_delete_plan(self):
|
||||
p = libraries.stripe.Plan(id="pl_delete")
|
||||
p.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/plans/pl_delete',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_plan(self):
|
||||
p = libraries.stripe.Plan(id="pl_update")
|
||||
p.name = "Plan Name"
|
||||
p.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/plans/pl_update',
|
||||
{
|
||||
'name': 'Plan Name',
|
||||
},
|
||||
None
|
||||
)
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeResourceTest, DUMMY_CARD
|
||||
)
|
||||
|
||||
|
||||
class RecipientTest(StripeResourceTest):
|
||||
|
||||
def test_list_recipients(self):
|
||||
libraries.stripe.Recipient.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/recipients',
|
||||
{}
|
||||
)
|
||||
|
||||
def test_recipient_transfers(self):
|
||||
recipient = libraries.stripe.Recipient(id='rp_transfer')
|
||||
recipient.transfers()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/transfers',
|
||||
{'recipient': 'rp_transfer'},
|
||||
)
|
||||
|
||||
def test_recipient_add_card(self):
|
||||
recipient = libraries.stripe.Recipient.construct_from({
|
||||
'id': 'rp_add_card',
|
||||
'sources': {
|
||||
'object': 'list',
|
||||
'url': '/v1/recipients/rp_add_card/sources',
|
||||
},
|
||||
}, 'api_key')
|
||||
recipient.sources.create(card=DUMMY_CARD)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/recipients/rp_add_card/sources',
|
||||
{
|
||||
'card': DUMMY_CARD,
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_recipient_update_card(self):
|
||||
card = libraries.stripe.Card.construct_from({
|
||||
'recipient': 'rp_update_card',
|
||||
'id': 'ca_update_card',
|
||||
}, 'api_key')
|
||||
card.name = 'The Best'
|
||||
card.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/recipients/rp_update_card/cards/ca_update_card',
|
||||
{
|
||||
'name': 'The Best',
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_recipient_delete_card(self):
|
||||
card = libraries.stripe.Card.construct_from({
|
||||
'recipient': 'rp_delete_card',
|
||||
'id': 'ca_delete_card',
|
||||
}, 'api_key')
|
||||
card.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/recipients/rp_delete_card/cards/ca_delete_card',
|
||||
{},
|
||||
None
|
||||
)
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class RefundTest(StripeResourceTest):
|
||||
|
||||
def test_create_refund(self):
|
||||
libraries.stripe.Refund.create(charge='ch_foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/refunds',
|
||||
{'charge': 'ch_foo'},
|
||||
None
|
||||
)
|
||||
|
||||
def test_fetch_refund(self):
|
||||
libraries.stripe.Refund.retrieve('re_foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/refunds/re_foo',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_list_refunds(self):
|
||||
libraries.stripe.Refund.list(limit=3, charge='ch_foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/refunds',
|
||||
{'limit': 3, 'charge': 'ch_foo'}
|
||||
)
|
||||
|
||||
def test_update_refund(self):
|
||||
refund = libraries.stripe.resource.Refund.construct_from({
|
||||
'id': "ref_update",
|
||||
'charge': "ch_update",
|
||||
'metadata': {},
|
||||
}, 'api_key')
|
||||
refund.metadata["key"] = "value"
|
||||
refund.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/refunds/ref_update',
|
||||
{
|
||||
'metadata': {
|
||||
'key': 'value',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
|
||||
class ChargeRefundTest(StripeResourceTest):
|
||||
|
||||
def test_create_refund(self):
|
||||
charge = libraries.stripe.Charge.construct_from({
|
||||
'id': 'ch_foo',
|
||||
'refunds': {
|
||||
'object': 'list',
|
||||
'url': '/v1/charges/ch_foo/refunds',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
charge.refunds.create()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_foo/refunds',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_non_recursive_save(self):
|
||||
charge = libraries.stripe.Charge.construct_from({
|
||||
'id': 'ch_nested_update',
|
||||
'customer': {
|
||||
'object': 'customer',
|
||||
'description': 'foo',
|
||||
},
|
||||
'refunds': {
|
||||
'object': 'list',
|
||||
'url': '/v1/charges/ch_foo/refunds',
|
||||
'data': [{
|
||||
'id': 'ref_123',
|
||||
}],
|
||||
},
|
||||
}, 'api_key')
|
||||
|
||||
charge.customer.description = 'bar'
|
||||
charge.refunds.has_more = True
|
||||
charge.refunds.data[0].description = 'bar'
|
||||
charge.save()
|
||||
|
||||
# Note: ideally, we'd want the library to NOT issue requests in this
|
||||
# case (i.e. the assert should actually be `assert_not_called()`).
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/charges/ch_nested_update',
|
||||
{'refunds': {'has_more': True}},
|
||||
None
|
||||
)
|
||||
|
||||
def test_fetch_refund(self):
|
||||
charge = libraries.stripe.Charge.construct_from({
|
||||
'id': 'ch_get_refund',
|
||||
'refunds': {
|
||||
'object': 'list',
|
||||
'url': '/v1/charges/ch_get_refund/refunds',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
charge.refunds.retrieve("ref_get")
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/charges/ch_get_refund/refunds/ref_get',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_list_refunds(self):
|
||||
charge = libraries.stripe.Charge.construct_from({
|
||||
'id': 'ch_get_refund',
|
||||
'refunds': {
|
||||
'object': 'list',
|
||||
'url': '/v1/charges/ch_get_refund/refunds',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
charge.refunds.list()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/charges/ch_get_refund/refunds',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_refund(self):
|
||||
refund = libraries.stripe.resource.Refund.construct_from({
|
||||
'id': "ref_update",
|
||||
'charge': "ch_update",
|
||||
'metadata': {},
|
||||
}, 'api_key')
|
||||
refund.metadata["key"] = "value"
|
||||
refund.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/refunds/ref_update',
|
||||
{
|
||||
'metadata': {
|
||||
'key': 'value',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class ProductTest(StripeResourceTest):
|
||||
|
||||
def test_list_products(self):
|
||||
libraries.stripe.Product.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/products',
|
||||
{}
|
||||
)
|
||||
|
||||
def test_delete_products(self):
|
||||
p = libraries.stripe.Product(id='product_to_delete')
|
||||
p.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/products/product_to_delete',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
|
||||
class SKUTest(StripeResourceTest):
|
||||
|
||||
def test_list_skus(self):
|
||||
libraries.stripe.SKU.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/skus',
|
||||
{}
|
||||
)
|
||||
|
||||
def test_delete_skus(self):
|
||||
sku = libraries.stripe.SKU(id='sku_delete')
|
||||
sku.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/skus/sku_delete',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
|
||||
class OrderTest(StripeResourceTest):
|
||||
|
||||
def test_list_orders(self):
|
||||
libraries.stripe.Order.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/orders',
|
||||
{}
|
||||
)
|
||||
|
||||
def test_pay_order(self):
|
||||
order = libraries.stripe.Order(id="or_pay")
|
||||
order.pay()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/orders/or_pay/pay',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_return_order(self):
|
||||
order = libraries.stripe.Order(id="or_return")
|
||||
order.return_order()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/orders/or_return/returns',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
|
||||
class OrderReturnTest(StripeResourceTest):
|
||||
|
||||
def test_list_order_returns(self):
|
||||
libraries.stripe.OrderReturn.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/order_returns',
|
||||
{}
|
||||
)
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class ReversalTest(StripeResourceTest):
|
||||
|
||||
def test_fetch_reversal(self):
|
||||
transfer = libraries.stripe.Charge.construct_from({
|
||||
'id': 'tr_get',
|
||||
'reversals': {
|
||||
'object': 'list',
|
||||
'url': '/v1/transfers/tr_get/reversals',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
transfer.reversals.retrieve("foo")
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/transfers/tr_get/reversals/foo',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_list_reversals(self):
|
||||
transfer = libraries.stripe.Charge.construct_from({
|
||||
'id': 'tr_list',
|
||||
'reversals': {
|
||||
'object': 'list',
|
||||
'url': '/v1/transfers/tr_list/reversals',
|
||||
}
|
||||
}, 'api_key')
|
||||
|
||||
transfer.reversals.list()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/transfers/tr_list/reversals',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_transfer(self):
|
||||
reversal = libraries.stripe.resource.Reversal.construct_from({
|
||||
'id': "rev_update",
|
||||
'transfer': "tr_update",
|
||||
'metadata': {},
|
||||
}, 'api_key')
|
||||
reversal.metadata["key"] = "value"
|
||||
reversal.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/transfers/tr_update/reversals/rev_update',
|
||||
{
|
||||
'metadata': {
|
||||
'key': 'value',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
import pickle
|
||||
import sys
|
||||
|
||||
import libraries.stripe
|
||||
from libraries.stripe import util
|
||||
from libraries.stripe.test.helper import StripeUnitTestCase, SAMPLE_INVOICE
|
||||
|
||||
|
||||
class StripeObjectTests(StripeUnitTestCase):
|
||||
|
||||
def test_initializes_with_parameters(self):
|
||||
obj = libraries.stripe.resource.StripeObject(
|
||||
'foo', 'bar', myparam=5, yourparam='boo')
|
||||
|
||||
self.assertEqual('foo', obj.id)
|
||||
self.assertEqual('bar', obj.api_key)
|
||||
|
||||
def test_access(self):
|
||||
obj = libraries.stripe.resource.StripeObject('myid', 'mykey', myparam=5)
|
||||
|
||||
# Empty
|
||||
self.assertRaises(AttributeError, getattr, obj, 'myattr')
|
||||
self.assertRaises(KeyError, obj.__getitem__, 'myattr')
|
||||
self.assertEqual('def', obj.get('myattr', 'def'))
|
||||
self.assertEqual(None, obj.get('myattr'))
|
||||
|
||||
# Setters
|
||||
obj.myattr = 'myval'
|
||||
obj['myitem'] = 'itval'
|
||||
self.assertEqual('sdef', obj.setdefault('mydef', 'sdef'))
|
||||
|
||||
# Getters
|
||||
self.assertEqual('myval', obj.setdefault('myattr', 'sdef'))
|
||||
self.assertEqual('myval', obj.myattr)
|
||||
self.assertEqual('myval', obj['myattr'])
|
||||
self.assertEqual('myval', obj.get('myattr'))
|
||||
|
||||
self.assertEqual(['id', 'myattr', 'mydef', 'myitem'],
|
||||
sorted(obj.keys()))
|
||||
self.assertEqual(['itval', 'myid', 'myval', 'sdef'],
|
||||
sorted(obj.values()))
|
||||
|
||||
# Illegal operations
|
||||
self.assertRaises(ValueError, setattr, obj, 'foo', '')
|
||||
|
||||
def test_refresh_from(self):
|
||||
obj = libraries.stripe.resource.StripeObject.construct_from({
|
||||
'foo': 'bar',
|
||||
'trans': 'me',
|
||||
}, 'mykey')
|
||||
|
||||
self.assertEqual('mykey', obj.api_key)
|
||||
self.assertEqual('bar', obj.foo)
|
||||
self.assertEqual('me', obj['trans'])
|
||||
self.assertEqual(None, obj.stripe_account)
|
||||
|
||||
obj.refresh_from({
|
||||
'foo': 'baz',
|
||||
'johnny': 5,
|
||||
}, 'key2', stripe_account='acct_foo')
|
||||
|
||||
self.assertEqual(5, obj.johnny)
|
||||
self.assertEqual('baz', obj.foo)
|
||||
self.assertRaises(AttributeError, getattr, obj, 'trans')
|
||||
self.assertEqual('key2', obj.api_key)
|
||||
self.assertEqual('acct_foo', obj.stripe_account)
|
||||
|
||||
obj.refresh_from({
|
||||
'trans': 4,
|
||||
'metadata': {'amount': 42}
|
||||
}, 'key2', True)
|
||||
|
||||
self.assertEqual('baz', obj.foo)
|
||||
self.assertEqual(4, obj.trans)
|
||||
|
||||
def test_passing_nested_refresh(self):
|
||||
obj = libraries.stripe.resource.StripeObject.construct_from({
|
||||
'foos': {
|
||||
'type': 'list',
|
||||
'data': [
|
||||
{'id': 'nested'}
|
||||
],
|
||||
}
|
||||
}, 'key', stripe_account='acct_foo')
|
||||
|
||||
nested = obj.foos.data[0]
|
||||
|
||||
self.assertEqual('key', obj.api_key)
|
||||
self.assertEqual('nested', nested.id)
|
||||
self.assertEqual('key', nested.api_key)
|
||||
self.assertEqual('acct_foo', nested.stripe_account)
|
||||
|
||||
def test_refresh_from_nested_object(self):
|
||||
obj = libraries.stripe.resource.StripeObject.construct_from(
|
||||
SAMPLE_INVOICE, 'key')
|
||||
|
||||
self.assertEqual(1, len(obj.lines.subscriptions))
|
||||
self.assertTrue(
|
||||
isinstance(obj.lines.subscriptions[0],
|
||||
libraries.stripe.resource.StripeObject))
|
||||
self.assertEqual('month', obj.lines.subscriptions[0].plan.interval)
|
||||
|
||||
def test_to_json(self):
|
||||
obj = libraries.stripe.resource.StripeObject.construct_from(
|
||||
SAMPLE_INVOICE, 'key')
|
||||
|
||||
self.check_invoice_data(util.json.loads(str(obj)))
|
||||
|
||||
def check_invoice_data(self, data):
|
||||
# Check rough structure
|
||||
self.assertEqual(20, len(list(data.keys())))
|
||||
self.assertEqual(3, len(list(data['lines'].keys())))
|
||||
self.assertEqual(0, len(data['lines']['invoiceitems']))
|
||||
self.assertEqual(1, len(data['lines']['subscriptions']))
|
||||
|
||||
# Check various data types
|
||||
self.assertEqual(1338238728, data['date'])
|
||||
self.assertEqual(None, data['next_payment_attempt'])
|
||||
self.assertEqual(False, data['livemode'])
|
||||
self.assertEqual('month',
|
||||
data['lines']['subscriptions'][0]['plan']['interval'])
|
||||
|
||||
def test_repr(self):
|
||||
obj = libraries.stripe.resource.StripeObject(
|
||||
'foo', 'bar', myparam=5)
|
||||
|
||||
obj['object'] = '\u4e00boo\u1f00'
|
||||
|
||||
res = repr(obj)
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
res = str(repr(obj), 'utf-8')
|
||||
|
||||
self.assertTrue('<StripeObject \u4e00boo\u1f00' in res)
|
||||
self.assertTrue('id=foo' in res)
|
||||
|
||||
def test_pickling(self):
|
||||
obj = libraries.stripe.resource.StripeObject(
|
||||
'foo', 'bar', myparam=5)
|
||||
|
||||
obj['object'] = 'boo'
|
||||
obj.refresh_from({'fala': 'lalala'}, api_key='bar', partial=True)
|
||||
|
||||
self.assertEqual('lalala', obj.fala)
|
||||
|
||||
pickled = pickle.dumps(obj)
|
||||
newobj = pickle.loads(pickled)
|
||||
|
||||
self.assertEqual('foo', newobj.id)
|
||||
self.assertEqual('bar', newobj.api_key)
|
||||
self.assertEqual('boo', newobj['object'])
|
||||
self.assertEqual('lalala', newobj.fala)
|
||||
|
||||
def test_deletion(self):
|
||||
obj = libraries.stripe.resource.StripeObject('id', 'key')
|
||||
|
||||
obj.coupon = "foo"
|
||||
self.assertEqual('foo', obj.coupon)
|
||||
|
||||
del obj.coupon
|
||||
self.assertRaises(AttributeError, getattr, obj, 'coupon')
|
||||
|
||||
obj.refresh_from({'coupon': 'foo'}, api_key='bar', partial=True)
|
||||
self.assertEqual('foo', obj.coupon)
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
import datetime
|
||||
import time
|
||||
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeResourceTest, DUMMY_PLAN
|
||||
)
|
||||
|
||||
|
||||
class SubscriptionTest(StripeResourceTest):
|
||||
|
||||
def test_list_subscriptions(self):
|
||||
libraries.stripe.Subscription.all(customer="test_cus", plan=DUMMY_PLAN['id'],
|
||||
limit=3)
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/subscriptions',
|
||||
{
|
||||
'customer': 'test_cus',
|
||||
'plan': DUMMY_PLAN['id'],
|
||||
'limit': 3,
|
||||
},
|
||||
)
|
||||
|
||||
def test_retrieve_subscription(self):
|
||||
libraries.stripe.Subscription.retrieve('test_sub')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/subscriptions/test_sub',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_create_subscription(self):
|
||||
libraries.stripe.Subscription.create(customer="test_cus", plan=DUMMY_PLAN['id'])
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/subscriptions',
|
||||
{
|
||||
'customer': 'test_cus',
|
||||
'plan': DUMMY_PLAN['id']
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_update_subscription(self):
|
||||
subscription = libraries.stripe.Subscription.construct_from({
|
||||
'id': 'test_sub',
|
||||
'customer': 'test_cus',
|
||||
}, 'api_key')
|
||||
|
||||
trial_end_dttm = datetime.datetime.now() + datetime.timedelta(days=15)
|
||||
trial_end_int = int(time.mktime(trial_end_dttm.timetuple()))
|
||||
|
||||
subscription.plan = DUMMY_PLAN['id']
|
||||
subscription.trial_end = trial_end_int
|
||||
subscription.save()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/subscriptions/test_sub',
|
||||
{
|
||||
'plan': DUMMY_PLAN['id'],
|
||||
'trial_end': trial_end_int
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_modify_subscription(self):
|
||||
trial_end_dttm = datetime.datetime.now() + datetime.timedelta(days=15)
|
||||
trial_end_int = int(time.mktime(trial_end_dttm.timetuple()))
|
||||
|
||||
libraries.stripe.Subscription.modify('test_sub',
|
||||
plan=DUMMY_PLAN['id'],
|
||||
trial_end=trial_end_int)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/subscriptions/test_sub',
|
||||
{
|
||||
'plan': DUMMY_PLAN['id'],
|
||||
'trial_end': trial_end_int
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_delete_subscription(self):
|
||||
subscription = libraries.stripe.Subscription.construct_from({
|
||||
'id': 'test_sub',
|
||||
'customer': 'test_cus',
|
||||
}, 'api_key')
|
||||
|
||||
subscription.delete()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/subscriptions/test_sub',
|
||||
{},
|
||||
None
|
||||
)
|
||||
|
||||
def test_delete_subscription_discount(self):
|
||||
subscription = libraries.stripe.Subscription.construct_from({
|
||||
'id': 'test_sub',
|
||||
'customer': 'test_cus',
|
||||
'coupon': 'test_discount'
|
||||
}, 'api_key')
|
||||
|
||||
subscription.delete_discount()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'delete',
|
||||
'/v1/subscriptions/test_sub/discount'
|
||||
)
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class ThreeDSecureTest(StripeResourceTest):
|
||||
|
||||
def test_threedsecure_create(self):
|
||||
libraries.stripe.ThreeDSecure.create(
|
||||
card="tok_test",
|
||||
amount=1500,
|
||||
currency="usd",
|
||||
return_url="https://example.org/3d-secure-result"
|
||||
)
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/3d_secure',
|
||||
{
|
||||
'card': 'tok_test',
|
||||
'amount': 1500,
|
||||
'currency': 'usd',
|
||||
'return_url': 'https://example.org/3d-secure-result'
|
||||
},
|
||||
None
|
||||
)
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
import libraries.stripe
|
||||
from libraries.stripe.test.helper import StripeResourceTest
|
||||
|
||||
|
||||
class TransferTest(StripeResourceTest):
|
||||
|
||||
def test_list_transfers(self):
|
||||
libraries.stripe.Transfer.list()
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'get',
|
||||
'/v1/transfers',
|
||||
{}
|
||||
)
|
||||
|
||||
def test_cancel_transfer(self):
|
||||
transfer = libraries.stripe.Transfer(id='tr_cancel')
|
||||
transfer.cancel()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/transfers/tr_cancel/cancel',
|
||||
{},
|
||||
None
|
||||
)
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
from libraries.stripe.test.helper import (
|
||||
StripeApiTestCase, MyUpdateable
|
||||
)
|
||||
|
||||
|
||||
class UpdateableAPIResourceTests(StripeApiTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(UpdateableAPIResourceTests, self).setUp()
|
||||
|
||||
self.mock_response({
|
||||
'thats': 'it'
|
||||
})
|
||||
|
||||
self.obj = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'foo': 'bar',
|
||||
'baz': 'boz',
|
||||
'metadata': {
|
||||
'size': 'l',
|
||||
'score': 4,
|
||||
'height': 10
|
||||
}
|
||||
}, 'mykey')
|
||||
|
||||
def checkSave(self):
|
||||
self.assertTrue(self.obj is self.obj.save())
|
||||
|
||||
self.assertEqual('it', self.obj.thats)
|
||||
# TODO: Should we force id to be retained?
|
||||
# self.assertEqual('myid', obj.id)
|
||||
self.assertRaises(AttributeError, getattr, self.obj, 'baz')
|
||||
|
||||
def test_idempotent_save(self):
|
||||
self.obj.baz = 'updated'
|
||||
self.obj.save(idempotency_key='foo')
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'metadata': {},
|
||||
'baz': 'updated',
|
||||
},
|
||||
{
|
||||
'Idempotency-Key': 'foo',
|
||||
},
|
||||
)
|
||||
|
||||
def test_save(self):
|
||||
self.obj.baz = 'updated'
|
||||
self.obj.other = 'newval'
|
||||
self.obj.metadata.size = 'm'
|
||||
self.obj.metadata.info = 'a2'
|
||||
self.obj.metadata.height = None
|
||||
|
||||
self.checkSave()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'baz': 'updated',
|
||||
'other': 'newval',
|
||||
'metadata': {
|
||||
'size': 'm',
|
||||
'info': 'a2',
|
||||
'height': '',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_add_key_to_nested_object(self):
|
||||
acct = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'legal_entity': {
|
||||
'size': 'l',
|
||||
'score': 4,
|
||||
'height': 10
|
||||
}
|
||||
}, 'mykey')
|
||||
|
||||
acct.legal_entity['first_name'] = 'bob'
|
||||
|
||||
self.assertTrue(acct is acct.save())
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'legal_entity': {
|
||||
'first_name': 'bob',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_save_nothing(self):
|
||||
acct = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'metadata': {
|
||||
'key': 'value',
|
||||
}
|
||||
}, 'mykey')
|
||||
|
||||
self.assertTrue(acct is acct.save())
|
||||
|
||||
# Note: ideally, we'd want the library to NOT issue requests in this
|
||||
# case (i.e. the assert should actually be `assert_not_called()`).
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{'metadata': {}},
|
||||
None
|
||||
)
|
||||
|
||||
def test_replace_nested_object(self):
|
||||
acct = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'legal_entity': {
|
||||
'last_name': 'smith',
|
||||
}
|
||||
}, 'mykey')
|
||||
|
||||
acct.legal_entity = {
|
||||
'first_name': 'bob',
|
||||
}
|
||||
|
||||
self.assertTrue(acct is acct.save())
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'legal_entity': {
|
||||
'first_name': 'bob',
|
||||
'last_name': '',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_array_setting(self):
|
||||
acct = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'legal_entity': {}
|
||||
}, 'mykey')
|
||||
|
||||
acct.legal_entity.additional_owners = [{'first_name': 'Bob'}]
|
||||
|
||||
self.assertTrue(acct is acct.save())
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'legal_entity': {
|
||||
'additional_owners': [
|
||||
{'first_name': 'Bob'}
|
||||
]
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_array_none(self):
|
||||
acct = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'legal_entity': {
|
||||
'additional_owners': None,
|
||||
}
|
||||
}, 'mykey')
|
||||
|
||||
acct.foo = 'bar'
|
||||
|
||||
self.assertTrue(acct is acct.save())
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'foo': 'bar',
|
||||
'legal_entity': {},
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_array_insertion(self):
|
||||
acct = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'legal_entity': {
|
||||
'additional_owners': []
|
||||
}
|
||||
}, 'mykey')
|
||||
|
||||
acct.legal_entity.additional_owners.append({'first_name': 'Bob'})
|
||||
|
||||
self.assertTrue(acct is acct.save())
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'legal_entity': {
|
||||
'additional_owners': {
|
||||
'0': {'first_name': 'Bob'},
|
||||
}
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_array_update(self):
|
||||
acct = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'legal_entity': {
|
||||
'additional_owners': [
|
||||
{'first_name': 'Bob'},
|
||||
{'first_name': 'Jane'}
|
||||
]
|
||||
}
|
||||
}, 'mykey')
|
||||
|
||||
acct.legal_entity.additional_owners[1].first_name = 'Janet'
|
||||
|
||||
self.assertTrue(acct is acct.save())
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'legal_entity': {
|
||||
'additional_owners': {
|
||||
'0': {},
|
||||
'1': {'first_name': 'Janet'}
|
||||
}
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_array_noop(self):
|
||||
acct = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'legal_entity': {
|
||||
'additional_owners': [{'first_name': 'Bob'}]
|
||||
},
|
||||
'currencies_supported': ['usd', 'cad']
|
||||
}, 'mykey')
|
||||
|
||||
self.assertTrue(acct is acct.save())
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'legal_entity': {'additional_owners': {'0': {}}}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_hash_noop(self):
|
||||
acct = MyUpdateable.construct_from({
|
||||
'id': 'myid',
|
||||
'legal_entity': {
|
||||
'address': {'line1': '1 Two Three'}
|
||||
}
|
||||
}, 'mykey')
|
||||
|
||||
self.assertTrue(acct is acct.save())
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{'legal_entity': {'address': {}}},
|
||||
None
|
||||
)
|
||||
|
||||
def test_save_replace_metadata_with_number(self):
|
||||
self.obj.baz = 'updated'
|
||||
self.obj.other = 'newval'
|
||||
self.obj.metadata = 3
|
||||
|
||||
self.checkSave()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'baz': 'updated',
|
||||
'other': 'newval',
|
||||
'metadata': 3,
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_save_overwrite_metadata(self):
|
||||
self.obj.metadata = {}
|
||||
self.checkSave()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'metadata': {
|
||||
'size': '',
|
||||
'score': '',
|
||||
'height': '',
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_save_replace_metadata(self):
|
||||
self.obj.baz = 'updated'
|
||||
self.obj.other = 'newval'
|
||||
self.obj.metadata = {
|
||||
'size': 'm',
|
||||
'info': 'a2',
|
||||
'score': 4,
|
||||
}
|
||||
|
||||
self.checkSave()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'baz': 'updated',
|
||||
'other': 'newval',
|
||||
'metadata': {
|
||||
'size': 'm',
|
||||
'info': 'a2',
|
||||
'height': '',
|
||||
'score': 4,
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
|
||||
def test_save_update_metadata(self):
|
||||
self.obj.baz = 'updated'
|
||||
self.obj.other = 'newval'
|
||||
self.obj.metadata.update({
|
||||
'size': 'm',
|
||||
'info': 'a2',
|
||||
'score': 4,
|
||||
})
|
||||
|
||||
self.checkSave()
|
||||
|
||||
self.requestor_mock.request.assert_called_with(
|
||||
'post',
|
||||
'/v1/myupdateables/myid',
|
||||
{
|
||||
'baz': 'updated',
|
||||
'other': 'newval',
|
||||
'metadata': {
|
||||
'size': 'm',
|
||||
'info': 'a2',
|
||||
'score': 4,
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
|
||||
import unittest2
|
||||
|
||||
from libraries.stripe import StripeError
|
||||
from libraries.stripe.test.helper import StripeUnitTestCase
|
||||
|
||||
|
||||
class StripeErrorTests(StripeUnitTestCase):
|
||||
|
||||
def test_formatting(self):
|
||||
err = StripeError('öre')
|
||||
if sys.version_info > (3, 0):
|
||||
assert str(err) == 'öre'
|
||||
else:
|
||||
assert str(err) == '\xc3\xb6re'
|
||||
assert str(err) == 'öre'
|
||||
|
||||
def test_formatting_with_request_id(self):
|
||||
err = StripeError('öre', headers={'request-id': '123'})
|
||||
if sys.version_info > (3, 0):
|
||||
assert str(err) == 'Request 123: öre'
|
||||
else:
|
||||
assert str(err) == 'Request 123: \xc3\xb6re'
|
||||
assert str(err) == 'Request 123: öre'
|
||||
|
||||
def test_formatting_with_none(self):
|
||||
err = StripeError(None, headers={'request-id': '123'})
|
||||
if sys.version_info > (3, 0):
|
||||
assert str(err) == 'Request 123: <empty message>'
|
||||
else:
|
||||
assert str(err) == 'Request 123: <empty message>'
|
||||
assert str(err) == 'Request 123: <empty message>'
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
Executable
+266
@@ -0,0 +1,266 @@
|
||||
import sys
|
||||
import unittest2
|
||||
|
||||
if 1/2 != 0: str=str
|
||||
|
||||
from mock import Mock, patch
|
||||
|
||||
import libraries.stripe
|
||||
|
||||
from libraries.stripe.test.helper import StripeUnitTestCase
|
||||
|
||||
VALID_API_METHODS = ('get', 'post', 'delete')
|
||||
|
||||
|
||||
class HttpClientTests(StripeUnitTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(HttpClientTests, self).setUp()
|
||||
|
||||
self.original_filters = libraries.stripe.http_client.warnings.filters[:]
|
||||
libraries.stripe.http_client.warnings.simplefilter('ignore')
|
||||
|
||||
def tearDown(self):
|
||||
libraries.stripe.http_client.warnings.filters = self.original_filters
|
||||
|
||||
super(HttpClientTests, self).tearDown()
|
||||
|
||||
def check_default(self, none_libs, expected):
|
||||
for lib in none_libs:
|
||||
setattr(stripe.http_client, lib, None)
|
||||
|
||||
inst = libraries.stripe.http_client.new_default_http_client()
|
||||
|
||||
self.assertTrue(isinstance(inst, expected))
|
||||
|
||||
def test_new_default_http_client_urlfetch(self):
|
||||
self.check_default((),
|
||||
libraries.stripe.http_client.UrlFetchClient)
|
||||
|
||||
def test_new_default_http_client_requests(self):
|
||||
self.check_default(('urlfetch',),
|
||||
libraries.stripe.http_client.RequestsClient)
|
||||
|
||||
def test_new_default_http_client_pycurl(self):
|
||||
self.check_default(('urlfetch', 'requests',),
|
||||
libraries.stripe.http_client.PycurlClient)
|
||||
|
||||
def test_new_default_http_client_urllib2(self):
|
||||
self.check_default(('urlfetch', 'requests', 'pycurl'),
|
||||
libraries.stripe.http_client.Urllib2Client)
|
||||
|
||||
|
||||
class ClientTestBase():
|
||||
|
||||
@property
|
||||
def request_mock(self):
|
||||
return self.request_mocks[self.request_client.name]
|
||||
|
||||
@property
|
||||
def valid_url(self, path='/foo'):
|
||||
return 'https://api.stripe.com%s' % (path,)
|
||||
|
||||
def make_request(self, method, url, headers, post_data):
|
||||
client = self.request_client(verify_ssl_certs=True)
|
||||
return client.request(method, url, headers, post_data)
|
||||
|
||||
def mock_response(self, body, code):
|
||||
raise NotImplementedError(
|
||||
'You must implement this in your test subclass')
|
||||
|
||||
def mock_error(self, error):
|
||||
raise NotImplementedError(
|
||||
'You must implement this in your test subclass')
|
||||
|
||||
def check_call(self, meth, abs_url, headers, params):
|
||||
raise NotImplementedError(
|
||||
'You must implement this in your test subclass')
|
||||
|
||||
def test_request(self):
|
||||
self.mock_response(self.request_mock, '{"foo": "baz"}', 200)
|
||||
|
||||
for meth in VALID_API_METHODS:
|
||||
abs_url = self.valid_url
|
||||
data = ''
|
||||
|
||||
if meth != 'post':
|
||||
abs_url = '%s?%s' % (abs_url, data)
|
||||
data = None
|
||||
|
||||
headers = {'my-header': 'header val'}
|
||||
|
||||
body, code, _ = self.make_request(
|
||||
meth, abs_url, headers, data)
|
||||
|
||||
self.assertEqual(200, code)
|
||||
self.assertEqual('{"foo": "baz"}', body)
|
||||
|
||||
self.check_call(self.request_mock, meth, abs_url,
|
||||
data, headers)
|
||||
|
||||
def test_exception(self):
|
||||
self.mock_error(self.request_mock)
|
||||
self.assertRaises(stripe.error.APIConnectionError,
|
||||
self.make_request,
|
||||
'get', self.valid_url, {}, None)
|
||||
|
||||
|
||||
class RequestsVerify(object):
|
||||
|
||||
def __eq__(self, other):
|
||||
return other and other.endswith('stripe/data/ca-certificates.crt')
|
||||
|
||||
|
||||
class RequestsClientTests(StripeUnitTestCase, ClientTestBase):
|
||||
request_client = libraries.stripe.http_client.RequestsClient
|
||||
|
||||
def mock_response(self, mock, body, code):
|
||||
result = Mock()
|
||||
result.content = body
|
||||
result.status_code = code
|
||||
|
||||
mock.request = Mock(return_value=result)
|
||||
|
||||
def mock_error(self, mock):
|
||||
mock.exceptions.RequestException = Exception
|
||||
mock.request.side_effect = mock.exceptions.RequestException()
|
||||
|
||||
def check_call(self, mock, meth, url, post_data, headers):
|
||||
mock.request.assert_called_with(meth, url,
|
||||
headers=headers,
|
||||
data=post_data,
|
||||
verify=RequestsVerify(),
|
||||
timeout=80)
|
||||
|
||||
|
||||
class UrlFetchClientTests(StripeUnitTestCase, ClientTestBase):
|
||||
request_client = libraries.stripe.http_client.UrlFetchClient
|
||||
|
||||
def mock_response(self, mock, body, code):
|
||||
result = Mock()
|
||||
result.content = body
|
||||
result.status_code = code
|
||||
|
||||
mock.fetch = Mock(return_value=result)
|
||||
|
||||
def mock_error(self, mock):
|
||||
mock.Error = mock.InvalidURLError = Exception
|
||||
mock.fetch.side_effect = mock.InvalidURLError()
|
||||
|
||||
def check_call(self, mock, meth, url, post_data, headers):
|
||||
mock.fetch.assert_called_with(
|
||||
url=url,
|
||||
method=meth,
|
||||
headers=headers,
|
||||
validate_certificate=True,
|
||||
deadline=55,
|
||||
payload=post_data
|
||||
)
|
||||
|
||||
|
||||
class Urllib2ClientTests(StripeUnitTestCase, ClientTestBase):
|
||||
request_client = libraries.stripe.http_client.Urllib2Client
|
||||
|
||||
def mock_response(self, mock, body, code):
|
||||
response = Mock
|
||||
response.read = Mock(return_value=body)
|
||||
response.code = code
|
||||
response.info = Mock(return_value={})
|
||||
|
||||
self.request_object = Mock()
|
||||
mock.Request = Mock(return_value=self.request_object)
|
||||
|
||||
mock.urlopen = Mock(return_value=response)
|
||||
|
||||
def mock_error(self, mock):
|
||||
mock.urlopen.side_effect = ValueError
|
||||
|
||||
def check_call(self, mock, meth, url, post_data, headers):
|
||||
if sys.version_info >= (3, 0) and isinstance(post_data, str):
|
||||
post_data = post_data.encode('utf-8')
|
||||
|
||||
mock.Request.assert_called_with(url, post_data, headers)
|
||||
mock.urlopen.assert_called_with(self.request_object)
|
||||
|
||||
|
||||
class PycurlClientTests(StripeUnitTestCase, ClientTestBase):
|
||||
request_client = libraries.stripe.http_client.PycurlClient
|
||||
|
||||
@property
|
||||
def request_mock(self):
|
||||
if not hasattr(self, 'curl_mock'):
|
||||
lib_mock = self.request_mocks[self.request_client.name]
|
||||
|
||||
self.curl_mock = Mock()
|
||||
|
||||
lib_mock.Curl = Mock(return_value=self.curl_mock)
|
||||
|
||||
return self.curl_mock
|
||||
|
||||
def setUp(self):
|
||||
super(PycurlClientTests, self).setUp()
|
||||
|
||||
self.sio_patcher = patch('stripe.util.StringIO.StringIO')
|
||||
|
||||
sio_mock = Mock()
|
||||
self.sio_patcher.start().return_value = sio_mock
|
||||
self.sio_getvalue = sio_mock.getvalue
|
||||
|
||||
def tearDown(self):
|
||||
super(PycurlClientTests, self).tearDown()
|
||||
|
||||
self.sio_patcher.stop()
|
||||
|
||||
def mock_response(self, mock, body, code):
|
||||
self.sio_getvalue.return_value = body
|
||||
|
||||
mock.getinfo.return_value = code
|
||||
|
||||
def mock_error(self, mock):
|
||||
class FakeException(BaseException):
|
||||
|
||||
def __getitem__(self, i):
|
||||
return 'foo'
|
||||
|
||||
libraries.stripe.http_client.pycurl.error = FakeException
|
||||
mock.perform.side_effect = libraries.stripe.http_client.pycurl.error
|
||||
|
||||
def check_call(self, mock, meth, url, post_data, headers):
|
||||
# TODO: Check the setopt calls
|
||||
pass
|
||||
|
||||
|
||||
class APIEncodeTest(StripeUnitTestCase):
|
||||
|
||||
def test_encode_dict(self):
|
||||
body = {
|
||||
'foo': {
|
||||
'dob': {
|
||||
'month': 1,
|
||||
},
|
||||
'name': 'bat'
|
||||
},
|
||||
}
|
||||
|
||||
values = [t for t in libraries.stripe.api_requestor._api_encode(body)]
|
||||
|
||||
self.assertTrue(('foo[dob][month]', 1) in values)
|
||||
self.assertTrue(('foo[name]', 'bat') in values)
|
||||
|
||||
def test_encode_array(self):
|
||||
body = {
|
||||
'foo': [{
|
||||
'dob': {
|
||||
'month': 1,
|
||||
},
|
||||
'name': 'bat'
|
||||
}],
|
||||
}
|
||||
|
||||
values = [t for t in libraries.stripe.api_requestor._api_encode(body)]
|
||||
|
||||
self.assertTrue(('foo[][dob][month]', 1) in values)
|
||||
self.assertTrue(('foo[][name]', 'bat') in values)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
Executable
+178
@@ -0,0 +1,178 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import unittest2
|
||||
import libraries.stripe
|
||||
|
||||
if 1/2 != 0: str=str
|
||||
|
||||
from mock import patch
|
||||
from libraries.stripe.test.helper import (StripeTestCase, NOW, DUMMY_CHARGE, DUMMY_CARD)
|
||||
|
||||
|
||||
class FunctionalTests(StripeTestCase):
|
||||
request_client = libraries.stripe.http_client.Urllib2Client
|
||||
|
||||
def setUp(self):
|
||||
super(FunctionalTests, self).setUp()
|
||||
|
||||
def get_http_client(*args, **kwargs):
|
||||
return self.request_client(*args, **kwargs)
|
||||
|
||||
self.client_patcher = patch(
|
||||
'stripe.http_client.new_default_http_client')
|
||||
|
||||
client_mock = self.client_patcher.start()
|
||||
client_mock.side_effect = get_http_client
|
||||
|
||||
def tearDown(self):
|
||||
super(FunctionalTests, self).tearDown()
|
||||
|
||||
self.client_patcher.stop()
|
||||
|
||||
def test_dns_failure(self):
|
||||
api_base = libraries.stripe.api_base
|
||||
try:
|
||||
libraries.stripe.api_base = 'https://my-invalid-domain.ireallywontresolve/v1'
|
||||
self.assertRaises(stripe.error.APIConnectionError,
|
||||
libraries.stripe.Customer.create)
|
||||
finally:
|
||||
libraries.stripe.api_base = api_base
|
||||
|
||||
def test_run(self):
|
||||
charge = libraries.stripe.Charge.create(**DUMMY_CHARGE)
|
||||
self.assertFalse(charge.refunded)
|
||||
charge.refund()
|
||||
self.assertTrue(charge.refunded)
|
||||
|
||||
def test_refresh(self):
|
||||
charge = libraries.stripe.Charge.create(**DUMMY_CHARGE)
|
||||
charge2 = libraries.stripe.Charge.retrieve(charge.id)
|
||||
self.assertEqual(charge2.created, charge.created)
|
||||
|
||||
charge2.junk = 'junk'
|
||||
charge2.refresh()
|
||||
self.assertRaises(AttributeError, lambda: charge2.junk)
|
||||
|
||||
def test_list_accessors(self):
|
||||
customer = libraries.stripe.Customer.create(card=DUMMY_CARD)
|
||||
self.assertEqual(customer['created'], customer.created)
|
||||
customer['foo'] = 'bar'
|
||||
self.assertEqual(customer.foo, 'bar')
|
||||
|
||||
def test_raise(self):
|
||||
EXPIRED_CARD = DUMMY_CARD.copy()
|
||||
EXPIRED_CARD['exp_month'] = NOW.month - 2
|
||||
EXPIRED_CARD['exp_year'] = NOW.year - 2
|
||||
self.assertRaises(stripe.error.CardError, libraries.stripe.Charge.create,
|
||||
amount=100, currency='usd', card=EXPIRED_CARD)
|
||||
|
||||
def test_response_headers(self):
|
||||
EXPIRED_CARD = DUMMY_CARD.copy()
|
||||
EXPIRED_CARD['exp_month'] = NOW.month - 2
|
||||
EXPIRED_CARD['exp_year'] = NOW.year - 2
|
||||
try:
|
||||
libraries.stripe.Charge.create(amount=100, currency='usd', card=EXPIRED_CARD)
|
||||
self.fail('charge creation with expired card did not fail')
|
||||
except libraries.stripe.error.CardError as e:
|
||||
self.assertTrue(e.request_id.startswith('req_'))
|
||||
|
||||
def test_unicode(self):
|
||||
# Make sure unicode requests can be sent
|
||||
self.assertRaises(stripe.error.InvalidRequestError,
|
||||
libraries.stripe.Charge.retrieve,
|
||||
id='☃')
|
||||
|
||||
def test_none_values(self):
|
||||
customer = libraries.stripe.Customer.create(plan=None)
|
||||
self.assertTrue(customer.id)
|
||||
|
||||
def test_missing_id(self):
|
||||
customer = libraries.stripe.Customer()
|
||||
self.assertRaises(stripe.error.InvalidRequestError, customer.refresh)
|
||||
|
||||
|
||||
class RequestsFunctionalTests(FunctionalTests):
|
||||
request_client = libraries.stripe.http_client.RequestsClient
|
||||
|
||||
|
||||
class UrlfetchFunctionalTests(FunctionalTests):
|
||||
request_client = 'urlfetch'
|
||||
|
||||
def setUp(self):
|
||||
if libraries.stripe.http_client.urlfetch is None:
|
||||
self.skipTest(
|
||||
'`urlfetch` from Google App Engine is unavailable.')
|
||||
else:
|
||||
super(UrlfetchFunctionalTests, self).setUp()
|
||||
|
||||
|
||||
class PycurlFunctionalTests(FunctionalTests):
|
||||
|
||||
def setUp(self):
|
||||
if not os.environ.get('STRIPE_TEST_PYCURL'):
|
||||
self.skipTest('Pycurl skipped as STRIPE_TEST_PYCURL is not set')
|
||||
if sys.version_info >= (3, 0):
|
||||
self.skipTest('Pycurl is not supported in Python 3')
|
||||
else:
|
||||
super(PycurlFunctionalTests, self).setUp()
|
||||
|
||||
request_client = libraries.stripe.http_client.PycurlClient
|
||||
|
||||
|
||||
class AuthenticationErrorTest(StripeTestCase):
|
||||
|
||||
def test_invalid_credentials(self):
|
||||
key = libraries.stripe.api_key
|
||||
try:
|
||||
libraries.stripe.api_key = 'invalid'
|
||||
libraries.stripe.Customer.create()
|
||||
except libraries.stripe.error.AuthenticationError as e:
|
||||
self.assertEqual(401, e.http_status)
|
||||
self.assertTrue(isinstance(e.http_body, str))
|
||||
self.assertTrue(isinstance(e.json_body, dict))
|
||||
# Note that an invalid API key bypasses many of the standard
|
||||
# facilities in the API server so currently no Request ID is
|
||||
# returned.
|
||||
finally:
|
||||
libraries.stripe.api_key = key
|
||||
|
||||
|
||||
class CardErrorTest(StripeTestCase):
|
||||
|
||||
def test_declined_card_props(self):
|
||||
EXPIRED_CARD = DUMMY_CARD.copy()
|
||||
EXPIRED_CARD['exp_month'] = NOW.month - 2
|
||||
EXPIRED_CARD['exp_year'] = NOW.year - 2
|
||||
try:
|
||||
libraries.stripe.Charge.create(amount=100, currency='usd', card=EXPIRED_CARD)
|
||||
except libraries.stripe.error.CardError as e:
|
||||
self.assertEqual(402, e.http_status)
|
||||
self.assertTrue(isinstance(e.http_body, str))
|
||||
self.assertTrue(isinstance(e.json_body, dict))
|
||||
self.assertTrue(e.request_id.startswith('req_'))
|
||||
|
||||
|
||||
class InvalidRequestErrorTest(StripeTestCase):
|
||||
|
||||
def test_nonexistent_object(self):
|
||||
try:
|
||||
libraries.stripe.Charge.retrieve('invalid')
|
||||
except libraries.stripe.error.InvalidRequestError as e:
|
||||
self.assertEqual(404, e.http_status)
|
||||
self.assertTrue(isinstance(e.http_body, str))
|
||||
self.assertTrue(isinstance(e.json_body, dict))
|
||||
self.assertTrue(e.request_id.startswith('req_'))
|
||||
|
||||
def test_invalid_data(self):
|
||||
try:
|
||||
libraries.stripe.Charge.create()
|
||||
except libraries.stripe.error.InvalidRequestError as e:
|
||||
self.assertEqual(400, e.http_status)
|
||||
self.assertTrue(isinstance(e.http_body, str))
|
||||
self.assertTrue(isinstance(e.json_body, dict))
|
||||
self.assertTrue(e.request_id.startswith('req_'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
from libraries.stripe.multipart_data_generator import MultipartDataGenerator
|
||||
from libraries.stripe.test.helper import StripeTestCase
|
||||
|
||||
|
||||
class MultipartDataGeneratorTests(StripeTestCase):
|
||||
|
||||
def run_test_multipart_data_with_file(self, test_file):
|
||||
params = {
|
||||
"key1": b"ASCII value",
|
||||
"key2": "Üñìçôdé value",
|
||||
"key3": test_file
|
||||
}
|
||||
generator = MultipartDataGenerator()
|
||||
generator.add_params(params)
|
||||
http_body = generator.get_post_data()
|
||||
|
||||
if sys.version_info >= (3,):
|
||||
http_body = http_body.decode('utf-8')
|
||||
|
||||
self.assertTrue(re.search(
|
||||
r"Content-Disposition: form-data; name=\"key1\"", http_body))
|
||||
self.assertTrue(re.search(r"ASCII value", http_body))
|
||||
self.assertTrue(re.search(
|
||||
r"Content-Disposition: form-data; name=\"key2\"", http_body))
|
||||
self.assertTrue(re.search(r"Üñìçôdé value", http_body))
|
||||
self.assertTrue(re.search(
|
||||
r"Content-Disposition: form-data; name=\"key3\"; "
|
||||
r"filename=\".+\"",
|
||||
http_body))
|
||||
self.assertTrue(re.search(
|
||||
r"Content-Type: application/octet-stream", http_body))
|
||||
|
||||
test_file.seek(0)
|
||||
file_contents = test_file.read()
|
||||
|
||||
if sys.version_info >= (3,) and isinstance(file_contents, bytes):
|
||||
file_contents = file_contents.decode('utf-8')
|
||||
|
||||
self.assertNotEqual(-1, http_body.find(file_contents))
|
||||
|
||||
def test_multipart_data_file_text(self):
|
||||
with open(__file__, mode='r') as test_file:
|
||||
self.run_test_multipart_data_with_file(test_file)
|
||||
|
||||
def test_multipart_data_file_binary(self):
|
||||
with open(__file__, mode='rb') as test_file:
|
||||
self.run_test_multipart_data_with_file(test_file)
|
||||
Executable
+417
@@ -0,0 +1,417 @@
|
||||
import datetime
|
||||
import unittest2
|
||||
import urllib.parse
|
||||
|
||||
from mock import Mock, ANY
|
||||
|
||||
import libraries.stripe
|
||||
|
||||
from libraries.stripe.test.helper import StripeUnitTestCase
|
||||
|
||||
VALID_API_METHODS = ('get', 'post', 'delete')
|
||||
|
||||
|
||||
class GMT1(datetime.tzinfo):
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return datetime.timedelta(hours=1)
|
||||
|
||||
def dst(self, dt):
|
||||
return datetime.timedelta(0)
|
||||
|
||||
def tzname(self, dt):
|
||||
return "Europe/Prague"
|
||||
|
||||
|
||||
class APIHeaderMatcher(object):
|
||||
EXP_KEYS = ['X-Stripe-Client-User-Agent', 'User-Agent', 'Authorization']
|
||||
METHOD_EXTRA_KEYS = {"post": ["Content-Type"]}
|
||||
|
||||
def __init__(self, api_key=None, extra={}, request_method=None):
|
||||
self.request_method = request_method
|
||||
self.api_key = api_key or libraries.stripe.api_key
|
||||
self.extra = extra
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self._keys_match(other) and
|
||||
self._auth_match(other) and
|
||||
self._extra_match(other))
|
||||
|
||||
def _keys_match(self, other):
|
||||
expected_keys = self.EXP_KEYS + list(self.extra.keys())
|
||||
if self.request_method is not None and self.request_method in \
|
||||
self.METHOD_EXTRA_KEYS:
|
||||
expected_keys.extend(self.METHOD_EXTRA_KEYS[self.request_method])
|
||||
|
||||
return (sorted(other.keys()) == sorted(expected_keys))
|
||||
|
||||
def _auth_match(self, other):
|
||||
return other['Authorization'] == "Bearer %s" % (self.api_key,)
|
||||
|
||||
def _extra_match(self, other):
|
||||
for k, v in self.extra.items():
|
||||
if other[k] != v:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class QueryMatcher(object):
|
||||
|
||||
def __init__(self, expected):
|
||||
self.expected = sorted(expected)
|
||||
|
||||
def __eq__(self, other):
|
||||
query = urllib.parse.urlsplit(other).query or other
|
||||
|
||||
parsed = libraries.stripe.util.parse_qsl(query)
|
||||
return self.expected == sorted(parsed)
|
||||
|
||||
|
||||
class UrlMatcher(object):
|
||||
|
||||
def __init__(self, expected):
|
||||
self.exp_parts = urllib.parse.urlsplit(expected)
|
||||
|
||||
def __eq__(self, other):
|
||||
other_parts = urllib.parse.urlsplit(other)
|
||||
|
||||
for part in ('scheme', 'netloc', 'path', 'fragment'):
|
||||
expected = getattr(self.exp_parts, part)
|
||||
actual = getattr(other_parts, part)
|
||||
if expected != actual:
|
||||
print('Expected %s "%s" but got "%s"' % (
|
||||
part, expected, actual))
|
||||
return False
|
||||
|
||||
q_matcher = QueryMatcher(stripe.util.parse_qsl(self.exp_parts.query))
|
||||
return q_matcher == other
|
||||
|
||||
|
||||
class APIRequestorRequestTests(StripeUnitTestCase):
|
||||
ENCODE_INPUTS = {
|
||||
'dict': {
|
||||
'astring': 'bar',
|
||||
'anint': 5,
|
||||
'anull': None,
|
||||
'adatetime': datetime.datetime(2013, 1, 1, tzinfo=GMT1()),
|
||||
'atuple': (1, 2),
|
||||
'adict': {'foo': 'bar', 'boz': 5},
|
||||
'alist': ['foo', 'bar'],
|
||||
},
|
||||
'list': [1, 'foo', 'baz'],
|
||||
'string': 'boo',
|
||||
'unicode': '\u1234',
|
||||
'datetime': datetime.datetime(2013, 1, 1, second=1, tzinfo=GMT1()),
|
||||
'none': None,
|
||||
}
|
||||
|
||||
ENCODE_EXPECTATIONS = {
|
||||
'dict': [
|
||||
('%s[astring]', 'bar'),
|
||||
('%s[anint]', 5),
|
||||
('%s[adatetime]', 1356994800),
|
||||
('%s[adict][foo]', 'bar'),
|
||||
('%s[adict][boz]', 5),
|
||||
('%s[alist][]', 'foo'),
|
||||
('%s[alist][]', 'bar'),
|
||||
('%s[atuple][]', 1),
|
||||
('%s[atuple][]', 2),
|
||||
],
|
||||
'list': [
|
||||
('%s[]', 1),
|
||||
('%s[]', 'foo'),
|
||||
('%s[]', 'baz'),
|
||||
],
|
||||
'string': [('%s', 'boo')],
|
||||
'unicode': [('%s', libraries.stripe.util.utf8('\u1234'))],
|
||||
'datetime': [('%s', 1356994801)],
|
||||
'none': [],
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
super(APIRequestorRequestTests, self).setUp()
|
||||
|
||||
self.http_client = Mock(stripe.http_client.HTTPClient)
|
||||
self.http_client._verify_ssl_certs = True
|
||||
self.http_client.name = 'mockclient'
|
||||
|
||||
self.requestor = libraries.stripe.api_requestor.APIRequestor(
|
||||
client=self.http_client)
|
||||
|
||||
def mock_response(self, return_body, return_code, requestor=None,
|
||||
headers=None):
|
||||
if not requestor:
|
||||
requestor = self.requestor
|
||||
|
||||
self.http_client.request = Mock(
|
||||
return_value=(return_body, return_code, headers or {}))
|
||||
|
||||
def check_call(self, meth, abs_url=None, headers=None,
|
||||
post_data=None, requestor=None):
|
||||
if not abs_url:
|
||||
abs_url = 'https://api.stripe.com%s' % (self.valid_path,)
|
||||
if not requestor:
|
||||
requestor = self.requestor
|
||||
if not headers:
|
||||
headers = APIHeaderMatcher(request_method=meth)
|
||||
|
||||
self.http_client.request.assert_called_with(
|
||||
meth, abs_url, headers, post_data)
|
||||
|
||||
@property
|
||||
def valid_path(self):
|
||||
return '/foo'
|
||||
|
||||
def encoder_check(self, key):
|
||||
stk_key = "my%s" % (key,)
|
||||
|
||||
value = self.ENCODE_INPUTS[key]
|
||||
expectation = [(k % (stk_key,), v) for k, v in
|
||||
self.ENCODE_EXPECTATIONS[key]]
|
||||
|
||||
stk = []
|
||||
fn = getattr(stripe.api_requestor.APIRequestor, "encode_%s" % (key,))
|
||||
fn(stk, stk_key, value)
|
||||
|
||||
if isinstance(value, dict):
|
||||
expectation.sort()
|
||||
stk.sort()
|
||||
|
||||
self.assertEqual(expectation, stk)
|
||||
|
||||
def _test_encode_naive_datetime(self):
|
||||
stk = []
|
||||
|
||||
libraries.stripe.api_requestor.APIRequestor.encode_datetime(
|
||||
stk, 'test', datetime.datetime(2013, 1, 1))
|
||||
|
||||
# Naive datetimes will encode differently depending on your system
|
||||
# local time. Since we don't know the local time of your system,
|
||||
# we just check that naive encodings are within 24 hours of correct.
|
||||
self.assertTrue(60 * 60 * 24 > abs(stk[0][1] - 1356994800))
|
||||
|
||||
def test_param_encoding(self):
|
||||
self.mock_response('{}', 200)
|
||||
|
||||
self.requestor.request('get', '', self.ENCODE_INPUTS)
|
||||
|
||||
expectation = []
|
||||
for type_, values in self.ENCODE_EXPECTATIONS.items():
|
||||
expectation.extend([(k % (type_,), str(v)) for k, v in values])
|
||||
|
||||
self.check_call('get', QueryMatcher(expectation))
|
||||
|
||||
def test_dictionary_list_encoding(self):
|
||||
params = {
|
||||
'foo': {
|
||||
'0': {
|
||||
'bar': 'bat',
|
||||
}
|
||||
}
|
||||
}
|
||||
encoded = list(stripe.api_requestor._api_encode(params))
|
||||
key, value = encoded[0]
|
||||
|
||||
self.assertEqual('foo[0][bar]', key)
|
||||
self.assertEqual('bat', value)
|
||||
|
||||
def test_url_construction(self):
|
||||
CASES = (
|
||||
('https://api.stripe.com?foo=bar', '', {'foo': 'bar'}),
|
||||
('https://api.stripe.com?foo=bar', '?', {'foo': 'bar'}),
|
||||
('https://api.stripe.com', '', {}),
|
||||
(
|
||||
'https://api.stripe.com/%20spaced?foo=bar%24&baz=5',
|
||||
'/%20spaced?foo=bar%24',
|
||||
{'baz': '5'}
|
||||
),
|
||||
(
|
||||
'https://api.stripe.com?foo=bar&foo=bar',
|
||||
'?foo=bar',
|
||||
{'foo': 'bar'}
|
||||
),
|
||||
)
|
||||
|
||||
for expected, url, params in CASES:
|
||||
self.mock_response('{}', 200)
|
||||
|
||||
self.requestor.request('get', url, params)
|
||||
|
||||
self.check_call('get', expected)
|
||||
|
||||
def test_empty_methods(self):
|
||||
for meth in VALID_API_METHODS:
|
||||
self.mock_response('{}', 200)
|
||||
|
||||
body, key = self.requestor.request(meth, self.valid_path, {})
|
||||
|
||||
if meth == 'post':
|
||||
post_data = ''
|
||||
else:
|
||||
post_data = None
|
||||
|
||||
self.check_call(meth, post_data=post_data)
|
||||
self.assertEqual({}, body)
|
||||
|
||||
def test_methods_with_params_and_response(self):
|
||||
for meth in VALID_API_METHODS:
|
||||
self.mock_response('{"foo": "bar", "baz": 6}', 200)
|
||||
|
||||
params = {
|
||||
'alist': [1, 2, 3],
|
||||
'adict': {'frobble': 'bits'},
|
||||
'adatetime': datetime.datetime(2013, 1, 1, tzinfo=GMT1())
|
||||
}
|
||||
encoded = ('adict%5Bfrobble%5D=bits&adatetime=1356994800&'
|
||||
'alist%5B%5D=1&alist%5B%5D=2&alist%5B%5D=3')
|
||||
|
||||
body, key = self.requestor.request(meth, self.valid_path,
|
||||
params)
|
||||
self.assertEqual({'foo': 'bar', 'baz': 6}, body)
|
||||
|
||||
if meth == 'post':
|
||||
self.check_call(
|
||||
meth,
|
||||
post_data=QueryMatcher(stripe.util.parse_qsl(encoded)))
|
||||
else:
|
||||
abs_url = "https://api.stripe.com%s?%s" % (
|
||||
self.valid_path, encoded)
|
||||
self.check_call(meth, abs_url=UrlMatcher(abs_url))
|
||||
|
||||
def test_uses_headers(self):
|
||||
self.mock_response('{}', 200)
|
||||
self.requestor.request('get', self.valid_path, {}, {'foo': 'bar'})
|
||||
self.check_call('get', headers=APIHeaderMatcher(extra={'foo': 'bar'}))
|
||||
|
||||
def test_uses_instance_key(self):
|
||||
key = 'fookey'
|
||||
requestor = libraries.stripe.api_requestor.APIRequestor(key,
|
||||
client=self.http_client)
|
||||
|
||||
self.mock_response('{}', 200, requestor=requestor)
|
||||
|
||||
body, used_key = requestor.request('get', self.valid_path, {})
|
||||
|
||||
self.check_call('get', headers=APIHeaderMatcher(
|
||||
key, request_method='get'), requestor=requestor)
|
||||
self.assertEqual(key, used_key)
|
||||
|
||||
def test_passes_api_version(self):
|
||||
libraries.stripe.api_version = 'fooversion'
|
||||
|
||||
self.mock_response('{}', 200)
|
||||
|
||||
body, key = self.requestor.request('get', self.valid_path, {})
|
||||
|
||||
self.check_call('get', headers=APIHeaderMatcher(
|
||||
extra={'Stripe-Version': 'fooversion'}, request_method='get'))
|
||||
|
||||
def test_uses_instance_account(self):
|
||||
account = 'acct_foo'
|
||||
requestor = libraries.stripe.api_requestor.APIRequestor(account=account,
|
||||
client=self.http_client)
|
||||
|
||||
self.mock_response('{}', 200, requestor=requestor)
|
||||
|
||||
requestor.request('get', self.valid_path, {})
|
||||
|
||||
self.check_call(
|
||||
'get',
|
||||
requestor=requestor,
|
||||
headers=APIHeaderMatcher(
|
||||
extra={'Stripe-Account': account},
|
||||
request_method='get'
|
||||
),
|
||||
)
|
||||
|
||||
def test_fails_without_api_key(self):
|
||||
libraries.stripe.api_key = None
|
||||
|
||||
self.assertRaises(stripe.error.AuthenticationError,
|
||||
self.requestor.request,
|
||||
'get', self.valid_path, {})
|
||||
|
||||
def test_not_found(self):
|
||||
self.mock_response('{"error": {}}', 404)
|
||||
|
||||
self.assertRaises(stripe.error.InvalidRequestError,
|
||||
self.requestor.request,
|
||||
'get', self.valid_path, {})
|
||||
|
||||
def test_authentication_error(self):
|
||||
self.mock_response('{"error": {}}', 401)
|
||||
|
||||
self.assertRaises(stripe.error.AuthenticationError,
|
||||
self.requestor.request,
|
||||
'get', self.valid_path, {})
|
||||
|
||||
def test_card_error(self):
|
||||
self.mock_response('{"error": {}}', 402)
|
||||
|
||||
self.assertRaises(stripe.error.CardError,
|
||||
self.requestor.request,
|
||||
'get', self.valid_path, {})
|
||||
|
||||
def test_rate_limit_error(self):
|
||||
self.mock_response('{"error": {}}', 429)
|
||||
|
||||
self.assertRaises(stripe.error.RateLimitError,
|
||||
self.requestor.request,
|
||||
'get', self.valid_path, {})
|
||||
|
||||
def test_old_rate_limit_error(self):
|
||||
"""
|
||||
Tests legacy rate limit error pre-2015-09-18
|
||||
"""
|
||||
self.mock_response('{"error": {"code":"rate_limit"}}', 400)
|
||||
|
||||
self.assertRaises(stripe.error.RateLimitError,
|
||||
self.requestor.request,
|
||||
'get', self.valid_path, {})
|
||||
|
||||
def test_server_error(self):
|
||||
self.mock_response('{"error": {}}', 500)
|
||||
|
||||
self.assertRaises(stripe.error.APIError,
|
||||
self.requestor.request,
|
||||
'get', self.valid_path, {})
|
||||
|
||||
def test_invalid_json(self):
|
||||
self.mock_response('{', 200)
|
||||
|
||||
self.assertRaises(stripe.error.APIError,
|
||||
self.requestor.request,
|
||||
'get', self.valid_path, {})
|
||||
|
||||
def test_invalid_method(self):
|
||||
self.assertRaises(stripe.error.APIConnectionError,
|
||||
self.requestor.request,
|
||||
'foo', 'bar')
|
||||
|
||||
|
||||
class DefaultClientTests(unittest2.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
libraries.stripe.default_http_client = None
|
||||
libraries.stripe.api_key = 'foo'
|
||||
|
||||
def test_default_http_client_called(self):
|
||||
hc = Mock(stripe.http_client.HTTPClient)
|
||||
hc._verify_ssl_certs = True
|
||||
hc.name = 'mockclient'
|
||||
hc.request = Mock(return_value=("{}", 200, {}))
|
||||
|
||||
libraries.stripe.default_http_client = hc
|
||||
libraries.stripe.Charge.list(limit=3)
|
||||
|
||||
hc.request.assert_called_with(
|
||||
'get', 'https://api.stripe.com/v1/charges?limit=3', ANY, None)
|
||||
|
||||
def tearDown(self):
|
||||
libraries.stripe.api_key = None
|
||||
libraries.stripe.default_http_client = None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
|
||||
logger = logging.getLogger('stripe')
|
||||
|
||||
__all__ = ['StringIO', 'parse_qsl', 'json', 'utf8']
|
||||
|
||||
try:
|
||||
# When cStringIO is available
|
||||
import io as StringIO
|
||||
except ImportError:
|
||||
try:
|
||||
import io
|
||||
except:
|
||||
from io import StringIO #for Python 3
|
||||
|
||||
try:
|
||||
from urllib.parse import parse_qsl
|
||||
except ImportError:
|
||||
# Python < 2.6
|
||||
try:
|
||||
from cgi import parse_qsl
|
||||
except:
|
||||
from urllib.parse import parse_qsl #for Python 3
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
json = None
|
||||
|
||||
if not (json and hasattr(json, 'loads')):
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
if not json:
|
||||
raise ImportError(
|
||||
"Stripe requires a JSON library, such as simplejson. "
|
||||
"HINT: Try installing the "
|
||||
"python simplejson library via 'pip install simplejson' or "
|
||||
"'easy_install simplejson', or contact support@stripe.com "
|
||||
"with questions.")
|
||||
else:
|
||||
raise ImportError(
|
||||
"Stripe requires a JSON library with the same interface as "
|
||||
"the Python 2.6 'json' library. You appear to have a 'json' "
|
||||
"library with a different interface. Please install "
|
||||
"the simplejson library. HINT: Try installing the "
|
||||
"python simplejson library via 'pip install simplejson' "
|
||||
"or 'easy_install simplejson', or contact support@stripe.com"
|
||||
"with questions.")
|
||||
|
||||
|
||||
def utf8(value):
|
||||
if isinstance(value, str) and sys.version_info < (3, 0):
|
||||
return value.encode('utf-8')
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def is_appengine_dev():
|
||||
return ('APPENGINE_RUNTIME' in os.environ and
|
||||
'Dev' in os.environ.get('SERVER_SOFTWARE', ''))
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
VERSION = '1.37.0'
|
||||
@@ -1,504 +1,373 @@
|
||||
from config import *
|
||||
from functions import *
|
||||
from admin import CommunityMapEditor,ArtistMapEditor,Selector,Items
|
||||
from api import load_code_api
|
||||
from api import *
|
||||
from admin import *
|
||||
from crons import *
|
||||
from tests import *
|
||||
from tasks import *
|
||||
|
||||
class MainHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,name):
|
||||
domain=gdi(self)
|
||||
if 0 and "treasurehunter" in name:
|
||||
whtml(self,"examples/learningPixi/treasure_hunter.html")
|
||||
elif "runner" in name:
|
||||
whtml(self,"htmls/runner.html",domain=domain)
|
||||
elif "executor" in name:
|
||||
whtml(self,"htmls/executor.html",domain=domain)
|
||||
elif name=="info/cookies":
|
||||
self.response.out.write(repr(self.request.cookies))
|
||||
elif "logs" in name:
|
||||
user=get_user(self,domain)
|
||||
whtml(self,"htmls/logs.html",domain=domain,user=user)
|
||||
elif "linux" in name:
|
||||
user=get_user(self,domain)
|
||||
whtml(self,"htmls/linux.html",domain=domain,user=user)
|
||||
elif "macos" in name:
|
||||
user=get_user(self,domain)
|
||||
whtml(self,"htmls/macos.html",domain=domain,user=user)
|
||||
elif "allnotes" in name:
|
||||
user=get_user(self,domain)
|
||||
whtml(self,"htmls/allnotes.html",domain=domain,user=user)
|
||||
elif "roadmap" in name:
|
||||
user=get_user(self,domain)
|
||||
whtml(self,"htmls/roadmap.html",domain=domain,user=user)
|
||||
elif "drm-free" in name:
|
||||
user=get_user(self,domain)
|
||||
whtml(self,"htmls/drmfree.html",domain=domain,user=user)
|
||||
elif "it-is-what-it-is" in name:
|
||||
user=get_user(self,domain)
|
||||
whtml(self,"htmls/disclaimers.html",domain=domain,user=user)
|
||||
elif "gallery/for/ideas" in name:
|
||||
user=get_user(self,domain)
|
||||
whtml(self,"utility/htmls/gallery.html",domain=domain,user=user,gallery=gallery)
|
||||
else:
|
||||
if domain.electron and self.request.get("buildid") in ["",None] and 0:
|
||||
return self.response.out.write("<div style='color: gray'>Build expired</div>")
|
||||
user=get_user(self,domain)
|
||||
if not user and name.startswith("r/") and len(name.split("/"))>1:
|
||||
referrer=name.split("/")[1]
|
||||
referrer=get_by_iid("user|%s"%referrer)
|
||||
if referrer:
|
||||
logging.info("Referrer is %s"%referrer.k())
|
||||
set_cookie(self,"referrer",referrer.k())
|
||||
ip=get_ip_info(self); ip.referrer=referrer.k(); put_ip_info(ip)
|
||||
return self.redirect("/")
|
||||
if not user and name.startswith("c/") and len(name.split("/"))>1: #unused [19/11/18]
|
||||
char=name.split("/")[1]
|
||||
char=get_character(char)
|
||||
if char:
|
||||
logging.info("Referrer is %s"%char.owner)
|
||||
set_cookie(self,"referrer",char.owner)
|
||||
ip=get_ip_info(self); ip.referrer=char.owner; put_ip_info(ip)
|
||||
if not domain.https_mode:
|
||||
if not self.request.headers.get("Cf-Visitor") and self.request.scheme=="https" or self.request.headers.get("Cf-Visitor") and "https" in self.request.headers.get("Cf-Visitor"):
|
||||
return self.redirect(self.request.url.replace("https","http"))
|
||||
render_selection(self,user,domain)
|
||||
def post(self,name):
|
||||
self.get(name)
|
||||
@ndb.toplevel
|
||||
@app.route('/comm')
|
||||
def serve_comm():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
return render_comm(request,user,domain)
|
||||
|
||||
class CommHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
render_comm(self,user,domain)
|
||||
def post(self):
|
||||
self.get()
|
||||
@app.route('/character/<name>')
|
||||
def serve_character(name=""):
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
character=get_character(name)
|
||||
if not character: return whtml(request,"htmls/simple_message.html",domain=domain,message="Not Found")
|
||||
if not user:
|
||||
ref=character.private and name or character.owner
|
||||
logging.info("Referrer is %s"%ref)
|
||||
set_cookie(request,"referrer",ref)
|
||||
ip=get_ip_info(request); ip.referrer=ref; put_ip_info(ip)
|
||||
domain.title=character.info.name
|
||||
return whtml(request,"htmls/character.html",domain=domain,character=character)
|
||||
|
||||
class CharacterHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,name):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
character=get_character(name)
|
||||
if not character: return whtml(self,"htmls/simple_message.html",domain=domain,message="Not Found")
|
||||
if not user:
|
||||
ref=character.private and name or character.owner
|
||||
logging.info("Referrer is %s"%ref)
|
||||
set_cookie(self,"referrer",ref)
|
||||
ip=get_ip_info(self); ip.referrer=ref; put_ip_info(ip)
|
||||
domain.title=character.info.name
|
||||
whtml(self,"htmls/character.html",domain=domain,character=character)
|
||||
def post(self,name):
|
||||
self.get(name)
|
||||
@ndb.toplevel
|
||||
@app.route('/characters')
|
||||
def server_characters():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
characters=Character.query().order(-Character.level).fetch(500)
|
||||
domain.title="Characters"
|
||||
return whtml(request,"htmls/player.html",domain=domain,characters=characters)
|
||||
|
||||
class VCharacterHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,name):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
character=get_character(name)
|
||||
if not character: return whtml(self,"htmls/simple_message.html",domain=domain,message="Not Found")
|
||||
characters=[character]
|
||||
for c in Backup.query(Backup.backup_item_id==character.k('i')).order(-Backup.backup_created).fetch(80):
|
||||
c.name=c.info.name="%s%s"%(c.info.name,(datetime.now()-c.backup_created).days)
|
||||
logging.info(c.info.slots["mainhand"]["name"])
|
||||
characters.append(c)
|
||||
domain.title=character.info.name
|
||||
whtml(self,"htmls/player.html",domain=domain,characters=characters)
|
||||
def post(self,name):
|
||||
self.get(name)
|
||||
@app.route('/player/<name>')
|
||||
def serve_player(name=""):
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
character=get_character(name)
|
||||
if not character: return whtml(request,"htmls/simple_message.html",domain=domain,message="Not Found")
|
||||
player=get_by_iid("user|%s"%character.owner)
|
||||
if not player: return whtml(request,"htmls/simple_message.html",domain=domain,message="Not Found")
|
||||
if not user:
|
||||
ref=character.private and name or player.k()
|
||||
logging.info("Referrer is %s"%ref)
|
||||
set_cookie(request,"referrer",ref)
|
||||
ip=get_ip_info(request); ip.referrer=ref; put_ip_info(ip)
|
||||
domain.title=player.name
|
||||
characters=[]
|
||||
if character.private: entities=[character]; domain.title=character.info.name
|
||||
else: entities=Character.query(Character.owner==character.owner, Character.private==False).fetch()
|
||||
if not len(entities): entities=[character]; domain.title=character.info.name
|
||||
for c in gf(player,"characters",[]):
|
||||
for e in entities:
|
||||
if simplify_name(e.name)==simplify_name(c["name"]):
|
||||
characters.append(e)
|
||||
return whtml(request,"htmls/player.html",domain=domain,characters=characters)
|
||||
|
||||
class CharactersHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
characters=Character.query().order(-Character.level).fetch(500)
|
||||
domain.title="Characters"
|
||||
whtml(self,"htmls/player.html",domain=domain,characters=characters)
|
||||
def post(self):
|
||||
self.get()
|
||||
@app.route('/merchants')
|
||||
@ndb.toplevel
|
||||
def serve_merchants():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
domain.title="All Online Merchants!"
|
||||
entities=Character.query(Character.online == True, Character.type == "merchant").fetch()
|
||||
return whtml(request,"htmls/player.html",domain=domain,characters=entities,merchants=True)
|
||||
|
||||
class PlayerHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,name):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
character=get_character(name)
|
||||
if not character: return whtml(self,"htmls/simple_message.html",domain=domain,message="Not Found")
|
||||
player=get_by_iid("user|%s"%character.owner)
|
||||
if not player: return whtml(self,"htmls/simple_message.html",domain=domain,message="Not Found")
|
||||
if not user:
|
||||
ref=character.private and name or player.k()
|
||||
logging.info("Referrer is %s"%ref)
|
||||
set_cookie(self,"referrer",ref)
|
||||
ip=get_ip_info(self); ip.referrer=ref; put_ip_info(ip)
|
||||
domain.title=player.name
|
||||
characters=[]
|
||||
if character.private: entities=[character]; domain.title=character.info.name
|
||||
else: entities=Character.query(Character.owner==character.owner, Character.private==False).fetch()
|
||||
if not len(entities): entities=[character]; domain.title=character.info.name
|
||||
for c in gf(player,"characters",[]):
|
||||
for e in entities:
|
||||
if simplify_name(e.name)==simplify_name(c["name"]):
|
||||
characters.append(e)
|
||||
whtml(self,"htmls/player.html",domain=domain,characters=characters)
|
||||
def post(self,name):
|
||||
self.get(name)
|
||||
@ndb.toplevel
|
||||
@app.route('/character/<name>/in/<region>/<sname>')
|
||||
@app.route('/character/<name>/in/<region>/<sname>/')
|
||||
def serve_server_and_character_selection(name="",region="",sname=""):
|
||||
logging.info("CMainHandler %s %s %s"%(name,region,sname))
|
||||
domain=gdi(request); level=80
|
||||
if domain.electron and request.values.get("buildid") in ["",None] and 0:
|
||||
return request.response.set_data("<div style='color: gray'>Build expired</dov>")
|
||||
if not domain.https_mode:
|
||||
if not request.headers.get("Cf-Visitor") and request.scheme=="https" or request.headers.get("Cf-Visitor") and "https" in request.headers.get("Cf-Visitor"):
|
||||
return request.redirect(request.url.replace("https","http"))
|
||||
servers=get_servers()
|
||||
user=get_user(request,domain)
|
||||
code=request.values.get("code")
|
||||
if code: domain.explicit_slot=code
|
||||
for c in gf(user,"characters",[]):
|
||||
if simplify_name(c["name"])==simplify_name(name):
|
||||
domain.character_name=c["name"]
|
||||
domain.url_character=c["id"]#so retry happens - this always gets set [05/01/18]
|
||||
level=c["level"]
|
||||
for server in servers:
|
||||
if server.region==region and server.name==sname:
|
||||
domain.url_ip=domain.https and server.ip or server.actual_ip
|
||||
domain.url_port=server.port
|
||||
logging.info("Set!")
|
||||
return render_selection(request,user,domain,level=level)
|
||||
|
||||
class MerchantsHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
domain.title="All Online Merchants!"
|
||||
entities=Character.query(Character.online == True, Character.type == "merchant").fetch()
|
||||
whtml(self,"htmls/player.html",domain=domain,characters=entities,merchants=True)
|
||||
def post(self):
|
||||
self.get()
|
||||
@ndb.toplevel
|
||||
@app.route('/server/<region>/<sname>')
|
||||
@app.route('/server/<region>/<sname>/')
|
||||
def serve_server_selection(region="",sname=""):
|
||||
logging.info("CMainHandler %s %s %s"%(name,region,sname))
|
||||
domain=gdi(request); S=None
|
||||
if domain.electron and request.values.get("buildid") in ["",None] and 0:
|
||||
return request.response.set_data("<div style='color: gray'>Build expired</dov>")
|
||||
if not domain.https_mode:
|
||||
if not request.headers.get("Cf-Visitor") and request.scheme=="https" or request.headers.get("Cf-Visitor") and "https" in request.headers.get("Cf-Visitor"):
|
||||
return request.redirect(request.url.replace("https","http"))
|
||||
servers=get_servers()
|
||||
user=get_user(request,domain)
|
||||
for server in servers:
|
||||
if server.region==region and server.name==sname:
|
||||
S=server
|
||||
return render_selection(request,user,domain,server=S)
|
||||
|
||||
class CMainHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,name,region,sname):
|
||||
logging.info("CMainHandler %s %s %s"%(name,region,sname))
|
||||
domain=gdi(self); level=80
|
||||
if domain.electron and self.request.get("buildid") in ["",None] and 0:
|
||||
return self.response.out.write("<div style='color: gray'>Build expired</dov>")
|
||||
@app.route('/ev/<uid>/<v>')
|
||||
@ndb.toplevel
|
||||
def server_everify(uid,v):
|
||||
domain=gdi(request)
|
||||
user=get_by_iid("user|%s"%uid)
|
||||
logging.info(user)
|
||||
message="Email Verification Failed"
|
||||
if user and not gf(user,"verified"):
|
||||
if gf(user,"everification")==v:
|
||||
def verification_transaction():
|
||||
element=get_by_iid(user.k('i'))
|
||||
element.info.verified=True
|
||||
element.put()
|
||||
return element
|
||||
if ndb.transaction(verification_transaction,xg=True,retries=8): message="Your Email Is Now Verified"
|
||||
elif user:
|
||||
message="Your Email Is Already Verified"
|
||||
whtml(request,"htmls/simple_message.html",domain=domain,message=message)
|
||||
return request.response
|
||||
|
||||
@app.route('/reset/<uid>/<key>')
|
||||
@ndb.toplevel
|
||||
def server_reset(uid,key):
|
||||
domain=gdi(request)
|
||||
user=get_by_iid("user|%s"%uid)
|
||||
logging.info(user)
|
||||
if user and gf(user,"password_key","123")==key:
|
||||
whtml(request,"htmls/contents/password_reset.html",domain=domain,user=user,id=uid,key=key)
|
||||
else:
|
||||
message="Invalid Password Reset URL"
|
||||
whtml(request,"htmls/simple_message.html",domain=domain,message=message)
|
||||
return request.response
|
||||
|
||||
@app.route('/code.js',methods=['GET','POST'])
|
||||
def serve_codejs():
|
||||
domain=gdi(request); user=get_user(request,domain); code=None; name=request.values.get("name")
|
||||
if user:
|
||||
data=get_user_data(user)
|
||||
for slot in gf(data,"code_list",{}):
|
||||
if "%s"%slot=="%s"%name or ("%s"%data.info.code_list[slot][0]).lower()==("%s"%to_filename(name)).lower():
|
||||
code=ndb.Key(InfoElement,"USERCODE-%s-%s"%(user.k(),slot)).get()
|
||||
if code:
|
||||
request.response.set_data("%s"%code.info.code)
|
||||
return request.response
|
||||
if request.values.get("xrequire"): request.response.set_data("throw('xrequire: Code not found')")
|
||||
else: request.response.set_data("game_log('load_code: Code not found',colors.code_error)")
|
||||
return request.response
|
||||
|
||||
@app.route('/data.js',methods=['GET','POST'])
|
||||
@ndb.toplevel
|
||||
def serve_datajs():
|
||||
domain=gdi(request); additional=""
|
||||
geometry={}
|
||||
for name in maps:
|
||||
key=maps[name]["key"]
|
||||
if maps[name].get("ignore"): continue
|
||||
#if name=="test" and not is_sdk: key="test"
|
||||
#logging.info(key)
|
||||
geometry[name]=get_by_iid("map|%s"%key).info.data
|
||||
data={
|
||||
"version":game_version,
|
||||
"achievements":achievements,
|
||||
"animations":animations,
|
||||
"monsters":monsters,
|
||||
"sprites":sprites,
|
||||
"maps":maps,
|
||||
"geometry":geometry,
|
||||
"npcs":npcs,
|
||||
"tilesets":tilesets,
|
||||
"imagesets":imagesets,
|
||||
"items":items,
|
||||
"sets":sets,
|
||||
"craft":craft,
|
||||
"titles":titles,
|
||||
"tokens":tokens,
|
||||
"dismantle":dismantle,
|
||||
"conditions":conditions,
|
||||
"cosmetics":cosmetics,
|
||||
"emotions":emotions,
|
||||
"projectiles":projectiles,
|
||||
"classes":classes,
|
||||
"dimensions":dimensions,
|
||||
"images":precomputed.images,
|
||||
"levels":levels,
|
||||
"positions":positions,
|
||||
"skills":skills,
|
||||
"events":events,
|
||||
"games":games,
|
||||
"multipliers":multipliers,
|
||||
#"codes":codes,
|
||||
"docs":docs,
|
||||
"drops":drops,
|
||||
}
|
||||
if request.values.get("reload"): additional="add_log('Game data reloaded','#32A3B0');\napply_backup()\n"
|
||||
request.response.set_data("var G=%s;\n%s"%(json.dumps(data),additional))
|
||||
return request.response
|
||||
|
||||
|
||||
@ndb.toplevel
|
||||
@app.route('/shells')
|
||||
def serve_shells():
|
||||
if not request.headers.get("Cf-Visitor") and request.scheme=="http" or request.headers.get("Cf-Visitor") and "https" not in request.headers.get("Cf-Visitor"):
|
||||
if not is_sdk: return request.redirect(request.url.replace("http","https"))
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
#if security_threat(request,domain): return #commented out [23/04/20]
|
||||
servers=get_servers(); server=select_server(request,user,servers)
|
||||
domain.stripe_enabled=True
|
||||
return whtml(request,"htmls/payments.html",domain=domain,user=user,server=server,extra_shells=extra_shells)
|
||||
|
||||
|
||||
@app.route("/map/<name>",methods=['GET']) #Resort Map Editor
|
||||
@app.route("/map/<name>/<suffix>",methods=['GET'])
|
||||
def serve_resort_get(name="",suffix=""):
|
||||
if not name: return
|
||||
name=name.split("/")[0]
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if security_threat(request,domain): return
|
||||
if not user or (not name.startswith("%s_"%user.k()) and user.k() not in inner_circle): return
|
||||
number=name.split("_")[1]
|
||||
if number not in ["1","2","3","4","5","6","7","8","9","10"]: return
|
||||
map=get_by_iid("map|%s"%name)
|
||||
mtilesets=copy.copy(tilesets)
|
||||
if map and gf(map,"image_map"): mtilesets["this_map"]={"file":"/tileset/%s.png"%map.info.image_map.blob_key}
|
||||
if map and gf(map,"image_map_a"): mtilesets["this_map_a"]={"file":"/tileset/%s.png"%map.info.image_map_a.blob_key}
|
||||
if not mtilesets.get("this_map"): mtilesets["this_map"]={"file":"/images/tiles/map/resort_default.png"}
|
||||
if not mtilesets.get("this_map_a"): mtilesets["this_map_a"]={"file":"/images/tiles/map/resort_default_a.png"}
|
||||
upload_url=blobstore.create_upload_url('/upload/tileset',gs_bucket_name=domain.gcs_bucket+"/images")
|
||||
return whtml(request,"utility/htmls/map_editor.html",domain=domain,name=name,map=map,upload_url=upload_url,tilesets=mtilesets,community=1,resort=1)
|
||||
|
||||
@app.route("/map/<name>",methods=['POST'])
|
||||
@app.route("/map/<name>/<suffix>",methods=['POST'])
|
||||
def serve_resort_post(name="",suffix=""):
|
||||
data=request.values.get("data")
|
||||
if not name: return
|
||||
name=name.split("/")[0]
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if not user or not name.startswith("%s_"%user.k()): return
|
||||
number=name.split("_")[1]
|
||||
if number not in ["1","2","3","4","5","6","7","8","9","10"]: return
|
||||
map=get_by_iid("map|%s"%name)
|
||||
if not map: map=Map(key=ndb.Key(Map,name),info=GG())
|
||||
map.info.data=json.loads(data)
|
||||
process_map(map)
|
||||
map.player=True
|
||||
map.updated=datetime.now()
|
||||
map.put()
|
||||
return to_pretty_num(olen(map.info.data))
|
||||
|
||||
@app.route('/maps')
|
||||
@app.route('/maps/<order>')
|
||||
def serve_maps(order=""):
|
||||
domain=gdi(request)
|
||||
def map_to_html(m):
|
||||
return "<div style='margin-bottom: 2px'><a href='%s/%s' target='_blank' style='color: white; font-weight: bold; text-decoration:none'>%s</a></div>"%(url,m.id(),m.id())
|
||||
html="<style> html{background-color:gray}</style>"
|
||||
if is_sdk: url="%s/admin/map_editor"%(domain.base_url)
|
||||
else: url="%s/%s"%(domain.base_url,"communitymaps")
|
||||
if order=="key":
|
||||
for m in Map.query().fetch(5000,keys_only=True): html+=map_to_html(m)
|
||||
else:
|
||||
for m in Map.query().order(-Map.updated).fetch(5000,keys_only=True): html+=map_to_html(m)
|
||||
return html
|
||||
|
||||
@app.route('/privacy')
|
||||
def serve_privacy():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
return whtml(request,"htmls/page.html",domain=domain,user=user,content="privacy")
|
||||
|
||||
@app.route('/terms')
|
||||
def serve_terms():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
return whtml(request,"htmls/page.html",domain=domain,user=user,content="terms")
|
||||
|
||||
@app.route('/contact')
|
||||
def serve_contact():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
return whtml(request,"htmls/page.html",domain=domain,user=user,content="contact")
|
||||
|
||||
@app.route('/credits')
|
||||
def serve_credits():
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
return whtml(request,"htmls/page.html",domain=domain,user=user,content="credits")
|
||||
|
||||
@app.route('/docs')
|
||||
@app.route('/docs/<path>')
|
||||
def serve_docs(path=""):
|
||||
domain=gdi(request); user=get_user(request,domain); domain.title="Docs"
|
||||
if len(path):
|
||||
domain.title="Docs /%s"%path
|
||||
path=path.split("/")
|
||||
return whtml(request,"htmls/docs.html",domain=domain,user=user,content="docs",dpath=path,extras=True)
|
||||
|
||||
@ndb.toplevel
|
||||
@app.route('/rearm')
|
||||
def serve_rearm():
|
||||
if not is_sdk: return ""
|
||||
free_servers()
|
||||
unlock_all()
|
||||
return "done!"
|
||||
|
||||
@ndb.toplevel
|
||||
@app.route('/', methods=['POST', 'GET'])
|
||||
@app.route('/<name>', methods=['POST', 'GET'])
|
||||
def server_main(name=""):
|
||||
domain=gdi(request)
|
||||
if 0 and "treasurehunter" in name:
|
||||
whtml(request,"examples/learningPixi/treasure_hunter.html")
|
||||
elif "runner" in name:
|
||||
whtml(request,"htmls/runner.html",domain=domain)
|
||||
elif "executor" in name:
|
||||
whtml(request,"htmls/executor.html",domain=domain)
|
||||
elif name=="info/cookies":
|
||||
request.response.set_data(repr(request.cookies))
|
||||
elif "logs" in name:
|
||||
user=get_user(request,domain)
|
||||
whtml(request,"htmls/logs.html",domain=domain,user=user)
|
||||
elif "linux" in name:
|
||||
user=get_user(request,domain)
|
||||
whtml(request,"htmls/linux.html",domain=domain,user=user)
|
||||
elif "macos" in name:
|
||||
user=get_user(request,domain)
|
||||
whtml(request,"htmls/macos.html",domain=domain,user=user)
|
||||
elif "allnotes" in name:
|
||||
user=get_user(request,domain)
|
||||
whtml(request,"htmls/allnotes.html",domain=domain,user=user)
|
||||
elif "roadmap" in name:
|
||||
user=get_user(request,domain)
|
||||
whtml(request,"htmls/roadmap.html",domain=domain,user=user)
|
||||
elif "drm-free" in name:
|
||||
user=get_user(request,domain)
|
||||
whtml(request,"htmls/drmfree.html",domain=domain,user=user)
|
||||
elif "it-is-what-it-is" in name:
|
||||
user=get_user(request,domain)
|
||||
whtml(request,"htmls/disclaimers.html",domain=domain,user=user)
|
||||
elif "gallery/for/ideas" in name:
|
||||
user=get_user(request,domain)
|
||||
whtml(request,"utility/htmls/gallery.html",domain=domain,user=user,gallery=gallery)
|
||||
else:
|
||||
if domain.electron and request.values.get("buildid") in ["",None] and 0:
|
||||
request.response.set_data("<div style='color: gray'>Build expired</div>")
|
||||
return request.response
|
||||
user=get_user(request,domain)
|
||||
if not user and name.startswith("r/") and len(name.split("/"))>1:
|
||||
referrer=name.split("/")[1]
|
||||
referrer=get_by_iid("user|%s"%referrer)
|
||||
if referrer:
|
||||
logging.info("Referrer is %s"%referrer.k())
|
||||
set_cookie(request,"referrer",referrer.k())
|
||||
ip=get_ip_info(request); ip.referrer=referrer.k(); put_ip_info(ip)
|
||||
return request.response.redirect("/")
|
||||
if not user and name.startswith("c/") and len(name.split("/"))>1: #unused [19/11/18]
|
||||
char=name.split("/")[1]
|
||||
char=get_character(char)
|
||||
if char:
|
||||
logging.info("Referrer is %s"%char.owner)
|
||||
set_cookie(request,"referrer",char.owner)
|
||||
ip=get_ip_info(request); ip.referrer=char.owner; put_ip_info(ip)
|
||||
if not domain.https_mode:
|
||||
if not self.request.headers.get("Cf-Visitor") and self.request.scheme=="https" or self.request.headers.get("Cf-Visitor") and "https" in self.request.headers.get("Cf-Visitor"):
|
||||
return self.redirect(self.request.url.replace("https","http"))
|
||||
servers=get_servers()
|
||||
user=get_user(self,domain)
|
||||
code=self.request.get("code")
|
||||
if code: domain.explicit_slot=code
|
||||
for c in gf(user,"characters",[]):
|
||||
if simplify_name(c["name"])==simplify_name(name):
|
||||
domain.character_name=c["name"]
|
||||
domain.url_character=c["id"]#so retry happens - this always gets set [05/01/18]
|
||||
level=c["level"]
|
||||
for server in servers:
|
||||
if server.region==region and server.name==sname:
|
||||
domain.url_ip=domain.https and server.ip or server.actual_ip
|
||||
domain.url_port=server.port
|
||||
logging.info("Set!")
|
||||
render_selection(self,user,domain,level=level)
|
||||
def post(self,name,region,sname):
|
||||
self.get(name,region,sname)
|
||||
|
||||
class SMainHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,region,sname):
|
||||
logging.info("CMainHandler %s %s %s"%(name,region,sname))
|
||||
domain=gdi(self); S=None
|
||||
if domain.electron and self.request.get("buildid") in ["",None] and 0:
|
||||
return self.response.out.write("<div style='color: gray'>Build expired</dov>")
|
||||
if not domain.https_mode:
|
||||
if not self.request.headers.get("Cf-Visitor") and self.request.scheme=="https" or self.request.headers.get("Cf-Visitor") and "https" in self.request.headers.get("Cf-Visitor"):
|
||||
return self.redirect(self.request.url.replace("https","http"))
|
||||
servers=get_servers()
|
||||
user=get_user(self,domain)
|
||||
for server in servers:
|
||||
if server.region==region and server.name==sname:
|
||||
S=server
|
||||
render_selection(self,user,domain,server=S)
|
||||
def post(self,region,sname):
|
||||
self.get(region,sname)
|
||||
|
||||
class EmailVerification(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,uid,v):
|
||||
domain=gdi(self)
|
||||
user=get_by_iid("user|%s"%uid)
|
||||
logging.info(user)
|
||||
message="Email Verification Failed"
|
||||
if user and not gf(user,"verified"):
|
||||
if gf(user,"everification")==v:
|
||||
def verification_transaction():
|
||||
element=get_by_iid(user.k('i'))
|
||||
element.info.verified=True
|
||||
element.put()
|
||||
return element
|
||||
if ndb.transaction(verification_transaction,xg=True,retries=8): message="Your Email Is Now Verified"
|
||||
elif user:
|
||||
message="Your Email Is Already Verified"
|
||||
whtml(self,"htmls/simple_message.html",domain=domain,message=message)
|
||||
def post(self,uid,v):
|
||||
self.get(uid,v)
|
||||
|
||||
class PasswordReset(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,uid,key):
|
||||
domain=gdi(self)
|
||||
user=get_by_iid("user|%s"%uid)
|
||||
logging.info(user)
|
||||
if user and gf(user,"password_key","123")==key:
|
||||
whtml(self,"htmls/contents/password_reset.html",domain=domain,user=user,id=uid,key=key)
|
||||
else:
|
||||
message="Invalid Password Reset URL"
|
||||
whtml(self,"htmls/simple_message.html",domain=domain,message=message)
|
||||
def post(self,uid,v):
|
||||
self.get(uid,v)
|
||||
|
||||
class CodeJS(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); user=get_user(self,domain); code=None; name=self.request.get("name")
|
||||
if user:
|
||||
data=get_user_data(user)
|
||||
for slot in gf(data,"code_list",{}):
|
||||
if "%s"%slot=="%s"%name or ("%s"%data.info.code_list[slot][0]).lower()==("%s"%to_filename(name)).lower():
|
||||
code=ndb.Key(InfoElement,"USERCODE-%s-%s"%(user.k(),slot)).get()
|
||||
if code:
|
||||
self.response.out.write("%s"%code.info.code)
|
||||
return
|
||||
if self.request.get("xrequire"): self.response.out.write("throw('xrequire: Code not found')")
|
||||
else: self.response.out.write("game_log('load_code: Code not found',colors.code_error)")
|
||||
def post(self):
|
||||
self.get()
|
||||
|
||||
class DataJS(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); additional=""
|
||||
geometry={}
|
||||
for name in maps:
|
||||
key=maps[name]["key"]
|
||||
if maps[name].get("ignore"): continue
|
||||
#if name=="test" and not is_sdk: key="test"
|
||||
#logging.info(key)
|
||||
geometry[name]=get_by_iid("map|%s"%key).info.data
|
||||
data={
|
||||
"version":game_version,
|
||||
"achievements":achievements,
|
||||
"animations":animations,
|
||||
"monsters":monsters,
|
||||
"sprites":sprites,
|
||||
"maps":maps,
|
||||
"geometry":geometry,
|
||||
"npcs":npcs,
|
||||
"tilesets":tilesets,
|
||||
"imagesets":imagesets,
|
||||
"items":items,
|
||||
"sets":sets,
|
||||
"craft":craft,
|
||||
"titles":titles,
|
||||
"tokens":tokens,
|
||||
"dismantle":dismantle,
|
||||
"conditions":conditions,
|
||||
"cosmetics":cosmetics,
|
||||
"emotions":emotions,
|
||||
"projectiles":projectiles,
|
||||
"classes":classes,
|
||||
"dimensions":dimensions,
|
||||
"images":precomputed.images,
|
||||
"levels":levels,
|
||||
"positions":positions,
|
||||
"skills":skills,
|
||||
"events":events,
|
||||
"games":games,
|
||||
"multipliers":multipliers,
|
||||
#"codes":codes,
|
||||
"docs":docs,
|
||||
"drops":drops,
|
||||
}
|
||||
if self.request.get("reload"): additional="add_log('Game data reloaded','#32A3B0');\napply_backup()\n"
|
||||
self.response.out.write("var G=%s;\n%s"%(json.dumps(data),additional))
|
||||
def post(self):
|
||||
self.get()
|
||||
|
||||
class PaymentsHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
if not self.request.headers.get("Cf-Visitor") and self.request.scheme=="http" or self.request.headers.get("Cf-Visitor") and "https" not in self.request.headers.get("Cf-Visitor"):
|
||||
if not is_sdk: return self.redirect(self.request.url.replace("http","https"))
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
#if security_threat(self,domain): return #commented out [23/04/20]
|
||||
servers=get_servers(); server=select_server(self,user,servers)
|
||||
domain.stripe_enabled=True
|
||||
whtml(self,"htmls/payments.html",domain=domain,user=user,server=server,extra_shells=extra_shells)
|
||||
def post(self):
|
||||
self.get()
|
||||
|
||||
class TileUpload(blobstore_handlers.BlobstoreUploadHandler):
|
||||
@ndb.toplevel
|
||||
def post(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
if security_threat(self,domain): return
|
||||
upload_files = self.get_file_infos('image'); file_info = upload_files[0]; blob_key=blobstore.create_gs_key_async(file_info.gs_object_name)
|
||||
key,name=gdmul(self,"key","iname")
|
||||
if name not in ["map","map_a"] or not user or not key.startswith(""+user.k()):
|
||||
if 0: return jhtmle(self,"Permission issue")
|
||||
else: return self.response.out.write("Permission issue")
|
||||
logging.info("Image Upload %s %s"%(key,name))
|
||||
map=get_by_iid("map|%s"%key); blob_key=blob_key.get_result()
|
||||
if not map: map=Map(key=ndb.Key(Map,key),info=GG())
|
||||
|
||||
if file_info.content_type in ["image/jpg","image/jpeg","image/jpe","image/png","image/gif"]:
|
||||
if gf(map,"image_%s"%name):
|
||||
try: blobstore.delete(blob_keys=gf(map,"image_%s"%name).blob_key)
|
||||
except: log_trace()
|
||||
setattr(map.info,"image_%s"%name,cGG(blob_key=blob_key,
|
||||
content_type=file_info.content_type,gs_object_name=file_info.gs_object_name))
|
||||
if 0: jhtml(self,[{"type":"success","message":"Image uploaded"}])
|
||||
else: self.redirect("/map/"+key)
|
||||
map.put()
|
||||
else:
|
||||
blobstore.delete(blob_keys=blob_key)
|
||||
if 0: jhtmle(self,"Not an image")
|
||||
else: self.response.out.write("Not an image")
|
||||
def get(self): self.post()
|
||||
|
||||
class GCSServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
|
||||
def get(self,resource):
|
||||
#resource = str(urllib.unquote(resource))
|
||||
#blob_key=blobstore.create_gs_key(resource)
|
||||
#self.send_blob(blob_key)
|
||||
logging.info("here")
|
||||
resource = str(urllib.unquote(resource))
|
||||
self.send_blob(resource)
|
||||
|
||||
class ResortEditor(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,name,suffix):
|
||||
if not name: return
|
||||
name=name.split("/")[0]
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
if security_threat(self,domain): return
|
||||
if not user or (not name.startswith("%s_"%user.k()) and user.k() not in inner_circle): return
|
||||
number=name.split("_")[1]
|
||||
if number not in ["1","2","3","4","5","6","7","8","9","10"]: return
|
||||
map=get_by_iid("map|%s"%name)
|
||||
mtilesets=copy.copy(tilesets)
|
||||
if map and gf(map,"image_map"): mtilesets["this_map"]={"file":"/tileset/%s.png"%map.info.image_map.blob_key}
|
||||
if map and gf(map,"image_map_a"): mtilesets["this_map_a"]={"file":"/tileset/%s.png"%map.info.image_map_a.blob_key}
|
||||
if not mtilesets.get("this_map"): mtilesets["this_map"]={"file":"/images/tiles/map/resort_default.png"}
|
||||
if not mtilesets.get("this_map_a"): mtilesets["this_map_a"]={"file":"/images/tiles/map/resort_default_a.png"}
|
||||
upload_url=blobstore.create_upload_url('/upload/tileset',gs_bucket_name=domain.gcs_bucket+"/images")
|
||||
whtml(self,"utility/htmls/map_editor.html",domain=domain,name=name,map=map,upload_url=upload_url,tilesets=mtilesets,community=1,resort=1)
|
||||
def post(self,name,suffix):
|
||||
data=self.request.get("data")
|
||||
if not name: return
|
||||
name=name.split("/")[0]
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
if not user or not name.startswith("%s_"%user.k()): return
|
||||
number=name.split("_")[1]
|
||||
if number not in ["1","2","3","4","5","6","7","8","9","10"]: return
|
||||
map=get_by_iid("map|%s"%name)
|
||||
if not map: map=Map(key=ndb.Key(Map,name),info=GG())
|
||||
map.info.data=json.loads(data)
|
||||
process_map(map)
|
||||
map.player=True
|
||||
map.updated=datetime.now()
|
||||
map.put()
|
||||
self.response.out.write(to_pretty_num(olen(map.info.data)))
|
||||
|
||||
class Redirector(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
self.response.out.write("<script>window.top.location='http://adventure.land'</script> <!-- This is temporary, until I can set up the FB version [04/NOV/16] -->")
|
||||
def post(self):
|
||||
self.get()
|
||||
|
||||
class WarmupHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
pass
|
||||
def post(self):
|
||||
self.get()
|
||||
|
||||
class MapLister(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,order):
|
||||
domain=gdi(self)
|
||||
def map_to_html(m):
|
||||
return "<div style='margin-bottom: 2px'><a href='%s/%s' target='_blank' style='color: white; font-weight: bold; text-decoration:none'>%s</a></div>"%(url,m.id(),m.id())
|
||||
html="<style> html{background-color:gray}</style>"
|
||||
if is_sdk: url="%s/admin/map_editor"%(domain.base_url)
|
||||
else: url="%s/%s"%(domain.base_url,"communitymaps")
|
||||
if order=="key":
|
||||
for m in Map.query().fetch(5000,keys_only=True): html+=map_to_html(m)
|
||||
else:
|
||||
for m in Map.query().order(-Map.updated).fetch(5000,keys_only=True): html+=map_to_html(m)
|
||||
self.response.out.write(html)
|
||||
def post(self):
|
||||
self.get()
|
||||
|
||||
class IPLister(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,order):
|
||||
domain=gdi(self)
|
||||
def ip_to_html(ip):
|
||||
return "<div style='margin-bottom: 2px'>%s {%s} [%s]</div>"%(ip.info.explanation,ip.random_id,ip.info.limit)
|
||||
html="<style> html{background-color:gray}</style>"
|
||||
for ip in IP.query(IP.exception==True).fetch(5000): html+=ip_to_html(ip)
|
||||
self.response.out.write(html)
|
||||
def post(self):
|
||||
self.get()
|
||||
|
||||
class PrivacyHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
whtml(self,"htmls/page.html",domain=domain,user=user,content="privacy")
|
||||
|
||||
class TermsHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
whtml(self,"htmls/page.html",domain=domain,user=user,content="terms")
|
||||
|
||||
class ContactHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
whtml(self,"htmls/page.html",domain=domain,user=user,content="contact")
|
||||
|
||||
class DocsHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,path):
|
||||
domain=gdi(self); user=get_user(self,domain); domain.title="Docs"
|
||||
if len(path):
|
||||
domain.title="Docs /%s"%path
|
||||
path=path.split("/")
|
||||
whtml(self,"htmls/docs.html",domain=domain,user=user,content="docs",dpath=path,extras=True)
|
||||
|
||||
class CreditsHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=gdi(self); user=get_user(self,domain)
|
||||
whtml(self,"htmls/page.html",domain=domain,user=user,content="credits")
|
||||
|
||||
class RearmHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
if not is_sdk: return
|
||||
free_servers()
|
||||
unlock_all()
|
||||
|
||||
application = webapp.WSGIApplication([
|
||||
('/ev/(.*)/([^/]*)/?', EmailVerification),
|
||||
('/reset/(.*)/([^/]*)/?', PasswordReset),
|
||||
('/data.js', DataJS),
|
||||
('/code.js', CodeJS),
|
||||
('/upload/tileset.*',TileUpload),
|
||||
('/tileset/(.*)\.png',GCSServeHandler),
|
||||
('/maps/?(.*)',MapLister),
|
||||
('/ips/?(.*)',IPLister),
|
||||
('/docs/?(.*)',DocsHandler),
|
||||
('/map/(.*)/?(.*)',ResortEditor),
|
||||
('/communitymaps/?(.*)', CommunityMapEditor),
|
||||
('/editmap/?(.*)', ArtistMapEditor),
|
||||
('/communityselector/?(.*)', Selector),
|
||||
('/communityitems', Items),
|
||||
('/shells', PaymentsHandler),
|
||||
('/temporaryfbcanvas', Redirector),
|
||||
('/_ah/warmup',WarmupHandler),
|
||||
('/privacy.*',PrivacyHandler),
|
||||
('/terms.*',TermsHandler),
|
||||
('/contact.*',ContactHandler),
|
||||
('/credits.*',CreditsHandler),
|
||||
('/server/([^/]*)/([^/]*)/?', SMainHandler),
|
||||
('/character/([^/]*)/in/([^/]*)/([^/]*)/?', CMainHandler),
|
||||
('/character/([^/]*)/?', CharacterHandler),
|
||||
('/visualizeT2/([^/]*)/?', VCharacterHandler),
|
||||
('/player/([^/]*)/?', PlayerHandler),
|
||||
('/characters', CharactersHandler),
|
||||
('/merchants', MerchantsHandler),
|
||||
('/comm/?.*', CommHandler),
|
||||
('/rearm',RearmHandler),
|
||||
('/?(.*)', MainHandler),
|
||||
],debug=is_sdk)
|
||||
if not request.headers.get("Cf-Visitor") and request.scheme=="https" or request.headers.get("Cf-Visitor") and "https" in request.headers.get("Cf-Visitor"):
|
||||
return request.redirect(request.url.replace("https","http"))
|
||||
render_selection(request,user,domain)
|
||||
return request.response
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Install google-cloud-sdk from: https://cloud.google.com/sdk/docs/install
|
||||
|
||||
Replace app.yaml with the python3 one
|
||||
|
||||
python3 CLOUD_SDK_ROOT/bin/dev_appserver.py OPTION yaml_path FILES
|
||||
|
||||
The python3 dev_appserver uses Java objects, test it according to your needs and performance expectations, I personally favor Python2 still [27/01/24]
|
||||
|
||||
Useful: https://cloud.google.com/appengine/docs/standard/tools/local-devserver-command?tab=python
|
||||
|
||||
alias run_thegame3="python3.11 /Users/kaan/Desktop/APPENGINE/google-cloud-sdk/bin/dev_appserver.py --storage_path=/Users/kaan/Desktop/DEPLOY/python3/storage/ --blobstore_path=/Users/kaan/Desktop/DEPLOY/python3/storage/blobstore/ --datastore_path=/Users/kaan/Desktop/DEPLOY/python3/storage/new_db.bin --host=0.0.0.0 --port=8083 /Users/kaan/Desktop/DEPLOY/python3/thegame/ --require_indexes --enable_host_checking=False"
|
||||
|
||||
Suggestions:
|
||||
1) Invoke /admin/make with your email put in admin.py
|
||||
2) From /admin/executor - call empty_fill_maps()
|
||||
3) After getting rid of the initial errors, figure out the rest
|
||||
@@ -0,0 +1,34 @@
|
||||
version: 4 #2-new UI | 3-new font dynamics | 4-python3
|
||||
runtime: python312
|
||||
app_engine_apis: true
|
||||
threadsafe: true
|
||||
api_version: 1
|
||||
builtins:
|
||||
- deferred: on
|
||||
|
||||
#F2/F4: same warmup handler performance [14/10/14]
|
||||
instance_class: F2
|
||||
automatic_scaling:
|
||||
min_idle_instances: 0
|
||||
max_idle_instances: 1
|
||||
min_pending_latency: 6000ms
|
||||
max_pending_latency: 12000ms
|
||||
|
||||
default_expiration: "4d"
|
||||
|
||||
handlers:
|
||||
- url: /favicon\.ico
|
||||
static_files: images/favicon.ico
|
||||
upload: favicon\.ico
|
||||
- url: /css
|
||||
static_dir: css
|
||||
- url: /images
|
||||
static_dir: images
|
||||
- url: /img/
|
||||
static_dir: images/screenshots
|
||||
- url: /sounds
|
||||
static_dir: sounds
|
||||
- url: /js
|
||||
static_dir: js
|
||||
- url: .*
|
||||
script: auto
|
||||
@@ -0,0 +1,3 @@
|
||||
Flask
|
||||
lxml
|
||||
appengine-python-standard
|
||||
@@ -0,0 +1 @@
|
||||
Flask
|
||||
@@ -0,0 +1,24 @@
|
||||
// creates a python3 project to safely test a python3 environment [27/01/24]
|
||||
|
||||
var path=require("path"),f=require(path.resolve(__dirname, "functions.js"));
|
||||
|
||||
f.execs("rm -rf ~/deploy/python3/thegame");
|
||||
f.execs("mkdir ~/deploy/python3/thegame");
|
||||
//f.execs("cp -r ~/thegame/* ~/deploy/python3/thegame");
|
||||
f.execs("rsync -rv --exclude=.electron ~/thegame/* ~/deploy/python3/thegame"); // steamworkds_sdk is problematic to cp [11/02/19]
|
||||
|
||||
f.execs("rm -rf ~/deploy/python3/thegame/node");
|
||||
f.execs("rm -rf ~/deploy/python3/thegame/scripts");
|
||||
f.execs("cp -f ~/deploy/python3/thegame/python3/app.yaml ~/deploy/python3/thegame/app.yaml");
|
||||
f.execs("cp -f ~/deploy/python3/thegame/python3/requirements.txt ~/deploy/python3/thegame/requirements.txt");
|
||||
f.execs("rm -rf ~/deploy/python3/thegame/lib");
|
||||
f.execs("mkdir ~/deploy/python3/thegame/lib");
|
||||
f.execs("rm -rf ~/deploy/python3/thegame/origin");
|
||||
f.execs("rm -rf ~/deploy/python3/thegame/electron");
|
||||
f.execs("find ~/deploy/python3/thegame/ -name '*.pxm' -delete");
|
||||
|
||||
f.execs("cp ~/deploy/python3/thegame/js/runner_functions.js ~/deploy/python3/thegame/htmls/contents/codes/runner_functions.js");
|
||||
f.execs("cp ~/deploy/python3/thegame/js/runner_compat.js ~/deploy/python3/thegame/htmls/contents/codes/runner_compat.js");
|
||||
f.execs("cp ~/deploy/python3/thegame/js/common_functions.js ~/deploy/python3/thegame/htmls/contents/codes/common_functions.js");
|
||||
|
||||
// f.write_file("~/deploy/python3/thegame/app.yaml",f.read_file("~/thegame/app.yaml").replace("application:","#application:").replace("version:","#version:"));
|
||||
+5
-1
@@ -20,6 +20,10 @@ f.execs("cp ~/deploy/thegame_appengine/stack/update_notes.txt ~/deploy/thegame_a
|
||||
f.execs("rm -rf ~/deploy/thegame_appengine/stack");
|
||||
f.execs("mkdir ~/deploy/thegame_appengine/stack");
|
||||
f.execs("cp ~/deploy/thegame_appengine/design/update_notes.txt ~/deploy/thegame_appengine/stack/update_notes.txt");
|
||||
f.execs("cp -f ~/deploy/thegame_appengine/python3/app.yaml ~/deploy/thegame_appengine/app.yaml");
|
||||
f.execs("cp -f ~/deploy/thegame_appengine/python3/requirements.txt ~/deploy/thegame_appengine/requirements.txt");
|
||||
f.execs("rm -rf ~/deploy/thegame_appengine/lib");
|
||||
f.execs("rm -rf ~/deploy/thegame_appengine/python3");
|
||||
f.execs("rm -rf ~/deploy/thegame_appengine/origin");
|
||||
f.execs("rm -rf ~/deploy/thegame_appengine/electron");
|
||||
f.execs("find ~/deploy/thegame_appengine/ -name '*.pxm' -delete");
|
||||
@@ -28,7 +32,7 @@ f.execs("cp ~/deploy/thegame_appengine/js/runner_functions.js ~/deploy/thegame_a
|
||||
f.execs("cp ~/deploy/thegame_appengine/js/runner_compat.js ~/deploy/thegame_appengine/htmls/contents/codes/runner_compat.js");
|
||||
f.execs("cp ~/deploy/thegame_appengine/js/common_functions.js ~/deploy/thegame_appengine/htmls/contents/codes/common_functions.js");
|
||||
|
||||
f.write_file("~/deploy/thegame_appengine/app.yaml",f.read_file("~/thegame/app.yaml").replace("application:","#application:").replace("version:","#version:"));
|
||||
// f.write_file("~/deploy/thegame_appengine/app.yaml",f.read_file("~/thegame/app.yaml").replace("application:","#application:").replace("version:","#version:"));
|
||||
|
||||
to_minify={
|
||||
// "js":["game.js","keyboard.js","html.js","functions.js","common_functions.js"],
|
||||
|
||||
@@ -1,65 +1,32 @@
|
||||
from config import *
|
||||
from functions import *
|
||||
|
||||
class DownloadHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
password,iid=gdmul(self,"password","iid")
|
||||
if password!=ELEMENT_PASSWORD: logging.error("breach attempt"); return
|
||||
element=get_by_iid(iid)
|
||||
self.response.out.write(cPickle.dumps(element))
|
||||
def post(self): self.get()
|
||||
@app.route('/tasks/download')
|
||||
@ndb.toplevel
|
||||
def serve_map_download(request):
|
||||
password,iid=gdmul(request,"password","iid")
|
||||
if password!=ELEMENT_PASSWORD: logging.error("breach attempt"); return
|
||||
element=get_by_iid(iid)
|
||||
return cPickle.dumps(element)
|
||||
|
||||
class PostTaskHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def post(self):
|
||||
domain=gdi(self)
|
||||
password=gdmul(self,"p")
|
||||
if password==SDK_UPLOAD_PASSWORD:
|
||||
logging.info("received a post_task")
|
||||
task_code,obj1,obj2,obj3=gdmul(self,"task_code","obj1","obj2","obj3"); element=None; element2=None; result=""
|
||||
if obj1: element=cPickle.loads(str(obj1))
|
||||
if obj2: element2=cPickle.loads(str(obj2))
|
||||
if obj3: element2=cPickle.loads(str(obj3))
|
||||
exec(task_code)
|
||||
logging.info(result)
|
||||
self.response.headers.add_header('Content-Type','application/x-www-form-urlencoded')
|
||||
if self.response.out.body and not result:
|
||||
result=self.response.out.body
|
||||
self.response.out.clear()
|
||||
self.response.out.write(cPickle.dumps(result))
|
||||
def get(self): self.post()
|
||||
|
||||
class PaymentwallHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def post(self):
|
||||
domain=gdi(self)
|
||||
self.response.out.write("1")
|
||||
def get(self): self.post()
|
||||
|
||||
class SuperRewardsHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def post(self):
|
||||
domain=gdi(self)
|
||||
id,uid,oid,new,total,sig=gdmul(self,"id","uid","oid","new","total","sig")
|
||||
logging.info("super_rewards %s"%([id,uid,oid,new,total,sig]))
|
||||
if not marker_check("superrewards-%s-%s"%(id,uid)):
|
||||
add_event(None,"superrewards_repeated",[],info=cGG(message="Super Rewards: callback repeated %s %s %s"%(uid,id,new),id=id,uid=uid,oid=oid,new=new,total=total,sig=sig))
|
||||
self.response.out.write("1")
|
||||
return
|
||||
user=get_by_iid("user|%s"%uid)
|
||||
if not user:
|
||||
add_event(None,"superrewards_no_user",[],info=cGG(message="Super Rewards: user not found for %s %s %s"%(uid,id,new),id=id,uid=uid,oid=oid,new=new,total=total,sig=sig))
|
||||
self.response.out.write("4") #http://docs.superrewards.com/docs/notification-postbacks
|
||||
return
|
||||
add_event(user,"superrewards_cash",["cashflow","payments"],info=cGG(message="Super Rewards: %s received %s shells"%(user.name,new),id=id,uid=uid,oid=oid,new=new,total=total,sig=sig))
|
||||
add_cash(user,int(math.ceil(int(new))),referrer=1)
|
||||
self.response.out.write("1")
|
||||
def get(self): self.post()
|
||||
|
||||
application = webapp.WSGIApplication([
|
||||
('/tasks/download.*', DownloadHandler),
|
||||
('/tasks/post.*', PostTaskHandler),
|
||||
('/tasks/pwallping.*', PaymentwallHandler),
|
||||
('/tasks/srcallback.*', SuperRewardsHandler),
|
||||
],debug=is_sdk)
|
||||
@app.route('/tasks/post',methods=['GET','POST'])
|
||||
@ndb.toplevel
|
||||
def serve_post(request):
|
||||
domain=gdi(request)
|
||||
password=gdmul(request,"p")
|
||||
if password==SDK_UPLOAD_PASSWORD:
|
||||
logging.info("received a post_task")
|
||||
task_code,obj1,obj2,obj3=gdmul(request,"task_code","obj1","obj2","obj3"); element=None; element2=None; result=""
|
||||
if obj1: element=cPickle.loads(str(obj1))
|
||||
if obj2: element2=cPickle.loads(str(obj2))
|
||||
if obj3: element2=cPickle.loads(str(obj3))
|
||||
exec(task_code)
|
||||
logging.info(result)
|
||||
request.response.headers.add_header('Content-Type','application/x-www-form-urlencoded')
|
||||
if request.response.out.body and not result:
|
||||
result=request.response.out.body
|
||||
request.response.out.clear()
|
||||
request.response.set_data(cPickle.dumps(result))
|
||||
return request.response
|
||||
else:
|
||||
return "password_issue"
|
||||
@@ -1,31 +1,36 @@
|
||||
from config import *
|
||||
from functions import *
|
||||
|
||||
class MainHandler(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self,name):
|
||||
domain=gdi(self)
|
||||
if name=="hash":
|
||||
start=datetime.now()
|
||||
logging.info(pbkdf2_hex("test","123456",iterations=160))
|
||||
logging.info(mssince(start))
|
||||
elif name=="levels":
|
||||
xp=200
|
||||
for i in xrange(100):
|
||||
new_xp=xp
|
||||
while new_xp>=100: new_xp/=10
|
||||
new_xp=int(new_xp)
|
||||
while new_xp*10<=xp: new_xp*=10
|
||||
xp=new_xp
|
||||
self.response.out.write("level %s %sxp %s worms %s 40K's<br />"%((i+1),xp,xp/200.0,xp/40000.0))
|
||||
xp*=1.25
|
||||
elif name.startswith("pixi_"):
|
||||
whtml(self,"utility/htmls/tests/%s.html"%name,domain=domain)
|
||||
else:
|
||||
self.response.out.write("test")
|
||||
def post(self,name):
|
||||
self.get(name)
|
||||
def test():
|
||||
@after_this_request
|
||||
def add_header(response):
|
||||
response.headers['X-Foo'] = 'Parachute'
|
||||
return response
|
||||
|
||||
application = webapp.WSGIApplication([
|
||||
('/test/?(.*)', MainHandler)
|
||||
],debug=is_sdk)
|
||||
@app.route('/test', methods=['POST', 'GET'])
|
||||
@app.route('/test/<name>', methods=['POST', 'GET'])
|
||||
@ndb.toplevel
|
||||
def serve_test(name=""):
|
||||
domain=gdi(request)
|
||||
if name=="hash":
|
||||
start=datetime.now()
|
||||
logging.info(pbkdf2_hex("test","123456",iterations=160))
|
||||
logging.info(mssince(start))
|
||||
elif name=="levels":
|
||||
xp=200
|
||||
for i in xrange(100):
|
||||
html=""
|
||||
new_xp=xp
|
||||
while new_xp>=100: new_xp/=10
|
||||
new_xp=int(new_xp)
|
||||
while new_xp*10<=xp: new_xp*=10
|
||||
xp=new_xp
|
||||
html+="level %s %sxp %s worms %s 40K's<br />"%((i+1),xp,xp/200.0,xp/40000.0)
|
||||
xp*=1.25
|
||||
return html
|
||||
elif name.startswith("pixi_"):
|
||||
return shtml("utility/htmls/tests/%s.html"%name,domain=domain)
|
||||
else:
|
||||
request.response=make_response('Setting the cookie')
|
||||
#test()
|
||||
return request.response
|
||||
@@ -0,0 +1,94 @@
|
||||
from config import *
|
||||
from functions import *
|
||||
|
||||
# for Python2 [27/01/24]
|
||||
|
||||
class PhotoUpload(blobstore_handlers.BlobstoreUploadHandler):
|
||||
@ndb.toplevel
|
||||
def post(self):
|
||||
domain=get(request); user=get_user(self,domain)
|
||||
if security_threat(self,domain): return
|
||||
if not getattr(user,"admin",False): return
|
||||
upload_files = self.get_file_infos('image'); file_info = upload_files[0]; blob_key=blobstore.create_gs_key_async(file_info.gs_object_name)
|
||||
key=gdmul(request,"key");
|
||||
logging.info("Image Upload %s"%(key))
|
||||
upload=get_by_iid("upload|%s"%key); blob_key=blob_key.get_result()
|
||||
if not upload: upload=Upload(key=ndb.Key(Upload,key),info=GG())
|
||||
|
||||
|
||||
if file_info.content_type in ["image/jpg","image/jpeg","image/jpe","image/png","image/gif"]:
|
||||
if gf(upload,"blob_key"):
|
||||
try:
|
||||
blobstore.delete(blob_keys=upload.info.blob_key)
|
||||
logging.info("Old image deleted")
|
||||
except: log_trace()
|
||||
|
||||
url=get_serving_url(blob_key,size=images.IMG_SERVING_SIZES_LIMIT)
|
||||
size=get_image_size(blob_key,encoding=filetype_to_image_encoding(file_info.content_type))
|
||||
|
||||
upload.info.blob_key=blob_key
|
||||
upload.info.content_type=file_info.content_type
|
||||
upload.info.gs_object_name=file_info.gs_object_name
|
||||
upload.info.url=url
|
||||
upload.info.width=size.width
|
||||
upload.info.height=size.height
|
||||
|
||||
self.response.out.write("{<br/> '%s':{'url':'%s','width':%s,'height':%s},<br />}"%(key,url,size.width,size.height))
|
||||
upload.put()
|
||||
else:
|
||||
blobstore.delete(blob_keys=blob_key)
|
||||
self.response.out.write("Not an image")
|
||||
def get(self): self.post()
|
||||
|
||||
class PhotoUploader(webapp.RequestHandler):
|
||||
@ndb.toplevel
|
||||
def get(self):
|
||||
domain=get(request); user=get_user(self,domain)
|
||||
if security_threat(self,domain): return
|
||||
upload_url=blobstore.create_upload_url('/admin/upload/handler',gs_bucket_name=domain.gcs_bucket+"/files")
|
||||
whtml(request,"utility/htmls/uploader.html",domain=domain,upload_url=upload_url)
|
||||
|
||||
class TileUpload(blobstore_handlers.BlobstoreUploadHandler):
|
||||
@ndb.toplevel
|
||||
def post(request):
|
||||
domain=gdi(request); user=get_user(request,domain)
|
||||
if security_threat(request,domain): return
|
||||
upload_files = request.get_file_infos('image'); file_info = upload_files[0]; blob_key=blobstore.create_gs_key_async(file_info.gs_object_name)
|
||||
key,name=gdmul(request,"key","iname")
|
||||
if name not in ["map","map_a"] or not user or not key.startswith(""+user.k()):
|
||||
if 0: return jhtmle(request,"Permission issue")
|
||||
else: return request.response.set_data("Permission issue")
|
||||
logging.info("Image Upload %s %s"%(key,name))
|
||||
map=get_by_iid("map|%s"%key); blob_key=blob_key.get_result()
|
||||
if not map: map=Map(key=ndb.Key(Map,key),info=GG())
|
||||
|
||||
if file_info.content_type in ["image/jpg","image/jpeg","image/jpe","image/png","image/gif"]:
|
||||
if gf(map,"image_%s"%name):
|
||||
try: blobstore.delete(blob_keys=gf(map,"image_%s"%name).blob_key)
|
||||
except: log_trace()
|
||||
setattr(map.info,"image_%s"%name,cGG(blob_key=blob_key,
|
||||
content_type=file_info.content_type,gs_object_name=file_info.gs_object_name))
|
||||
if 0: jhtml(request,[{"type":"success","message":"Image uploaded"}])
|
||||
else: request.redirect("/map/"+key)
|
||||
map.put()
|
||||
else:
|
||||
blobstore.delete(blob_keys=blob_key)
|
||||
if 0: jhtmle(request,"Not an image")
|
||||
else: request.response.set_data("Not an image")
|
||||
def get(): request.post()
|
||||
|
||||
class GCSServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
|
||||
def get(resource):
|
||||
#resource = str(urllib.unquote(resource))
|
||||
#blob_key=blobstore.create_gs_key(resource)
|
||||
#request.send_blob(blob_key)
|
||||
logging.info("here")
|
||||
resource = str(urllib.unquote(resource))
|
||||
request.send_blob(resource)
|
||||
|
||||
application = webapp.WSGIApplication([
|
||||
('/admin/upload', PhotoUploader),
|
||||
('/admin/upload/handler', PhotoUpload),
|
||||
('/upload/tileset.*',TileUpload),
|
||||
('/tileset/(.*)\.png',GCSServeHandler),
|
||||
],debug=is_sdk)
|
||||
@@ -61,7 +61,7 @@
|
||||
</div>
|
||||
<script>
|
||||
var codemirror = CodeMirror(function(current){$("#code").replaceWith(current);},{
|
||||
value: "domain=gdi(self); user=get_user(self,domain); user_data=get_user_data(user)\n",
|
||||
value: "domain=gdi(request); user=get_user(request,domain); user_data=get_user_data(user)\n",
|
||||
mode: "python",
|
||||
indentUnit:4,
|
||||
indentWithTabs:true,
|
||||
|
||||
Reference in New Issue
Block a user