WIP: File Preview support
This commit is contained in:
@@ -178,7 +178,7 @@ class ValidateCustomFields(Validator):
|
|||||||
|
|
||||||
|
|
||||||
def post_item(entry, data):
|
def post_item(entry, data):
|
||||||
post_internal(entry, data)
|
return post_internal(entry, data)
|
||||||
|
|
||||||
|
|
||||||
app = Eve(validator=ValidateCustomFields, auth=CustomTokenAuth)
|
app = Eve(validator=ValidateCustomFields, auth=CustomTokenAuth)
|
||||||
|
@@ -1,19 +1,45 @@
|
|||||||
import os
|
import os
|
||||||
|
import hashlib
|
||||||
|
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
from flask import request
|
from flask import request
|
||||||
|
|
||||||
from application import app
|
from application import app
|
||||||
|
from application import post_item
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
from bson import ObjectId
|
||||||
|
|
||||||
|
RFC1123_DATE_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
|
||||||
|
|
||||||
|
|
||||||
file_server = Blueprint('file_server', __name__,
|
file_server = Blueprint('file_server', __name__,
|
||||||
template_folder='templates',
|
template_folder='templates',
|
||||||
static_folder='static/storage')
|
static_folder='static/storage')
|
||||||
|
|
||||||
|
|
||||||
@file_server.route('/file/thumbnail/<file_name>')
|
def hashfile(afile, hasher, blocksize=65536):
|
||||||
def thumbnail(file_name=None):
|
buf = afile.read(blocksize)
|
||||||
|
while len(buf) > 0:
|
||||||
|
hasher.update(buf)
|
||||||
|
buf = afile.read(blocksize)
|
||||||
|
return hasher.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
@file_server.route('/build_previews/<file_name>')
|
||||||
|
def build_previews(file_name=None):
|
||||||
|
from pymongo import MongoClient
|
||||||
|
|
||||||
|
# Get File
|
||||||
|
client = MongoClient()
|
||||||
|
db = client.eve
|
||||||
|
file_ = db.files.find({"path": "{0}".format(file_name)})
|
||||||
|
file_ = file_[0]
|
||||||
|
user = file_['user']
|
||||||
|
|
||||||
folder_name = file_name[:2]
|
folder_name = file_name[:2]
|
||||||
file_folder_path = os.path.join(app.config['FILE_STORAGE'],
|
file_folder_path = os.path.join(app.config['FILE_STORAGE'],
|
||||||
folder_name)
|
folder_name)
|
||||||
@@ -22,9 +48,6 @@ def thumbnail(file_name=None):
|
|||||||
if not os.path.isfile(file_path):
|
if not os.path.isfile(file_path):
|
||||||
return "", 404
|
return "", 404
|
||||||
|
|
||||||
format_ = "jpeg"
|
|
||||||
formats = ["jpeg", "png"]
|
|
||||||
size = "s"
|
|
||||||
sizes = ["xs", "s", "m", "l", "xl"]
|
sizes = ["xs", "s", "m", "l", "xl"]
|
||||||
size_dict = {
|
size_dict = {
|
||||||
"xs": (32, 32),
|
"xs": (32, 32),
|
||||||
@@ -33,38 +56,100 @@ def thumbnail(file_name=None):
|
|||||||
"l": (640, 480),
|
"l": (640, 480),
|
||||||
"xl": (1024, 768)
|
"xl": (1024, 768)
|
||||||
}
|
}
|
||||||
if "format" in request.args:
|
|
||||||
if request.args['format'] in formats:
|
|
||||||
format_ = request.args['format']
|
|
||||||
if "size" in request.args:
|
|
||||||
if request.args['size'] in sizes:
|
|
||||||
size = request.args['size']
|
|
||||||
|
|
||||||
# The Thumbnail already exist?
|
# Generate
|
||||||
thumbnail_folder_path = os.path.join(file_folder_path, size)
|
preview_list = []
|
||||||
thumbnail_file_path = os.path.join(thumbnail_folder_path, file_name)
|
for size in sizes:
|
||||||
if os.path.isfile(thumbnail_file_path):
|
resized_file_name = "{0}_{1}".format(size, file_name)
|
||||||
file_static_path = os.path.join("", folder_name, size, file_name)
|
resized_file_path = os.path.join(
|
||||||
return file_server.send_static_file(file_static_path)
|
app.config['FILE_STORAGE'],
|
||||||
|
resized_file_name)
|
||||||
|
|
||||||
# Create thumbnail
|
# Create thumbnail
|
||||||
if not os.path.exists(thumbnail_folder_path):
|
if not os.path.isfile(resized_file_path):
|
||||||
os.mkdir(thumbnail_folder_path)
|
|
||||||
if not os.path.isfile(thumbnail_file_path):
|
|
||||||
try:
|
try:
|
||||||
im = Image.open(file_path)
|
im = Image.open(file_path)
|
||||||
except IOError:
|
except IOError:
|
||||||
return "", 500
|
return "", 500
|
||||||
im.thumbnail(size_dict[size])
|
im.thumbnail(size_dict[size])
|
||||||
try:
|
try:
|
||||||
im.save(thumbnail_file_path)
|
im.save(resized_file_path)
|
||||||
except IOError:
|
except IOError:
|
||||||
raise
|
|
||||||
return "", 500
|
return "", 500
|
||||||
|
|
||||||
file_static_path = os.path.join("", folder_name, size, file_name)
|
# file_static_path = os.path.join("", folder_name, size, file_name)
|
||||||
return file_server.send_static_file(file_static_path)
|
picture_file_file = open(resized_file_path, 'rb')
|
||||||
return "", 500
|
hash_ = hashfile(picture_file_file, hashlib.md5())
|
||||||
|
name = "{0}{1}".format(hash_,
|
||||||
|
os.path.splitext(file_name)[1])
|
||||||
|
picture_file_file.close()
|
||||||
|
description = "Thumbnail {0} for file {1}".format(
|
||||||
|
size, file_name)
|
||||||
|
|
||||||
|
prop = {}
|
||||||
|
prop['name'] = resized_file_name
|
||||||
|
prop['description'] = description
|
||||||
|
prop['user'] = user
|
||||||
|
prop['is_preview'] = True
|
||||||
|
prop['preview_name'] = "{0}_png".format(size)
|
||||||
|
# TODO set proper contentType and length
|
||||||
|
prop['contentType'] = 'image/png'
|
||||||
|
prop['length'] = 0
|
||||||
|
prop['uploadDate'] = datetime.strftime(
|
||||||
|
datetime.now(), RFC1123_DATE_FORMAT)
|
||||||
|
prop['md5'] = hash_
|
||||||
|
prop['filename'] = resized_file_name
|
||||||
|
prop['backend'] = 'attract'
|
||||||
|
prop['path'] = name
|
||||||
|
|
||||||
|
entry = post_item ('files', prop)
|
||||||
|
if entry[0]['_status'] == 'ERR':
|
||||||
|
entry = db.files.find({"path": name})
|
||||||
|
|
||||||
|
entry = entry[0]
|
||||||
|
prop['_id'] = entry['_id']
|
||||||
|
|
||||||
|
new_folder_name = name[:2]
|
||||||
|
new_folder_path = os.path.join(
|
||||||
|
app.config['FILE_STORAGE'],
|
||||||
|
new_folder_name)
|
||||||
|
new_file_path = os.path.join(
|
||||||
|
new_folder_path,
|
||||||
|
name)
|
||||||
|
|
||||||
|
if not os.path.exists(new_folder_path):
|
||||||
|
os.makedirs(new_folder_path)
|
||||||
|
|
||||||
|
# Clean up temporary file
|
||||||
|
os.rename(
|
||||||
|
resized_file_path,
|
||||||
|
new_file_path)
|
||||||
|
|
||||||
|
preview_list.append(str(prop['_id']))
|
||||||
|
#print (new_file_path)
|
||||||
|
|
||||||
|
# Add previews to file
|
||||||
|
previews = []
|
||||||
|
try:
|
||||||
|
previews = file_['previews']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
preview_list = preview_list + previews
|
||||||
|
|
||||||
|
#print (previews)
|
||||||
|
#print (preview_list)
|
||||||
|
#print (file_['_id'])
|
||||||
|
|
||||||
|
file_ = db.files.update(
|
||||||
|
{"_id": ObjectId(file_['_id'])},
|
||||||
|
{"$set": {"previews": preview_list}}
|
||||||
|
)
|
||||||
|
|
||||||
|
#print (file_)
|
||||||
|
|
||||||
|
return "", 200
|
||||||
|
|
||||||
|
|
||||||
@file_server.route('/file', methods=['POST'])
|
@file_server.route('/file', methods=['POST'])
|
||||||
@file_server.route('/file/<file_name>')
|
@file_server.route('/file/<file_name>')
|
||||||
|
@@ -9,7 +9,7 @@ RESOURCE_METHODS = ['GET', 'POST', 'DELETE']
|
|||||||
# individual items (defaults to read-only item access).
|
# individual items (defaults to read-only item access).
|
||||||
ITEM_METHODS = ['GET', 'PUT', 'DELETE', 'PATCH']
|
ITEM_METHODS = ['GET', 'PUT', 'DELETE', 'PATCH']
|
||||||
|
|
||||||
PAGINATION_LIMIT = 100
|
PAGINATION_LIMIT = 999
|
||||||
|
|
||||||
# To be implemented on Eve 0.6
|
# To be implemented on Eve 0.6
|
||||||
# RETURN_MEDIA_AS_URL = True
|
# RETURN_MEDIA_AS_URL = True
|
||||||
@@ -144,6 +144,12 @@ files_schema = {
|
|||||||
'type': 'string',
|
'type': 'string',
|
||||||
'required': True,
|
'required': True,
|
||||||
},
|
},
|
||||||
|
'is_preview': {
|
||||||
|
'type': 'boolean'
|
||||||
|
},
|
||||||
|
'preview_name': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
'user': {
|
'user': {
|
||||||
'type': 'objectid',
|
'type': 'objectid',
|
||||||
'required': True,
|
'required': True,
|
||||||
@@ -176,6 +182,18 @@ files_schema = {
|
|||||||
'path': {
|
'path': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
'required': True,
|
'required': True,
|
||||||
|
'unique': True,
|
||||||
|
},
|
||||||
|
'previews': {
|
||||||
|
'type': 'list',
|
||||||
|
'schema': {
|
||||||
|
'type': 'objectid',
|
||||||
|
'data_relation': {
|
||||||
|
'resource': 'files',
|
||||||
|
'field': '_id',
|
||||||
|
'embeddable': True
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user