Initial Commit

This commit is contained in:
Tyrel Souza 2016-12-07 15:05:14 -05:00
commit f878d1ff64
No known key found for this signature in database
GPG Key ID: 2EECB5087209E6A5
22 changed files with 644 additions and 0 deletions

28
.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
__pycache__/
*.py[cod]
build/
dist/
sdist/
.eggs/
*.egg-info/
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
*.pot
# Django stuff:
*.log
*.db
# Sphinx documentation
docs/_build/

5
README.rst Normal file
View File

@ -0,0 +1,5 @@
Django-dbstorage
----------------
Readme Coming soon

0
dbstorage/__init__.py Normal file
View File

4
dbstorage/admin.py Normal file
View File

@ -0,0 +1,4 @@
from django.contrib import admin
from .models import DBFile
admin.site.register(DBFile)

View File

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from addgene.common.migration import NoBackwards
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='DBFile',
fields=[
('id', models.AutoField(
verbose_name='ID',
serialize=False,
auto_created=True,
primary_key=True)),
('name', models.CharField(max_length=100)),
('content_type', models.CharField(max_length=100)),
('b64', models.TextField()),
],
),
NoBackwards(),
]

View File

11
dbstorage/models.py Normal file
View File

@ -0,0 +1,11 @@
from django.db import models
# Create your models here.
class DBFile(models.Model):
name = models.CharField(max_length=100)
content_type = models.CharField(max_length=100)
b64 = models.TextField()
def __unicode__(self):
return unicode(self.name)

82
dbstorage/storage.py Normal file
View File

@ -0,0 +1,82 @@
import mimetypes
import logging
import hashlib
from django.db.transaction import atomic
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__)
class DBStorage(Storage):
"""
This is our 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(name=name)
return ContentFile(the_file.b64.decode('base64'))
@atomic
def _save(self, name, content, max_length=None):
ct = None
if hasattr(content.file, "read"):
read_data = content.file.read()
else:
read_data = content.file.encode('utf8')
b64 = read_data.encode('base64')
# Try to get the real content_type if applicable.
try:
if hasattr(content, 'content_type'):
ct = content.content_type
elif hasattr(content.file, 'content_type'):
ct = content.file.content_type
except AttributeError:
pass
# USE mimetypes.guess_type as a fallback.
if ct is None:
# https://docs.python.org/2/library/mimetypes.html
ct = mimetypes.guess_type(name)[0]
# After we get the mimetype by name potentially, mangle it.
name = hashlib.md5(read_data).hexdigest()
# create the file, or just return name if the exact file already exists
if not DBFile.objects.filter(name=name).exists():
the_file = DBFile(
name=name,
content_type=ct,
b64=b64)
the_file.save()
return name
def get_available_name(self, name, max_length=None):
return name
def path(self, name):
return name
def delete(self, name):
assert name, "The name argument is not allowed to be empty."
DBFile.objects.get(name=name).delete()
def exists(self, name):
return DBFile.objects.filter(name=name).exists()
def size(self, name):
dbf = DBFile.objects.get(name=name)
return len(dbf.b64)
def url(self, name):
return reverse('dbstorage_file', args=(name,))

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

56
dbstorage/tests.py Normal file
View File

@ -0,0 +1,56 @@
import hashlib
import os
from .models import DBFile
from django.core.files.storage import default_storage
from django.test import TestCase
from django.test.utils import override_settings
PROJECT_ROOT = os.path.dirname(os.path.realpath(__file__))
class DBFileTest(TestCase):
def setUp(self):
self.filename = "kris.jpg"
self.filepath = os.path.join(PROJECT_ROOT, "test_files", self.filename)
self.md5 = hashlib.md5(open(self.filepath, 'rb').read()).hexdigest()
def _upload(self):
with open(self.filepath, 'rb') as f:
return default_storage.save(self.filepath, f)
@override_settings(
DEFAULT_STORAGE="dbstorage.storage.DBStorage")
def test_upload(self):
""" Test that the file storage uploads and puts in DB Properly """
name = self._upload()
self.assertEqual(name, self.md5)
self.assertTrue(DBFile.objects.filter(name=name).exists())
@override_settings(
DEFAULT_STORAGE="dbstorage.storage.DBStorage")
def test_equality(self):
""" Test that the DB entry matches what is expected from the file """
name = self._upload()
with open(self.filepath, 'rb') as f:
dbf = DBFile.objects.get(name=name)
self.assertEqual(dbf.b64.decode("base64"),
f.read())
self.assertEqual(dbf.content_type, 'image/jpeg')
@override_settings(
DEFAULT_STORAGE="dbstorage.storage.DBStorage")
def test_open(self):
""" Test that the storage mechanism can upload """
name = self._upload()
dbf = default_storage.open(name)
with open(self.filepath, 'rb') as f:
self.assertEqual(dbf.read(), f.read())
@override_settings(
DEFAULT_STORAGE="dbstorage.storage.DBStorage")
def test_exists(self):
""" Test that the storage mechanism can check existance """
name = self._upload()
self.assertTrue(default_storage.exists(name))

7
dbstorage/urls.py Normal file
View File

@ -0,0 +1,7 @@
from django.conf.urls import patterns, url
import views
urlpatterns = patterns(
'',
url(r'^(?P<name>.*)$', views.show_file, name="dbstorage_file"),
)

11
dbstorage/views.py Normal file
View File

@ -0,0 +1,11 @@
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from .models import DBFile
def show_file(request, name):
dbf = get_object_or_404(DBFile, name=name)
return HttpResponse(
dbf.b64.decode('base64'),
content_type=dbf.content_type)

20
docs/Makefile Normal file
View File

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = DjangoDBStorage
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

156
docs/conf.py Normal file
View File

@ -0,0 +1,156 @@
# -*- coding: utf-8 -*-
#
# Django DBStorage documentation build configuration file, created by
# sphinx-quickstart on Wed Dec 7 14:50:49 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Django DBStorage'
copyright = u'2016, Tyrel Souza'
author = u'Tyrel Souza'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'0.0.1'
# The full version, including alpha/beta/rc tags.
release = u'0.0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'DjangoDBStoragedoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'DjangoDBStorage.tex', u'Django DBStorage Documentation',
u'Tyrel Souza', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'djangodbstorage', u'Django DBStorage Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'DjangoDBStorage', u'Django DBStorage Documentation',
author, 'DjangoDBStorage', 'One line description of project.',
'Miscellaneous'),
]

20
docs/index.rst Normal file
View File

@ -0,0 +1,20 @@
.. Django DBStorage documentation master file, created by
sphinx-quickstart on Wed Dec 7 14:50:49 2016.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Django DBStorage's documentation!
============================================
.. toctree::
:maxdepth: 2
:caption: Contents:
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

36
docs/make.bat Normal file
View File

@ -0,0 +1,36 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=DjangoDBStorage
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd

22
manage.py Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings")
try:
from django.core.management import execute_from_command_line
except ImportError:
# The above import may fail for some other reason. Ensure that the
# issue is really that Django is missing to avoid masking other
# exceptions on Python 2.
try:
import django
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
)
raise
execute_from_command_line(sys.argv)

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
Django==1.10.4
Sphinx==1.5

0
tests/__init__.py Normal file
View File

120
tests/settings.py Normal file
View File

@ -0,0 +1,120 @@
"""
Django settings for tests project.
Generated by 'django-admin startproject' using Django 1.10.4.
For more information on this file, see
https://docs.djangoproject.com/en/1.10/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.10/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '_95vgv#3blxe^171sc3*3yjc4z%*10id0hb9-^$#p3ekiwu71a'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'tests.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'tests.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_URL = '/static/'

21
tests/urls.py Normal file
View File

@ -0,0 +1,21 @@
"""tests URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
]

16
tests/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for tests project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings")
application = get_wsgi_application()