Files
jm2l/jm2l/upload.py
T

601 lines
25 KiB
Python
Raw Normal View History

2015-02-13 02:29:37 +01:00
# -*- coding: utf8 -*-
from pyramid.view import view_config, view_defaults
from pyramid.response import Response
from pyramid.exceptions import NotFound
2015-07-21 00:35:09 +02:00
from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest
2015-02-13 02:29:37 +01:00
from PIL import Image
import re, os, shutil
from os import path
import mimetypes
import magic
import subprocess
2020-07-26 17:38:55 +02:00
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
2015-02-13 02:29:37 +01:00
# Database access imports
2015-04-04 04:42:51 +02:00
from .models import User, Place, Tiers, Event, SallePhy
2015-07-21 00:35:09 +02:00
from .blenderthumbnailer import blend_extract_thumb, write_png
2016-10-08 21:42:16 +02:00
from jm2l.const import CurrentYear
2017-10-01 12:58:32 +02:00
from slugify import slugify
2015-02-13 02:29:37 +01:00
2020-07-26 17:38:55 +02:00
MIN_FILE_SIZE = 1 # bytes
MAX_FILE_SIZE = 500000000 # bytes
2015-02-13 02:29:37 +01:00
IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
ACCEPTED_MIMES = ['application/pdf',
2020-07-26 17:38:55 +02:00
'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.text-template',
'application/vnd.oasis.opendocument.graphics',
'application/vnd.oasis.opendocument.graphics-template',
'application/vnd.oasis.opendocument.presentation',
'application/vnd.oasis.opendocument.presentation-template',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-template',
'image/svg+xml',
'application/x-blender'
]
2015-02-13 02:29:37 +01:00
ACCEPT_FILE_TYPES = IMAGE_TYPES
THUMBNAIL_SIZE = 80
2020-07-26 17:38:55 +02:00
EXPIRATION_TIME = 300 # seconds
IMAGEPATH = ['images']
DOCPATH = ['document']
THUMBNAILPATH = ['images', 'thumbnails']
2015-02-13 02:29:37 +01:00
# change the following to POST if DELETE isn't supported by the webserver
2020-07-26 17:38:55 +02:00
DELETEMETHOD = "DELETE"
2015-02-13 02:29:37 +01:00
mimetypes.init()
2020-07-26 17:38:55 +02:00
class MediaPath():
2018-07-01 12:19:47 +02:00
def get_all(self, media_table, linked_id, MediaType=None):
filelist = list()
curpath = self.get_mediapath(media_table, linked_id, None)
2020-07-26 17:38:55 +02:00
thumbpath = os.path.join(curpath, 'thumbnails')
2018-07-01 12:19:47 +02:00
if not os.path.isdir(curpath) or not os.path.isdir(thumbpath):
return list()
for f in os.listdir(curpath):
2020-07-26 17:38:55 +02:00
filename, ext = os.path.splitext(f)
if os.path.isdir(os.path.join(curpath, f)):
2018-07-01 12:19:47 +02:00
continue
if f.endswith('.type'):
continue
if f:
ress_url = '/image/%s/%d/%s' % (media_table, linked_id, f.replace(" ", "%20"))
2020-07-26 17:38:55 +02:00
thumb_url = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ", "%20"))
2018-07-01 12:19:47 +02:00
if MediaType is None:
2020-07-26 17:38:55 +02:00
if os.path.exists(os.path.join(thumbpath, f + ".jpg")):
filelist.append((ress_url, thumb_url + ".jpg"))
2018-07-01 13:24:48 +02:00
else:
filelist.append((ress_url, thumb_url))
2020-07-26 17:38:55 +02:00
elif MediaType == 'Image' and len(os.path.splitext(filename)[1]) == 0:
2018-07-01 12:19:47 +02:00
filelist.append((ress_url, thumb_url))
2020-07-26 17:38:55 +02:00
elif MediaType == 'Other' and len(os.path.splitext(filename)[1]):
2018-07-01 12:19:47 +02:00
filelist.append((ress_url, thumb_url))
return filelist
def get_list(self, media_table, linked_id, MediaType=None):
2015-02-13 02:29:37 +01:00
filelist = list()
curpath = self.get_mediapath(media_table, linked_id, None)
if not os.path.isdir(curpath):
return list()
for f in os.listdir(curpath):
2020-07-26 17:38:55 +02:00
if os.path.isdir(os.path.join(curpath, f)):
2015-02-13 02:29:37 +01:00
continue
if f.endswith('.type'):
continue
if f:
2020-07-26 17:38:55 +02:00
filename, ext = os.path.splitext(f)
tmpurl = '/image/%s/%d/%s' % (media_table, linked_id, f.replace(" ", "%20"))
if MediaType is None:
filelist.append(tmpurl)
2020-07-26 17:38:55 +02:00
elif MediaType == 'Image' and ext.lower() in ['.gif', '.jpg', '.png', '.svg', '.jpeg']:
filelist.append(tmpurl)
2020-07-26 17:38:55 +02:00
elif MediaType == 'Other' and ext.lower() not in ['.gif', '.jpg', '.png', '.svg', '.jpeg']:
filelist.append(tmpurl)
2015-02-13 02:29:37 +01:00
return filelist
2020-07-26 17:38:55 +02:00
def get_thumb(self, media_table, linked_id, MediaType=None):
2015-02-13 02:29:37 +01:00
filelist = list()
curpath = self.get_mediapath(media_table, linked_id, None)
2020-07-26 17:38:55 +02:00
curpath = os.path.join(curpath, 'thumbnails')
2015-02-13 02:29:37 +01:00
if not os.path.isdir(curpath):
return list()
for f in os.listdir(curpath):
2020-07-26 17:38:55 +02:00
filename, ext = os.path.splitext(f)
if os.path.isdir(os.path.join(curpath, f)):
2015-02-13 02:29:37 +01:00
continue
if f.endswith('.type'):
continue
if f:
2020-07-26 17:38:55 +02:00
tmpurl = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ", "%20"))
if MediaType is None:
filelist.append(tmpurl)
2020-07-26 17:38:55 +02:00
elif MediaType == 'Image' and len(os.path.splitext(filename)[1]) == 0:
filelist.append(tmpurl)
2020-07-26 17:38:55 +02:00
elif MediaType == 'Other' and len(os.path.splitext(filename)[1]):
filelist.append(tmpurl)
2020-07-26 17:38:55 +02:00
return filelist
2017-09-30 20:19:20 +02:00
def move_mediapath(self, media_table, from_id, to_id):
"""
Move target media folder to follow database
:param media_table: type of media
:param from_id: source
:param to_id: destination
:return: Error if any
"""
if media_table in ['tiers', 'place', 'salle', 'users']:
2020-07-26 17:38:55 +02:00
src = IMAGEPATH + [media_table, from_id]
dst = IMAGEPATH + [media_table, to_id]
2017-09-30 20:19:20 +02:00
else:
raise RuntimeError("Sorry, Media '%s' not supported yet for move." % media_table)
src_path = os.path.join('jm2l/upload', *src)
dst_path = os.path.join('jm2l/upload', *dst)
if not os.path.isdir(src_path):
# Nothing to do ...
return False
if os.path.isdir(dst_path):
raise RuntimeError('Destination path already exist')
shutil.move(src_path, dst_path)
return True
2015-02-13 02:29:37 +01:00
def get_mediapath(self, media_table, linked_id, name):
2017-09-30 20:19:20 +02:00
"""
:param media_table: type of media
:param linked_id: id of media
:param name: filename
:return: full relative path on server side
"""
2015-02-13 02:29:37 +01:00
linked_id = str(linked_id)
if media_table in ['tiers', 'place', 'salle']:
# Retrieve Slug
2020-07-26 17:38:55 +02:00
if media_table == 'tiers':
2015-02-13 02:29:37 +01:00
slug = Tiers.by_id(linked_id).slug
2020-07-26 17:38:55 +02:00
if media_table == 'place':
2017-10-01 12:58:32 +02:00
slug = Place.by_id(linked_id).slug or slugify(Place.by_id(linked_id).name)
2020-07-26 17:38:55 +02:00
if media_table == 'salle':
2015-04-04 04:42:51 +02:00
slug = SallePhy.by_id(linked_id).slug
2020-07-26 17:38:55 +02:00
p = IMAGEPATH + [media_table, slug]
elif media_table == 'presse':
2015-02-13 02:29:37 +01:00
# Use Year in linked_id
2020-07-26 17:38:55 +02:00
p = IMAGEPATH + [media_table, linked_id]
elif media_table == 'tasks':
2015-02-13 02:29:37 +01:00
# Use Current Year
2020-07-26 17:38:55 +02:00
p = IMAGEPATH + [str(CurrentYear), media_table, linked_id]
elif media_table == 'poles':
2015-03-23 09:53:12 +01:00
# Use Current Year
2020-07-26 17:38:55 +02:00
p = IMAGEPATH + [str(CurrentYear), media_table, linked_id]
2015-02-13 02:29:37 +01:00
elif media_table in ['RIB', 'Justif']:
slug = User.by_id(linked_id).slug
2020-07-26 17:38:55 +02:00
p = IMAGEPATH + ['users', slug, media_table]
2017-09-30 20:19:20 +02:00
elif media_table in ['users', 'badge']:
user = User.by_id(linked_id)
if not user:
raise HTTPNotFound()
else:
slug = user.slug
2020-07-26 17:38:55 +02:00
p = IMAGEPATH + [media_table, slug]
elif media_table == 'event':
2015-02-13 02:29:37 +01:00
ev = Event.by_id(linked_id)
slug = ev.slug
year = ev.for_year
2020-07-26 17:38:55 +02:00
p = IMAGEPATH + ['event', str(year), slug]
2015-02-13 02:29:37 +01:00
if name:
2020-07-26 17:38:55 +02:00
p += [name]
2015-02-13 02:29:37 +01:00
TargetPath = os.path.join('jm2l/upload', *p)
if not os.path.isdir(os.path.dirname(TargetPath)):
2015-10-31 17:31:03 +01:00
try:
os.makedirs(os.path.dirname(TargetPath))
2020-07-26 17:38:55 +02:00
except OSError as e:
2015-10-31 17:31:03 +01:00
if e.errno != 17:
raise e
2020-07-26 17:38:55 +02:00
return os.path.join('jm2l/upload', *p)
2015-02-13 02:29:37 +01:00
def ExtMimeIcon(self, mime):
2020-07-26 17:38:55 +02:00
if mime == 'application/pdf':
2015-02-13 02:29:37 +01:00
return "/img/PDF.png"
2015-07-21 00:35:09 +02:00
def check_blend_file(self, fileobj):
head = fileobj.read(12)
fileobj.seek(0)
if head[:2] == b'\x1f\x8b': # gzip magic
import zlib
head = zlib.decompress(fileobj.read(), 31)[:12]
fileobj.seek(0)
if head.startswith(b'BLENDER'):
return True
def get_mimetype_from_file(self, fileobj):
mimetype = magic.from_buffer(fileobj.read(1024), mime=True)
fileobj.seek(0)
# Check if the binary file is a blender file
2020-07-26 17:38:55 +02:00
if (mimetype == "application/octet-stream" or mimetype == "application/x-gzip") and self.check_blend_file(
fileobj):
2015-07-21 00:35:09 +02:00
return "application/x-blender", True
else:
return mimetype, False
def get_mimetype(self, name):
""" This function return the mime-type based on .type file """
try:
with open(self.mediapath(name) + '.type', 'r', 16) as f:
mime = f.read()
return mime
except IOError:
return None
2020-07-26 17:38:55 +02:00
2015-02-13 02:29:37 +01:00
@view_defaults(route_name='media_upload')
class MediaUpload(MediaPath):
def __init__(self, request):
self.request = request
self.media_table = self.request.matchdict.get('media_table')
2015-12-05 14:01:03 +01:00
self.display_only = False
if self.media_table.startswith('_'):
self.display_only = True
self.media_table = self.media_table[1:]
2015-02-13 02:29:37 +01:00
self.linked_id = self.request.matchdict.get('uid')
if not self.linked_id.isdigit():
raise HTTPBadRequest('Wrong Parameter')
request.response.headers['Access-Control-Allow-Origin'] = '*'
request.response.headers['Access-Control-Allow-Methods'] = 'OPTIONS, HEAD, GET, POST, PUT, DELETE'
def mediapath(self, name):
return self.get_mediapath(self.media_table, self.linked_id, name)
def validate(self, result, filecontent):
2015-07-21 00:35:09 +02:00
""" Do some basic check to the uploaded file before to accept it """
# Try to determine mime type from content uploaded
found_mime = magic.from_buffer(filecontent.read(1024), mime=True)
2015-02-13 02:29:37 +01:00
filecontent.seek(0)
2020-07-26 17:38:55 +02:00
2015-07-21 00:35:09 +02:00
# Do a special statement for specific detected mime type
if found_mime in ["application/octet-stream", "application/x-gzip"]:
# Lets see if it's a bender file
if self.check_blend_file(filecontent):
found_mime = "application/x-blender"
# MonKey Patch of content type
2020-07-26 17:38:55 +02:00
result['type'] = found_mime
# Reject mime type that don't match
if found_mime != result['type']:
2015-07-21 00:35:09 +02:00
result['error'] = 'L\'extension du fichier ne correspond pas à son contenu - '
result['error'] += "( %s vs %s )" % (found_mime, result['type'])
2015-02-13 02:29:37 +01:00
return False
2015-07-21 00:35:09 +02:00
2015-02-13 02:29:37 +01:00
# Accept images and mime types listed
2015-07-21 00:35:09 +02:00
if not found_mime in ACCEPTED_MIMES:
if not (IMAGE_TYPES.match(found_mime)):
2015-02-13 02:29:37 +01:00
result['error'] = 'Ce type fichier n\'est malheureusement pas supporté. '
return False
2015-07-21 00:35:09 +02:00
2015-02-13 02:29:37 +01:00
if result['size'] < MIN_FILE_SIZE:
result['error'] = 'le fichier est trop petit'
elif result['size'] > MAX_FILE_SIZE:
result['error'] = 'le fichier est trop voluminueux'
2020-07-26 17:38:55 +02:00
# elif not ACCEPT_FILE_TYPES.match(file['type']):
2015-02-13 02:29:37 +01:00
# file['error'] = u'les type de fichiers acceptés sont png, jpg et gif'
else:
return True
2015-07-21 00:35:09 +02:00
2015-02-13 02:29:37 +01:00
return False
2015-07-21 00:35:09 +02:00
def get_file_size(self, fileobj):
2020-07-26 17:38:55 +02:00
fileobj.seek(0, 2) # Seek to the end of the file
size = fileobj.tell() # Get the position of EOF
fileobj.seek(0) # Reset the file position to the beginning
2015-02-13 02:29:37 +01:00
return size
2020-07-26 17:38:55 +02:00
def thumbnailurl(self, name):
return self.request.route_url('media_view', name='thumbnails',
media_table=self.media_table,
uid=self.linked_id) + '/' + name
2015-02-13 02:29:37 +01:00
2020-07-26 17:38:55 +02:00
def thumbnailpath(self, name):
2015-02-13 02:29:37 +01:00
origin = self.mediapath(name)
2020-07-26 17:38:55 +02:00
TargetPath = os.path.join(os.path.dirname(origin), 'thumbnails', name)
2015-02-13 02:29:37 +01:00
if not os.path.isdir(os.path.dirname(TargetPath)):
2020-07-26 17:38:55 +02:00
os.makedirs(os.path.dirname(TargetPath))
2015-02-13 02:29:37 +01:00
return TargetPath
def createthumbnail(self, filename):
2020-07-26 17:38:55 +02:00
image = Image.open(self.mediapath(filename))
2015-02-13 02:29:37 +01:00
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
timage.paste(
image,
2020-09-29 22:49:30 +02:00
(int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
2015-02-13 02:29:37 +01:00
TargetFileName = self.thumbnailpath(filename)
2020-09-29 22:49:30 +02:00
if not TargetFileName.endswith('png'):
timage = timage.convert('RGB')
2020-07-26 17:38:55 +02:00
timage.save(TargetFileName)
return self.thumbnailurl(os.path.basename(TargetFileName))
2015-02-13 02:29:37 +01:00
def pdfthumbnail(self, filename):
TargetFileName = self.thumbnailpath(filename)
2020-07-26 17:38:55 +02:00
Command = ["convert", "./%s[0]" % self.mediapath(filename), "./%s_.jpg" % TargetFileName]
2015-02-13 02:29:37 +01:00
Result = subprocess.call(Command)
2020-07-26 17:38:55 +02:00
if Result == 0:
image = Image.open(TargetFileName + "_.jpg")
pdf_indicator = Image.open("jm2l/static/img/PDF_Thumb_Stamp.png")
2015-02-13 02:29:37 +01:00
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail
timage.paste(
2020-07-26 17:38:55 +02:00
image,
2020-09-29 22:49:30 +02:00
(int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
2015-02-13 02:29:37 +01:00
# Stamp with PDF file type
timage.paste(
pdf_indicator,
2020-07-26 17:38:55 +02:00
(timage.size[0] - 30, timage.size[1] - 30),
2015-02-13 02:29:37 +01:00
pdf_indicator,
2020-07-26 17:38:55 +02:00
)
timage.convert('RGB').save(TargetFileName + ".jpg", 'JPEG')
os.unlink(TargetFileName + "_.jpg")
return self.thumbnailurl(os.path.basename(TargetFileName + ".jpg"))
2015-02-13 02:29:37 +01:00
return self.ExtMimeIcon('application/pdf')
2015-03-21 19:12:58 +01:00
def svgthumbnail(self, filename):
TargetFileName = self.thumbnailpath(filename)
2020-07-26 17:38:55 +02:00
Command = ["convert", "./%s[0]" % self.mediapath(filename), "./%s_.jpg" % TargetFileName]
2015-03-21 19:12:58 +01:00
Result = subprocess.call(Command)
2020-07-26 17:38:55 +02:00
if Result == 0:
image = Image.open(TargetFileName + "_.jpg")
pdf_indicator = Image.open("jm2l/static/img/svg-icon.png")
2015-03-21 19:12:58 +01:00
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail
timage.paste(
2020-07-26 17:38:55 +02:00
image,
2020-09-29 22:49:30 +02:00
(int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
2015-03-21 19:12:58 +01:00
# Stamp with PDF file type
timage.paste(
pdf_indicator,
2020-07-26 17:38:55 +02:00
(timage.size[0] - 30, timage.size[1] - 30),
2015-03-21 19:12:58 +01:00
pdf_indicator,
2020-07-26 17:38:55 +02:00
)
timage.convert('RGB').save(TargetFileName + ".jpg", 'JPEG')
os.unlink(TargetFileName + "_.jpg")
return self.thumbnailurl(os.path.basename(TargetFileName + ".jpg"))
2015-03-21 19:12:58 +01:00
return self.ExtMimeIcon('image/svg+xml')
2015-02-13 02:29:37 +01:00
def docthumbnail(self, filename):
TargetFileName = self.thumbnailpath(filename)
# let's take the thumbnail generated inside the document
Command = ["unzip", "-p", self.mediapath(filename), "Thumbnails/thumbnail.png"]
ThumbBytes = subprocess.check_output(Command)
2020-07-26 17:38:55 +02:00
image = Image.open(StringIO.StringIO(ThumbBytes))
2015-02-13 02:29:37 +01:00
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
# Use the correct stamp
2020-07-26 17:38:55 +02:00
f, ext = os.path.splitext(filename)
istamp = [('Writer', 'odt'),
('Impress', 'odp'),
('Calc', 'ods'),
('Draw', 'odg')]
stampfilename = filter(lambda x, y: ext.endswith(y), istamp)
stamp = Image.open("jm2l/static/img/%s-icon.png" % stampfilename[0][0])
2015-02-13 02:29:37 +01:00
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail
timage.paste(
2020-07-26 17:38:55 +02:00
image,
2020-09-29 22:49:30 +02:00
(int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
2015-02-13 02:29:37 +01:00
# Stamp with PDF file type
timage.paste(
stamp,
2020-07-26 17:38:55 +02:00
(timage.size[0] - 30, timage.size[1] - 30),
2015-02-13 02:29:37 +01:00
stamp,
2020-07-26 17:38:55 +02:00
)
timage.convert('RGB').save(TargetFileName + ".jpg", 'JPEG')
return self.thumbnailurl(os.path.basename(TargetFileName + ".jpg"))
2015-02-13 02:29:37 +01:00
2015-07-21 00:35:09 +02:00
def blendthumbnail(self, filename):
blendfile = self.mediapath(filename)
# Extract Thumb
if 0:
head = fileobj.read(12)
fileobj.seek(0)
2020-07-26 17:38:55 +02:00
2015-07-21 00:35:09 +02:00
if head[:2] == b'\x1f\x8b': # gzip magic
import zlib
head = zlib.decompress(fileobj.read(), 31)[:12]
2020-07-26 17:38:55 +02:00
fileobj.seek(0)
2015-07-21 00:35:09 +02:00
buf, width, height = blend_extract_thumb(blendfile)
if buf:
png = write_png(buf, width, height)
TargetFileName = self.thumbnailpath(filename)
image = Image.open(StringIO.StringIO(png))
2020-07-26 17:38:55 +02:00
blender_indicator = Image.open("jm2l/static/img/Blender_Thumb_Stamp.png")
2015-07-21 00:35:09 +02:00
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail
timage.paste(
image,
2020-09-29 22:49:30 +02:00
(int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
2015-07-21 00:35:09 +02:00
# Stamp with Blender file type
timage.paste(
blender_indicator,
2020-07-26 17:38:55 +02:00
(timage.size[0] - 30, timage.size[1] - 30),
2015-07-21 00:35:09 +02:00
blender_indicator,
2020-07-26 17:38:55 +02:00
)
timage.save(TargetFileName + ".png")
return self.thumbnailurl(os.path.basename(TargetFileName + ".png"))
2015-07-21 00:35:09 +02:00
return self.ExtMimeIcon('application/x-blender')
2020-07-26 17:38:55 +02:00
def fileinfo(self, name):
filename = self.mediapath(name)
2015-02-13 02:29:37 +01:00
f, ext = os.path.splitext(name)
2020-07-26 17:38:55 +02:00
if ext != '.type' and os.path.isfile(filename):
2015-02-13 02:29:37 +01:00
info = {}
info['name'] = name
info['size'] = os.path.getsize(filename)
info['url'] = self.request.route_url('media_view',
2020-07-26 17:38:55 +02:00
name=name,
media_table=self.media_table,
uid=self.linked_id)
2015-07-21 00:35:09 +02:00
mime = self.get_mimetype(name)
if IMAGE_TYPES.match(mime):
2015-02-13 02:29:37 +01:00
info['thumbnailUrl'] = self.thumbnailurl(name)
elif mime in ACCEPTED_MIMES:
thumb = self.thumbnailpath("%s%s" % (f, ext))
2015-07-21 00:35:09 +02:00
thumbext = ".jpg"
if mime == "application/x-blender":
thumbext = ".png"
2020-07-26 17:38:55 +02:00
if os.path.exists(thumb + thumbext):
info['thumbnailUrl'] = self.thumbnailurl(name) + thumbext
2015-02-13 02:29:37 +01:00
else:
info['thumbnailUrl'] = self.ExtMimeIcon(mime)
else:
info['thumbnailUrl'] = self.ExtMimeIcon(mime)
2015-12-05 14:01:03 +01:00
if not self.display_only:
info['deleteType'] = DELETEMETHOD
info['deleteUrl'] = self.request.route_url('media_upload',
2020-07-26 17:38:55 +02:00
sep='',
name='',
media_table=self.media_table,
uid=self.linked_id) + '/' + name
2015-12-05 14:01:03 +01:00
if DELETEMETHOD != 'DELETE':
info['deleteUrl'] += '&_method=DELETE'
2015-02-13 02:29:37 +01:00
return info
else:
return None
@view_config(request_method='OPTIONS')
def options(self):
return Response(body='')
@view_config(request_method='HEAD')
def options(self):
return Response(body='')
@view_config(request_method='GET', renderer="json")
def get(self):
p = self.request.matchdict.get('name')
if p:
return self.fileinfo(p)
else:
filelist = []
content = self.mediapath('')
if content and path.exists(content):
for f in os.listdir(content):
n = self.fileinfo(f)
if n:
filelist.append(n)
2020-07-26 17:38:55 +02:00
return {"files": filelist}
2015-02-13 02:29:37 +01:00
@view_config(request_method='DELETE', xhr=True, accept="application/json", renderer='json')
def delete(self):
filename = self.request.matchdict.get('name')
try:
os.remove(self.mediapath(filename) + '.type')
except IOError:
pass
except OSError:
2020-07-26 17:38:55 +02:00
pass
2015-02-13 02:29:37 +01:00
try:
os.remove(self.thumbnailpath(filename))
except IOError:
pass
2020-07-26 17:38:55 +02:00
except OSError:
2015-02-13 02:29:37 +01:00
pass
try:
2020-07-26 17:38:55 +02:00
os.remove(self.thumbnailpath(filename + ".jpg"))
2015-02-13 02:29:37 +01:00
except IOError:
pass
2020-07-26 17:38:55 +02:00
except OSError:
pass
2015-02-13 02:29:37 +01:00
try:
os.remove(self.mediapath(filename))
except IOError:
return False
return True
2020-07-26 17:38:55 +02:00
2015-02-13 02:29:37 +01:00
@view_config(request_method='POST', xhr=True, accept="application/json", renderer='json')
def post(self):
if self.request.matchdict.get('_method') == "DELETE":
return self.delete()
results = []
for name, fieldStorage in self.request.POST.items():
2020-09-29 22:49:30 +02:00
# if isinstance(fieldStorage, unicode):
# continue
2015-02-13 02:29:37 +01:00
result = {}
result['name'] = os.path.basename(fieldStorage.filename)
result['type'] = fieldStorage.type
result['size'] = self.get_file_size(fieldStorage.file)
2015-07-21 00:35:09 +02:00
2015-02-13 02:29:37 +01:00
if self.validate(result, fieldStorage.file):
2020-07-26 17:38:55 +02:00
filename, file_extension = os.path.splitext(result['name'])
local_filename = slugify(filename) + file_extension
2015-07-21 00:35:09 +02:00
# Keep mime-type in .type file
2020-07-26 17:38:55 +02:00
with open(self.mediapath(local_filename) + '.type', 'w') as f:
2015-02-13 02:29:37 +01:00
f.write(result['type'])
2020-07-26 17:38:55 +02:00
2015-07-21 00:35:09 +02:00
# Store uploaded file
fieldStorage.file.seek(0)
2020-07-26 17:38:55 +02:00
with open(self.mediapath(local_filename), 'wb') as f:
shutil.copyfileobj(fieldStorage.file, f)
2015-07-21 00:35:09 +02:00
2015-02-13 02:29:37 +01:00
if re.match(IMAGE_TYPES, result['type']):
result['thumbnailUrl'] = self.createthumbnail(local_filename)
2020-07-26 17:38:55 +02:00
elif result['type'] == 'application/pdf':
result['thumbnailUrl'] = self.pdfthumbnail(local_filename)
2020-07-26 17:38:55 +02:00
elif result['type'] == 'image/svg+xml':
result['thumbnailUrl'] = self.svgthumbnail(local_filename)
2015-02-13 02:29:37 +01:00
elif result['type'].startswith('application/vnd'):
result['thumbnailUrl'] = self.docthumbnail(local_filename)
2020-07-26 17:38:55 +02:00
elif result['type'] == 'application/x-blender':
result['thumbnailUrl'] = self.blendthumbnail(local_filename)
2015-02-13 02:29:37 +01:00
else:
result['thumbnailUrl'] = self.ExtMimeIcon(result['type'])
2015-07-21 00:35:09 +02:00
2015-02-13 02:29:37 +01:00
result['deleteType'] = DELETEMETHOD
result['deleteUrl'] = self.request.route_url('media_upload',
2020-07-26 17:38:55 +02:00
sep='',
name='',
media_table=self.media_table,
uid=self.linked_id) + '/' + local_filename
2015-02-13 02:29:37 +01:00
result['url'] = self.request.route_url('media_view',
2020-07-26 17:38:55 +02:00
media_table=self.media_table,
uid=self.linked_id,
name=local_filename)
2015-02-13 02:29:37 +01:00
if DELETEMETHOD != 'DELETE':
result['deleteUrl'] += '&_method=DELETE'
results.append(result)
2020-07-26 17:38:55 +02:00
return {"files": results}
2015-02-13 02:29:37 +01:00
@view_defaults(route_name='media_view')
class MediaView(MediaPath):
2020-07-26 17:38:55 +02:00
def __init__(self, request):
2015-02-13 02:29:37 +01:00
self.request = request
self.media_table = self.request.matchdict.get('media_table')
self.linked_id = self.request.matchdict.get('uid')
2020-07-26 17:38:55 +02:00
def mediapath(self, name):
2015-02-13 02:29:37 +01:00
return self.get_mediapath(self.media_table, self.linked_id, name)
2020-07-26 17:38:55 +02:00
@view_config(request_method='GET', http_cache=(EXPIRATION_TIME, {'public': True}))
2015-02-13 02:29:37 +01:00
def get(self):
name = self.request.matchdict.get('name')
2015-07-21 00:35:09 +02:00
self.request.response.content_type = self.get_mimetype(name)
try:
2020-07-26 17:38:55 +02:00
self.request.response.body_file = open(self.mediapath(name), 'rb', 10000)
except IOError:
raise NotFound
2015-02-13 02:29:37 +01:00
return self.request.response
##return Response(app_iter=ImgHandle, content_type = 'image/png')