Remove filehash, set pk to name (#33)
* Remove filehash, set pk to name * remove stale comment and dead block
This commit is contained in:
parent
4d29d41b07
commit
5b91a7b362
25
dbfilestorage/migrations/0005_auto_20170127_2037.py
Normal file
25
dbfilestorage/migrations/0005_auto_20170127_2037.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.4 on 2017-01-27 20:37
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('dbfilestorage', '0004_dbfile_mtime'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='dbfile',
|
||||||
|
name='filehash',
|
||||||
|
field=models.CharField(max_length=32),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='dbfile',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=100, primary_key=True, serialize=False),
|
||||||
|
),
|
||||||
|
]
|
19
dbfilestorage/migrations/0006_remove_dbfile_filehash.py
Normal file
19
dbfilestorage/migrations/0006_remove_dbfile_filehash.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.4 on 2017-01-27 20:42
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('dbfilestorage', '0005_auto_20170127_2037'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='dbfile',
|
||||||
|
name='filehash',
|
||||||
|
),
|
||||||
|
]
|
@ -7,8 +7,7 @@ class DBFile(models.Model):
|
|||||||
# This is kept as `name` and not something like `md5` because the file
|
# This is kept as `name` and not something like `md5` because the file
|
||||||
# operations pass around `name` as the identifier, so it's kept the same
|
# operations pass around `name` as the identifier, so it's kept the same
|
||||||
# to make sense.
|
# to make sense.
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100, primary_key=True)
|
||||||
filehash = models.CharField(max_length=32, primary_key=True)
|
|
||||||
|
|
||||||
# file data
|
# file data
|
||||||
content_type = models.CharField(max_length=100)
|
content_type = models.CharField(max_length=100)
|
||||||
@ -16,8 +15,8 @@ class DBFile(models.Model):
|
|||||||
mtime = models.DateTimeField(auto_now=True)
|
mtime = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"{filehash} <{content_type}>".format(
|
return u"{name} <{content_type}>".format(
|
||||||
filehash=self.filehash, content_type=self.content_type)
|
name=self.name, content_type=self.content_type)
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
if self.content_type is None:
|
if self.content_type is None:
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
import logging
|
import logging
|
||||||
import hashlib
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.db.transaction import atomic
|
from django.db.transaction import atomic
|
||||||
@ -15,7 +14,7 @@ L = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def _get_object(param):
|
def _get_object(param):
|
||||||
return DBFile.objects.filter(Q(name=param) | Q(filehash=param)).first()
|
return DBFile.objects.filter(name=param).first()
|
||||||
|
|
||||||
|
|
||||||
class DBFileStorage(Storage):
|
class DBFileStorage(Storage):
|
||||||
@ -55,21 +54,12 @@ class DBFileStorage(Storage):
|
|||||||
# USE mimetypes.guess_type as an attempt at getting the content type.
|
# USE mimetypes.guess_type as an attempt at getting the content type.
|
||||||
ct = mimetypes.guess_type(name)[0]
|
ct = mimetypes.guess_type(name)[0]
|
||||||
|
|
||||||
# After we get the mimetype by name potentially, mangle it.
|
|
||||||
filehash = hashlib.md5(read_data).hexdigest()
|
|
||||||
|
|
||||||
file_ext = os.path.splitext(name)[1]
|
|
||||||
if not file_ext:
|
|
||||||
file_ext = ".txt"
|
|
||||||
|
|
||||||
# create the file, or just return name if the exact file already exists
|
# create the file, or just return name if the exact file already exists
|
||||||
if not DBFile.objects.filter(filehash=filehash, name=name).exists():
|
if not DBFile.objects.filter(name=name).exists():
|
||||||
the_file = DBFile(
|
the_file = DBFile.objects.create(
|
||||||
name=name,
|
name=name,
|
||||||
filehash=filehash,
|
|
||||||
content_type=ct,
|
content_type=ct,
|
||||||
b64=b64)
|
b64=b64)
|
||||||
the_file.save()
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def get_available_name(self, name, max_length=None):
|
def get_available_name(self, name, max_length=None):
|
||||||
@ -82,7 +72,7 @@ class DBFileStorage(Storage):
|
|||||||
DBFile.objects.filter(pk=name).delete()
|
DBFile.objects.filter(pk=name).delete()
|
||||||
|
|
||||||
def exists(self, name):
|
def exists(self, name):
|
||||||
return DBFile.objects.filter(Q(name=name) | Q(filehash=name)).exists()
|
return DBFile.objects.filter(name=name).exists()
|
||||||
|
|
||||||
def size(self, name):
|
def size(self, name):
|
||||||
dbf = _get_object(name)
|
dbf = _get_object(name)
|
||||||
|
@ -13,12 +13,10 @@ def show_file(request, name):
|
|||||||
|
|
||||||
:return HttpResponse: Rendered file
|
:return HttpResponse: Rendered file
|
||||||
"""
|
"""
|
||||||
dbf = DBFile.objects.filter(Q(name=name)|Q(filehash=name))
|
dbf = get_object_or_404(DBFile, name=name)
|
||||||
if dbf.exists():
|
response = HttpResponse(
|
||||||
response = HttpResponse(
|
dbf.b64.decode('base64'),
|
||||||
dbf[0].b64.decode('base64'),
|
content_type=dbf.content_type)
|
||||||
content_type=dbf[0].content_type)
|
response['Content-Disposition'] = 'attachment; filename="{}"'.format(
|
||||||
response['Content-Disposition'] = 'attachment; filename="{}"'.format(
|
dbf.name)
|
||||||
dbf[0].name)
|
return response
|
||||||
return response
|
|
||||||
raise Http404
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import hashlib
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from dbfilestorage.models import DBFile
|
from dbfilestorage.models import DBFile
|
||||||
@ -21,7 +20,6 @@ class DBFileTest(TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.filename = "kris.jpg"
|
self.filename = "kris.jpg"
|
||||||
self.filepath = os.path.join(PROJECT_ROOT, "test_files", self.filename)
|
self.filepath = os.path.join(PROJECT_ROOT, "test_files", self.filename)
|
||||||
self.md5 = hashlib.md5(open(self.filepath, 'rb').read()).hexdigest()
|
|
||||||
|
|
||||||
self._upload()
|
self._upload()
|
||||||
|
|
||||||
@ -31,16 +29,15 @@ class DBFileTest(TestCase):
|
|||||||
|
|
||||||
def test_upload(self):
|
def test_upload(self):
|
||||||
""" Test that the file storage uploads and puts in DB Properly """
|
""" Test that the file storage uploads and puts in DB Properly """
|
||||||
self.assertTrue(DBFile.objects.filter(filehash=self.md5).exists())
|
self.assertTrue(DBFile.objects.filter(name=self.filepath).exists())
|
||||||
|
|
||||||
def test_content_file(self):
|
def test_content_file(self):
|
||||||
""" Test that this code works with ContentFile as well """
|
""" Test that this code works with ContentFile as well """
|
||||||
content_file = ContentFile(u"ΑΔΔGΕΝΕ")
|
content_file = ContentFile(u"ΑΔΔGΕΝΕ")
|
||||||
content_file_md5 = hashlib.md5(u"ΑΔΔGΕΝΕ".encode('utf8')).hexdigest()
|
|
||||||
default_storage.save("unicode", content_file)
|
default_storage.save("unicode", content_file)
|
||||||
unicode_file = DBFile.objects.get(filehash=content_file_md5)
|
unicode_file = DBFile.objects.get(name="unicode")
|
||||||
self.assertEqual(unicode(unicode_file),
|
self.assertEqual(unicode(unicode_file),
|
||||||
"{} <application/octet-stream>".format(content_file_md5))
|
"unicode <application/octet-stream>")
|
||||||
|
|
||||||
def test_no_duplicate_upload(self):
|
def test_no_duplicate_upload(self):
|
||||||
""" Test that it won't make a new file if it already exists """
|
""" Test that it won't make a new file if it already exists """
|
||||||
@ -51,25 +48,25 @@ class DBFileTest(TestCase):
|
|||||||
def test_equality(self):
|
def test_equality(self):
|
||||||
""" Test that the DB entry matches what is expected from the file """
|
""" Test that the DB entry matches what is expected from the file """
|
||||||
with open(self.filepath, 'rb') as f:
|
with open(self.filepath, 'rb') as f:
|
||||||
dbf = DBFile.objects.get(filehash=self.md5)
|
dbf = DBFile.objects.get(name=self.filepath)
|
||||||
self.assertEqual(dbf.b64.decode("base64"), f.read())
|
self.assertEqual(dbf.b64.decode("base64"), f.read())
|
||||||
self.assertEqual(dbf.content_type, 'image/jpeg')
|
self.assertEqual(dbf.content_type, 'image/jpeg')
|
||||||
|
|
||||||
def test_open(self):
|
def test_open(self):
|
||||||
""" Test that the storage mechanism can upload """
|
""" Test that the storage mechanism can upload """
|
||||||
dbf = default_storage.open(self.md5)
|
dbf = default_storage.open(self.filepath)
|
||||||
with open(self.filepath, 'rb') as f:
|
with open(self.filepath, 'rb') as f:
|
||||||
self.assertEqual(dbf.read(), f.read())
|
self.assertEqual(dbf.read(), f.read())
|
||||||
|
|
||||||
def test_exists(self):
|
def test_exists(self):
|
||||||
""" Test that the storage mechanism can check existance """
|
""" Test that the storage mechanism can check existance """
|
||||||
self.assertTrue(default_storage.exists(self.md5))
|
self.assertTrue(default_storage.exists(self.filepath))
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
""" Test Deletion """
|
""" Test Deletion """
|
||||||
self.assertTrue(DBFile.objects.filter(filehash=self.md5).exists())
|
self.assertTrue(DBFile.objects.filter(name=self.filepath).exists())
|
||||||
default_storage.delete(self.md5)
|
default_storage.delete(self.filepath)
|
||||||
self.assertFalse(DBFile.objects.filter(filehash=self.md5).exists())
|
self.assertFalse(DBFile.objects.filter(name=self.filepath).exists())
|
||||||
# Also test that calling delete on something that doesn't exist,
|
# Also test that calling delete on something that doesn't exist,
|
||||||
# errors silently
|
# errors silently
|
||||||
self.assertFalse(DBFile.objects.filter(name="Nothing").exists())
|
self.assertFalse(DBFile.objects.filter(name="Nothing").exists())
|
||||||
@ -77,20 +74,18 @@ class DBFileTest(TestCase):
|
|||||||
|
|
||||||
def test_size(self):
|
def test_size(self):
|
||||||
""" Ensure we can get the proper size """
|
""" Ensure we can get the proper size """
|
||||||
size = default_storage.size(self.md5)
|
size = default_storage.size(self.filepath)
|
||||||
self.assertGreater(size, 0)
|
self.assertGreater(size, 0)
|
||||||
|
|
||||||
def test_url(self):
|
def test_url(self):
|
||||||
""" Test that the url returned is the md5 path not the filename """
|
""" Test that the url returned is the filename """
|
||||||
self.assertIn(self.filename, default_storage.url(self.md5))
|
self.assertIn(self.filename, default_storage.url(self.filename))
|
||||||
|
|
||||||
def test_view(self):
|
def test_view(self):
|
||||||
client = Client()
|
client = Client()
|
||||||
# check it works for both md5 and filename
|
url = default_storage.url(self.filepath)
|
||||||
for param in (self.md5, self.filepath):
|
resp = client.get(url)
|
||||||
url = default_storage.url(param)
|
self.assertEqual(resp.status_code, 200)
|
||||||
resp = client.get(url)
|
|
||||||
self.assertEqual(resp.status_code, 200)
|
|
||||||
|
|
||||||
def test_view_fails(self):
|
def test_view_fails(self):
|
||||||
client = Client()
|
client = Client()
|
||||||
@ -107,7 +102,7 @@ class DBFileTest(TestCase):
|
|||||||
client.login(username=my_admin.username, password='top_secret')
|
client.login(username=my_admin.username, password='top_secret')
|
||||||
url = reverse("admin:dbfilestorage_dbfile_changelist")
|
url = reverse("admin:dbfilestorage_dbfile_changelist")
|
||||||
resp = client.get(url)
|
resp = client.get(url)
|
||||||
self.assertContains(resp, self.md5)
|
self.assertContains(resp, self.filepath)
|
||||||
|
|
||||||
def test_mtime(self):
|
def test_mtime(self):
|
||||||
""" Ensure we can get the modified time """
|
""" Ensure we can get the modified time """
|
||||||
|
Loading…
Reference in New Issue
Block a user