93 lines
2.9 KiB
Python
93 lines
2.9 KiB
Python
import mimetypes
|
|
import logging
|
|
import hashlib
|
|
import os
|
|
|
|
from django.db.transaction import atomic
|
|
from django.db.models import Q
|
|
from django.core.files.base import ContentFile
|
|
from django.core.files.storage import Storage
|
|
from django.core.urlresolvers import reverse
|
|
|
|
from .models import DBFile
|
|
|
|
L = logging.getLogger(__name__)
|
|
|
|
|
|
def _get_object(param):
|
|
return DBFile.objects.filter(Q(name=param)|Q(filehash=param)).first()
|
|
|
|
|
|
class DBFileStorage(Storage):
|
|
"""
|
|
This is the Test Database file upload storage backend.
|
|
This is used so that in our test database we always have uploaded
|
|
files.
|
|
|
|
To read more about how to set it up and configure it:
|
|
https://docs.djangoproject.com/en/1.8/howto/custom-file-storage
|
|
"""
|
|
|
|
def _open(self, name, mode='rb'):
|
|
the_file = DBFile.objects.get(pk=name)
|
|
return ContentFile(the_file.b64.decode('base64'))
|
|
|
|
@atomic
|
|
def _save(self, name, content, max_length=None):
|
|
"""
|
|
The save method does most of the 'magic'.
|
|
It stores the contents of the file as a base64 string.
|
|
It then takes the filename, and tries to get the mimetype from that
|
|
(for rendering)
|
|
Then it takes the md5 of the read file and uses that as the "unique"
|
|
key to access the file.
|
|
Then it checks if the file exists and if it doesn't, it will create
|
|
the entry in the database.
|
|
|
|
:return str: the name(md5) to look up the file by.
|
|
"""
|
|
if hasattr(content.file, "read"):
|
|
read_data = content.file.read()
|
|
else:
|
|
read_data = content.file.encode('utf8')
|
|
b64 = read_data.encode('base64')
|
|
|
|
# USE mimetypes.guess_type as an attempt at getting the content type.
|
|
ct = mimetypes.guess_type(name)[0]
|
|
|
|
# After we get the mimetype by name potentially, mangle it.
|
|
filehash = hashlib.md5(read_data).hexdigest()
|
|
|
|
# create the file, or just return name if the exact file already exists
|
|
if not DBFile.objects.filter(pk=name).exists():
|
|
the_file = DBFile(
|
|
name=os.path.basename(name),
|
|
filehash=filehash,
|
|
content_type=ct,
|
|
b64=b64)
|
|
the_file.save()
|
|
return filehash
|
|
|
|
def get_available_name(self, name, max_length=None):
|
|
return name
|
|
|
|
def path(self, name):
|
|
dbf = _get_object(name)
|
|
return dbf.name
|
|
|
|
def delete(self, name):
|
|
assert name, "The name argument is not allowed to be empty."
|
|
# name is the Pk, so it will be unique, deleting on the QS so
|
|
# that it fails silently if the file doesn't exist.
|
|
DBFile.objects.filter(pk=name).delete()
|
|
|
|
def exists(self, name):
|
|
return DBFile.objects.filter(pk=name).exists()
|
|
|
|
def size(self, name):
|
|
dbf = DBFile.objects.get(pk=name)
|
|
return len(dbf.b64)
|
|
|
|
def url(self, name):
|
|
return reverse('dbstorage_file', args=(name,))
|