Flask-Cloudy 0.10.0

This commit is contained in:
Mardix
2015-07-30 00:46:30 -04:00
parent 618ce43487
commit a9a15d3fc6
10 changed files with 183 additions and 39 deletions
+2 -1
View File
@@ -1,5 +1,6 @@
0.7.0
0.10.0
- Removed LOCAL_PATH configuration. Use CONTAINER as the LOCAL_PATH
- Change config prefix to STORAGE_*
0.6.0
- More pythonic
+14 -8
View File
@@ -34,7 +34,7 @@ For local file storage, it also provides a flask endpoint to access the files.
@app.route("/upload", methods=["POST", "GET"]):
def upload():
if request.method == "POST":
file = request.file.get("file")
file = request.files.get("file")
my_upload = storage.upload(file)
# some useful properties
@@ -185,7 +185,7 @@ Storage:
The **Storage** class allows you to access, upload, get an object from the Storage.
##### Storage(provider, key=None, secret=None, container=None)
##### Storage(provider, key=None, secret=None, container=None, allowed_extensions=None)
- provider: the storage provider:
@@ -209,6 +209,8 @@ The **Storage** class allows you to access, upload, get an object from the Stora
- For cloud storage, use the **BUCKET NAME**
- For LOCAL provider, it's the directory path where to access the files
- allowed_extensions: List of extensions to upload to upload
##### Storage.init_app(app)
@@ -239,7 +241,7 @@ It will also setup a server endpoint when STORAGE_PROVIDER == LOCAL
@app.route("/upload", methods=["POST", "GET"]):
def upload():
if request.method == "POST":
file = request.file.get("file")
file = request.files.get("file")
my_upload = storage.upload(file)
# some useful properties
@@ -452,11 +454,15 @@ To save the object to a local path
print(my_new_file) # Will print -> /my/new/path/my_object.txt
##### Object.download(name=None)
##### Object.download_url(timeout=60, name=None)
Return a URL that triggers the browser download of the file.
Use the url to download the file
- timeout: int - The time in seconds to give access to the url
- name: str - for LOCAL only, to rename the file being downloaded
.
storage = Storage(provider, key, secret, container)
my_object = storage.get("my_object.txt")
@@ -475,12 +481,12 @@ Use the url to download the file
---
---
I hope you find this library useful, enjoy!
Thank you
Mardix :)
---
License: MIT - Copyright 2015 Mardix
License: MIT - Copyright 2015 Mardix
+1
View File
@@ -0,0 +1 @@
__author__ = 'mardochee.macxis'
+37
View File
@@ -0,0 +1,37 @@
from flask import Flask, request, render_template, redirect, abort, url_for
from flask_cloudy import Storage
app = Flask(__name__)
app.config.update({
"STORAGE_PROVIDER": "LOCAL",
"STORAGE_CONTAINER": "./data",
"STORAGE_KEY": "",
"STORAGE_SECRET": "",
"STORAGE_SERVER": True
})
storage = Storage()
storage.init_app(app)
@app.route("/")
def index():
return render_template("index.html", storage=storage)
@app.route("/view/<path:object_name>")
def view(object_name):
obj = storage.get(object_name)
print obj.name
return render_template("view.html", obj=obj)
@app.route("/upload", methods=["POST"])
def upload():
file = request.files.get("file")
my_object = storage.upload(file)
return redirect(url_for("view", object_name=my_object.name))
if __name__ == "__main__":
app.run(debug=True, port=5000)
+3
View File
@@ -0,0 +1,3 @@
Hello World!
from flask_cloud import Storage
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Flask-Cloudy</title>
</head>
<body>
<h1>Flask-Cloudy</h1>
<form action="{{ url_for('upload') }}" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="file" name="file" id="fileToUpload"> <br>
<input type="submit" value="Upload File" name="submit">
</form>
<hr>
<h3>List of files available on the storage:</h3>
<table>
<thead>
<th>Name</th>
<th>Size</th>
</thead>
<tbody>
{% for obj in storage %}
<tr>
<td><a href="{{ url_for('view', object_name=obj.name) }}">{{ obj.name }}</a></td>
<td>{{ obj.size }} bytes</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
+23
View File
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Flask-Cloudy</title>
</head>
<body>
<h1>Flask-Cloudy: View File</h1>
<a href="{{ url_for('index') }}"><- Home</a>
<br> <br>
Name: {{ obj.name }} <br><br>
Size: {{ obj.size }} bytes <br><br>
Short url: {{ obj.short_url }} <br><br>
View file: <a href="{{ obj.url }}">{{ obj.url }}</a> <br><br>
{% set download_url = obj.download_url() %}
Download: <a href="{{ download_url }}">{{ download_url }}</a> <br><br>
</body>
</html>
+60 -23
View File
@@ -3,6 +3,10 @@ Flask-Cloudy
"""
import os
import datetime
import base64
import hmac
import hashlib
import warnings
from werkzeug.utils import secure_filename
from werkzeug.datastructures import FileStorage
@@ -13,9 +17,11 @@ from libcloud.storage.types import Provider, ObjectDoesNotExistError
from libcloud.storage.providers import DRIVERS, get_driver
from libcloud.storage.base import Object as BaseObject, StorageDriver
from libcloud.storage.drivers import local
from six.moves.urllib.parse import urlparse, urlunparse, urljoin
from six.moves.urllib.parse import urlparse, urlunparse, urljoin, urlencode
import slugify
SERVER_ENDPOINT = "FLASK_CLOUDY_SERVER"
EXTENSIONS = {
@@ -126,7 +132,7 @@ class Storage(object):
:param secret: str - provider secret
:param container: str - the name of the container (bucket or a dir name if local)
:param allowed_extensions: list - extensions allowed for upload
:param app: Flask object -
:param app: object - Flask instance
:param kwargs: any other params will pass to the provider initialization
:return:
"""
@@ -134,10 +140,10 @@ class Storage(object):
if app:
self.init_app(app)
if allowed_extensions:
self.allowed_extensions = allowed_extensions
if provider:
if allowed_extensions:
self.allowed_extensions = allowed_extensions
kwparams = {
"key": key,
"secret": secret
@@ -343,11 +349,15 @@ class Storage(object):
obj = self.get(object_name)
if obj:
dl = request.args.get("dl")
name = request.args.get("name")
name = request.args.get("name", obj.name)
if get_file_extension(name) != obj.extension:
name += ".%s" % obj.extension
_url = obj.get_cdn_url()
return send_file(_url,
as_attachment=True if dl else False,
attachment_filename=name or False,
attachment_filename=name,
conditional=True)
else:
abort(404)
@@ -369,7 +379,7 @@ class Object(object):
container
@method
download()
download() use save_to() instead
delete()
"""
@@ -492,21 +502,6 @@ class Object(object):
"""
return "%s/%s" % (self.container.name, self.name)
def download(self, name=None, signed=True):
"""
Trigger a browse download
:return:
"""
if "local" in self.driver.name.lower():
return url_for(SERVER_ENDPOINT,
object_name=self.path,
dl=1,
name=name)
else:
if signed:
pass
pass
def save_to(self, destination, name=None, overwrite=False, delete_on_failure=True):
"""
To save the object in a local path
@@ -527,3 +522,45 @@ class Object(object):
overwrite_existing=overwrite,
delete_on_failure=delete_on_failure)
return obj_path if file else None
def download_url(self, timeout=60, name=None):
"""
Trigger a browse download
:param timeout: int - Time in seconds to expire the download
:param name: str - for LOCAL only, to rename the file being downloaded
:return: str
"""
if "local" in self.driver.name.lower():
return url_for(SERVER_ENDPOINT,
object_name=self.name,
dl=1,
name=name,
_external=True)
else:
driver_name = self.driver.name.lower()
expires = (datetime.datetime.now()
+ datetime.timedelta(seconds=timeout)).strftime("%s")
if 's3' in driver_name or 'google' in driver_name:
s2s = "GET\n\n\n{expires}\n/{object_name}"\
.format(expires=expires, object_name=self.path)
h = hmac.new(self.driver.secret, s2s, hashlib.sha1)
s = base64.encodestring(h.digest()).strip()
_keyIdName = "AWSAccessKeyId" if "s3" in driver_name else "GoogleAccessId"
params = {
_keyIdName: self.driver.key,
"Expires": expires,
"Signature": s
}
urlkv = urlencode(params)
return "%s?%s" % (self.secure_url, urlkv)
elif 'cloudfiles' in driver_name:
return self.driver.ex_get_object_temp_url(self._obj,
method="GET",
timeout=expires)
else:
raise NotImplemented("This provider '%s' doesn't support or "
"doesn't have a signed url "
"implemented yet" % self.provider_name)
+1 -1
View File
@@ -19,7 +19,7 @@ Supported storage:
from setuptools import setup, find_packages
__NAME__ = "Flask-Cloudy"
__version__ = "0.7.0"
__version__ = "0.10.0"
__author__ = "Mardix"
__license__ = "MIT"
__copyright__ = "2015"
+3 -6
View File
@@ -24,12 +24,6 @@ class App(object):
STORAGE_ALLOWED_EXTENSIONS=[])
def _setup_function():
pass
def _teardown_function():
pass
def test_get_file_extension():
filename = "hello.jpg"
assert get_file_extension(filename) == "jpg"
@@ -170,3 +164,6 @@ def test_save_to():
file2 = o.save_to(CWD + "/data", name="my_new_file", overwrite=True)
assert os.path.isfile(file)
assert file2 == CWD + "/data/my_new_file.txt"
from flask_cloudy import Storage