Got upload view working, staging preview and delete working ok

This commit is contained in:
Roberto Rosario
2011-07-06 01:31:27 -04:00
parent 7417fca835
commit 2816c1f86f
16 changed files with 520 additions and 85 deletions
+19
View File
@@ -0,0 +1,19 @@
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.conf import settings
from navigation.api import register_links, register_top_menu, \
register_model_list_columns, register_multi_item_links, \
register_sidebar_template
from sources.staging import StagingFile
upload_document_from_local = {'text': _(u'local'), 'view': 'upload_document_from_local', 'famfam': 'drive_disk', 'keep_query': True}
upload_document_from_staging = {'text': _(u'staging'), 'view': 'upload_document_from_staging', 'famfam': 'drive_network', 'keep_query': True}#, 'condition': lambda x: USE_STAGING_DIRECTORY}
upload_document_from_user_staging = {'text': _(u'user staging'), 'view': 'upload_document_from_user_staging', 'famfam': 'drive_user', 'keep_query': True}#, 'condition': lambda x: PER_USER_STAGING_DIRECTORY}
staging_file_preview = {'text': _(u'preview'), 'class': 'fancybox-noscaling', 'view': 'staging_file_preview', 'args': ['source.source_type', 'source.pk', 'object.id'], 'famfam': 'zoom'}
staging_file_delete = {'text': _(u'delete'), 'view': 'staging_file_delete', 'args': ['source.source_type', 'source.pk', 'object.id'], 'famfam': 'delete'}
register_links(StagingFile, [staging_file_preview, staging_file_delete])
-2
View File
@@ -2,7 +2,5 @@ from django.contrib import admin
from sources.models import StagingFolder, WebForm
admin.site.register(StagingFolder)
admin.site.register(WebForm)
+39
View File
@@ -0,0 +1,39 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
from django.conf import settings
from common.forms import DetailForm
from common.literals import PAGE_SIZE_CHOICES, PAGE_ORIENTATION_CHOICES
from common.conf.settings import DEFAULT_PAPER_SIZE
from common.conf.settings import DEFAULT_PAGE_ORIENTATION
from documents.forms import DocumentForm
class StagingDocumentForm(DocumentForm):
"""
Form that show all the files in the staging folder specified by the
StagingFile class passed as 'cls' argument
"""
def __init__(self, *args, **kwargs):
cls = kwargs.pop('cls')
super(StagingDocumentForm, self).__init__(*args, **kwargs)
try:
self.fields['staging_file_id'].choices = [
(staging_file.id, staging_file) for staging_file in cls.get_all()
]
except:
pass
# Put staging_list field first in the field order list
staging_list_index = self.fields.keyOrder.index('staging_file_id')
staging_list = self.fields.keyOrder.pop(staging_list_index)
self.fields.keyOrder.insert(0, staging_list)
staging_file_id = forms.ChoiceField(label=_(u'Staging file'))
class Meta(DocumentForm.Meta):
exclude = ('description', 'file', 'document_type', 'tags')
+11 -7
View File
@@ -40,8 +40,8 @@ SOURCE_ICON_CHOICES = (
(SOURCE_ICON_WORLD, _(u'world'))
)
SOURCE_CHOICE_WEB_FORM = 'wform'
SOURCE_CHOICE_STAGING = 'stagn'
SOURCE_CHOICE_WEB_FORM = 'webform'
SOURCE_CHOICE_STAGING = 'staging'
SOURCE_CHOICES = (
(SOURCE_CHOICE_WEB_FORM, _(u'Web form')),
@@ -56,15 +56,11 @@ class BaseModel(models.Model):
blacklist = models.TextField(blank=True, verbose_name=_(u'blacklist'))
document_type = models.ForeignKey(DocumentType, blank=True, null=True, verbose_name=_(u'document type'))
# M2M
# Default Metadata sets
# Default Metadata types & default values
def __unicode__(self):
return u'%s (%s)' % (self.title, dict(SOURCE_CHOICES).get(self.source_type))
class Meta:
ordering = ['title']
ordering = ('title',)
abstract = True
@@ -104,6 +100,14 @@ class StagingFolder(InteractiveBaseModel):
uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_(u'uncompress'))
delete_after_upload = models.BooleanField(default=True, verbose_name=_(u'delete after upload'))
def get_preview_size(self):
dimensions = []
dimensions.append(unicode(self.preview_width))
if self.preview_height:
dimensions.append(unicode(self.preview_height))
return u'x'.join(dimensions)
class Meta:
verbose_name = _(u'staging folder')
verbose_name_plural = _(u'staging folder')
+160
View File
@@ -0,0 +1,160 @@
import errno
import os
import hashlib
from django.core.files.base import File
from django.core.exceptions import ObjectDoesNotExist
from django.utils.translation import ugettext
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from converter import TRANFORMATION_CHOICES
from converter.api import convert, cache_cleanup
#from documents.conf.settings import STAGING_DIRECTORY
STAGING_DIRECTORY = u'/tmp'
#from documents.conf.settings import DEFAULT_TRANSFORMATIONS
#from documents.conf.settings import STAGING_FILES_PREVIEW_SIZE
STAGING_FILES_PREVIEW_SIZE = u'640'
#from documents.conf.settings import USER_STAGING_DIRECTORY_ROOT
#from documents.conf.settings import USER_STAGING_DIRECTORY_EXPRESSION
#from documents.literals import UPLOAD_SOURCE_STAGING, \
# UPLOAD_SOURCE_USER_STAGING
UPLOAD_SOURCE_LOCAL = u'local'
UPLOAD_SOURCE_STAGING = u'staging'
UPLOAD_SOURCE_USER_STAGING = u'user_staging'
HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest()
#TODO: Do benchmarks
#func = lambda:[StagingFile.get_all() is None for i in range(100)]
#t1=time.time();func();t2=time.time();print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)
#STAGING_FILE_FUNCTIONS = {
# UPLOAD_SOURCE_STAGING: lambda x: STAGING_DIRECTORY,
# UPLOAD_SOURCE_USER_STAGING: lambda x: os.path.join(USER_STAGING_DIRECTORY_ROOT, eval(USER_STAGING_DIRECTORY_EXPRESSION, {'user': x.user}))
#}
def evaluate_user_staging_path(request, source):
try:
return STAGING_FILE_FUNCTIONS[source](request)
except Exception, exc:
messages.error(request, _(u'Error evaluating user staging directory expression; %s') % exc)
return u''
def get_all_files(path):
try:
return sorted([os.path.normcase(f) for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))])
except OSError, exc:
raise OSError(ugettext(u'Unable get list of staging files: %s') % exc)
def _return_new_class():
return type('StagingFile', (StagingFile,), dict(StagingFile.__dict__))
def create_staging_file_class(request, source):
cls = _return_new_class()
#cls.set_path(evaluate_user_staging_path(request, source))
cls.set_path(source)
return cls
class StagingFile(object):
"""
Simple class to encapsulate the files in a directory and hide the
specifics to the view
"""
path = STAGING_DIRECTORY
@classmethod
def set_path(cls, path):
cls.path = path
@classmethod
def get_all(cls):
"""
Return a list of StagingFile instances corresponding to the
current path
"""
staging_files = []
for filename in get_all_files(cls.path):
staging_files.append(StagingFile(
filepath=os.path.join(cls.path, filename)))
return staging_files
@classmethod
def get(cls, id):
"""
Return a single StagingFile instance corresponding to the id
given as argument
"""
files_dict = dict([(file.id, file) for file in cls.get_all()])
if id in files_dict:
return files_dict[id]
else:
raise ObjectDoesNotExist
def __init__(self, filepath):
self.filepath = filepath
self.filename = os.path.basename(filepath)
self._id = HASH_FUNCTION(open(filepath).read())
def __unicode__(self):
return self.filename
def __repr__(self):
return self.__unicode__()
def __getattr__(self, name):
if name == 'id':
return self._id
else:
raise AttributeError
def upload(self):
"""
Return a StagingFile encapsulated in a File class instance to
allow for easier upload a staging files
"""
try:
return File(file(self.filepath, 'rb'), name=self.filename)
except Exception, exc:
raise Exception(ugettext(u'Unable to upload staging file: %s') % exc)
def delete(self):
#tranformation_string, errors = get_transformation_string(DEFAULT_TRANSFORMATIONS)
cache_cleanup(self.filepath, size=STAGING_FILES_PREVIEW_SIZE)#, extra_options=tranformation_string)
try:
os.unlink(self.filepath)
except OSError, exc:
if exc.errno == errno.ENOENT:
pass
else:
raise OSError(ugettext(u'Unable to delete staging file: %s') % exc)
def preview(self, preview_size):
errors = []
#tranformation_string, errors = get_transformation_string(DEFAULT_TRANSFORMATIONS)
#output_file = convert(self.filepath, size=STAGING_FILES_PREVIEW_SIZE, extra_options=tranformation_string, cleanup_files=False)
output_file = convert(self.filepath, size=preview_size, cleanup_files=False)
return output_file, errors
def get_transformation_string(transformations):
transformation_list = []
errors = []
for transformation in transformations:
try:
if transformation['name'] in TRANFORMATION_CHOICES:
output = TRANFORMATION_CHOICES[transformation['name']] % eval(transformation['arguments'])
transformation_list.append(output)
except Exception, e:
errors.append(e)
tranformation_string = ' '.join(transformation_list)
return tranformation_string, errors
+23
View File
@@ -0,0 +1,23 @@
from django.conf.urls.defaults import patterns, url
#from converter.api import QUALITY_HIGH, QUALITY_PRINT
#from documents.conf.settings import PREVIEW_SIZE
#from documents.conf.settings import PRINT_SIZE
#from documents.conf.settings import THUMBNAIL_SIZE
#from documents.conf.settings import DISPLAY_SIZE
#from documents.conf.settings import MULTIPAGE_PREVIEW_SIZE
#from documents.literals import UPLOAD_SOURCE_LOCAL, \
# UPLOAD_SOURCE_STAGING, UPLOAD_SOURCE_USER_STAGING
urlpatterns = patterns('sources.views',
#url(r'^upload/local/$', 'upload_document_with_type', {'source': UPLOAD_SOURCE_LOCAL}, 'upload_document_from_local'),
#url(r'^upload/staging/$', 'upload_document_with_type', {'source': UPLOAD_SOURCE_STAGING}, 'upload_document_from_staging'),
#url(r'^upload/staging/user/$', 'upload_document_with_type', {'source': UPLOAD_SOURCE_USER_STAGING}, 'upload_document_from_user_staging'),
url(r'^staging_file/type/(?P<source_type>\w+)/(?P<source_id>\d+)/(?P<staging_file_id>\w+)/preview/$', 'staging_file_preview', (), 'staging_file_preview'),
url(r'^staging_file/type/(?P<source_type>\w+)/(?P<source_id>\d+)/(?P<staging_file_id>\w+)/delete/$', 'staging_file_delete', (), 'staging_file_delete'),
url(r'^upload/interactive/(?P<source_type>\w+)/(?P<source_id>\d+)/$', 'upload_interactive', (), 'upload_interactive'),
url(r'^upload/interactive/$', 'upload_interactive', (), 'upload_interactive'),
)
+368 -1
View File
@@ -1 +1,368 @@
# Create your views here.
import os
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from permissions.api import check_permissions
from documents.literals import PERMISSION_DOCUMENT_CREATE
from documents.models import DocumentType
from metadata.api import save_metadata_list, \
decode_metadata_from_url, metadata_repr_as_list
from metadata.forms import MetadataFormSet, MetadataSelectionForm
import sendfile
from converter.exceptions import UnkownConvertError, UnknownFormat
from documents.literals import PICTURE_ERROR_SMALL, PICTURE_ERROR_MEDIUM, \
PICTURE_UNKNOWN_SMALL, PICTURE_UNKNOWN_MEDIUM
#TEMP
from documents.forms import DocumentForm
from sources.models import WebForm, StagingFolder
from sources.models import SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING
from sources.staging import create_staging_file_class
from sources.forms import StagingDocumentForm
def upload_interactive(request, source_type=None, source_id=None):
check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
subtemplates_list = []
tab_links = []
context = {}
web_forms = WebForm.objects.filter(enabled=True)
for web_form in web_forms:
tab_links.append({
'text': web_form.title,
'view': 'upload_interactive',
'args': [u'"%s"' % web_form.source_type, web_form.pk],
'famfam': web_form.icon,
'keep_query': True
})
staging_folders = StagingFolder.objects.filter(enabled=True)
for staging_folder in staging_folders:
tab_links.append({
'text': staging_folder.title,
'view': 'upload_interactive',
'args': [u'"%s"' % staging_folder.source_type, staging_folder.pk],
'famfam': staging_folder.icon,
'keep_query': True
})
if web_forms.count() == 0 and staging_folders.count() == 0:
subtemplates_list.append(
{
'name': 'generic_subtemplate.html',
'context': {
'title': _(u'Upload sources'),
'paragraphs': [
_(u'Not document sources have been defined or there are no sources enabled.')
# TODO: Add link to setup
],
}
})
document_type_id = request.GET.get('document_type_id', None)
if document_type_id:
document_type = get_object_or_404(DocumentType, pk=document_type_id[0])
else:
document_type = None
subtemplates_list = []
if source_type is None and source_id is None:
if web_forms.count():
source_type = web_forms[0].source_type
source_id = web_forms[0].pk
elif staging_folders.count():
source_type = staging_folders[0].source_type
source_id = staging_folders[0].pk
if source_type and source_id:
if source_type == SOURCE_CHOICE_WEB_FORM:
web_form = get_object_or_404(WebForm, pk=source_id)
context['source'] = web_form
form = DocumentForm(document_type=document_type)
subtemplates_list.append({
'name': 'generic_form_subtemplate.html',
'context': {
'form': form,
'title': _(u'upload a local document from source: %s') % web_form.title,
},
})
elif source_type == SOURCE_CHOICE_STAGING:
staging_folder = get_object_or_404(StagingFolder, pk=source_id)
context['source'] = staging_folder
StagingFile = create_staging_file_class(request, staging_folder.folder_path)
form = StagingDocumentForm(cls=StagingFile,
document_type=document_type)
try:
staging_filelist = StagingFile.get_all()
except Exception, e:
messages.error(request, e)
staging_filelist = []
finally:
subtemplates_list = [
{
'name': 'generic_form_subtemplate.html',
'context': {
'form': form,
'title': _(u'upload a document from staging source: %s') % staging_folder.title,
}
},
{
'name': 'generic_list_subtemplate.html',
'context': {
'title': _(u'files in staging path'),
'object_list': staging_filelist,
'hide_link': True,
}
},
]
context.update({
'document_type_id': document_type_id,
'subtemplates_list': subtemplates_list,
'sidebar_subtemplates_list': [
{
'name': 'generic_subtemplate.html',
'context': {
'title': _(u'Current metadata'),
'paragraphs': metadata_repr_as_list(decode_metadata_from_url(request.GET)),
'side_bar': True,
}
}],
'temporary_navigation_links': {'form_header': {'upload_interactive': {'links': tab_links}}}
})
return render_to_response('generic_form.html', context,
context_instance=RequestContext(request))
def _handle_save_document(request, document, form=None):
RecentDocument.objects.add_document_for_user(request.user, document)
if form:
if form.cleaned_data['new_filename']:
document.file_filename = form.cleaned_data['new_filename']
document.save()
if form and 'document_type_available_filenames' in form.cleaned_data:
if form.cleaned_data['document_type_available_filenames']:
document.file_filename = form.cleaned_data['document_type_available_filenames'].filename
document.save()
save_metadata_list(decode_metadata_from_url(request.GET), document, create=True)
warnings = update_indexes(document)
if request.user.is_staff or request.user.is_superuser:
for warning in warnings:
messages.warning(request, warning)
create_history(HISTORY_DOCUMENT_CREATED, document, {'user': request.user})
def _handle_zip_file(request, uploaded_file, document_type=None):
filename = getattr(uploaded_file, 'filename', getattr(uploaded_file, 'name', ''))
if filename.lower().endswith('zip'):
zfobj = zipfile.ZipFile(uploaded_file)
for filename in zfobj.namelist():
if not filename.endswith('/'):
zip_document = Document(file=SimpleUploadedFile(
name=filename, content=zfobj.read(filename)))
if document_type:
zip_document.document_type = document_type
zip_document.save()
_handle_save_document(request, zip_document)
messages.success(request, _(u'Extracted file: %s, uploaded successfully.') % filename)
#Signal that uploaded file was a zip file
return True
else:
#Otherwise tell parent to handle file
return False
def upload_document_with_type(request, source):
check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
document_type_id = request.GET.get('document_type_id', None)
if document_type_id:
document_type = get_object_or_404(DocumentType, pk=document_type_id[0])
else:
document_type = None
if request.method == 'POST':
if source == UPLOAD_SOURCE_LOCAL:
form = DocumentForm(request.POST, request.FILES, document_type=document_type)
if form.is_valid():
try:
expand = form.cleaned_data['expand']
if (not expand) or (expand and not _handle_zip_file(request, request.FILES['file'], document_type)):
instance = form.save()
instance.save()
if document_type:
instance.document_type = document_type
_handle_save_document(request, instance, form)
messages.success(request, _(u'Document uploaded successfully.'))
except Exception, e:
messages.error(request, e)
return HttpResponseRedirect(request.get_full_path())
elif (USE_STAGING_DIRECTORY and source == UPLOAD_SOURCE_STAGING) or (PER_USER_STAGING_DIRECTORY and source == UPLOAD_SOURCE_USER_STAGING):
StagingFile = create_staging_file_class(request, source)
form = StagingDocumentForm(request.POST,
request.FILES, cls=StagingFile,
document_type=document_type)
if form.is_valid():
try:
staging_file = StagingFile.get(form.cleaned_data['staging_file_id'])
expand = form.cleaned_data['expand']
if (not expand) or (expand and not _handle_zip_file(request, staging_file.upload(), document_type)):
document = Document(file=staging_file.upload())
if document_type:
document.document_type = document_type
document.save()
_handle_save_document(request, document, form)
messages.success(request, _(u'Staging file: %s, uploaded successfully.') % staging_file.filename)
if DELETE_STAGING_FILE_AFTER_UPLOAD:
staging_file.delete()
messages.success(request, _(u'Staging file: %s, deleted successfully.') % staging_file.filename)
except Exception, e:
messages.error(request, e)
return HttpResponseRedirect(request.META['HTTP_REFERER'])
else:
if source == UPLOAD_SOURCE_LOCAL:
form = DocumentForm(document_type=document_type)
elif (USE_STAGING_DIRECTORY and source == UPLOAD_SOURCE_STAGING) or (PER_USER_STAGING_DIRECTORY and source == UPLOAD_SOURCE_USER_STAGING):
StagingFile = create_staging_file_class(request, source)
form = StagingDocumentForm(cls=StagingFile,
document_type=document_type)
subtemplates_list = []
if source == UPLOAD_SOURCE_LOCAL:
subtemplates_list.append({
'name': 'generic_form_subtemplate.html',
'context': {
'form': form,
'title': _(u'upload a local document'),
},
})
elif (USE_STAGING_DIRECTORY and source == UPLOAD_SOURCE_STAGING) or (PER_USER_STAGING_DIRECTORY and source == UPLOAD_SOURCE_USER_STAGING):
if source == UPLOAD_SOURCE_STAGING:
form_title = _(u'upload a document from staging')
list_title = _(u'files in staging')
else:
form_title = _(u'upload a document from user staging')
list_title = _(u'files in user staging')
try:
staging_filelist = StagingFile.get_all()
except Exception, e:
messages.error(request, e)
staging_filelist = []
finally:
subtemplates_list = [
{
'name': 'generic_form_subtemplate.html',
'context': {
'form': form,
'title': form_title,
}
},
{
'name': 'generic_list_subtemplate.html',
'context': {
'title': list_title,
'object_list': staging_filelist,
'hide_link': True,
}
},
]
context = {
'source': source,
'document_type_id': document_type_id,
'subtemplates_list': subtemplates_list,
'sidebar_subtemplates_list': [
{
'name': 'generic_subtemplate.html',
'context': {
'title': _(u'Current metadata'),
'paragraphs': metadata_repr_as_list(decode_metadata_from_url(request.GET)),
'side_bar': True,
}
}]
}
return render_to_response('generic_form.html', context,
context_instance=RequestContext(request))
def staging_file_preview(request, source_type, source_id, staging_file_id):
check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
staging_folder = get_object_or_404(StagingFolder, pk=source_id)
StagingFile = create_staging_file_class(request, staging_folder.folder_path)
try:
output_file, errors = StagingFile.get(staging_file_id).preview(staging_folder.get_preview_size())
if errors and (request.user.is_staff or request.user.is_superuser):
for error in errors:
messages.warning(request, _(u'Staging file transformation error: %(error)s') % {
'error': error
})
except UnkownConvertError, e:
if request.user.is_staff or request.user.is_superuser:
messages.error(request, e)
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_ERROR_MEDIUM)
except UnknownFormat:
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_UNKNOWN_MEDIUM)
except Exception, e:
if request.user.is_staff or request.user.is_superuser:
messages.error(request, e)
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_ERROR_MEDIUM)
finally:
return sendfile.sendfile(request, output_file)
def staging_file_delete(request, source_type, source_id, staging_file_id):
check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
staging_folder = get_object_or_404(StagingFolder, pk=source_id)
StagingFile = create_staging_file_class(request, staging_folder.folder_path)
staging_file = StagingFile.get(staging_file_id)
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', None)))
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None)))
if request.method == 'POST':
try:
staging_file.delete()
messages.success(request, _(u'Staging file delete successfully.'))
except Exception, e:
messages.error(request, e)
return HttpResponseRedirect(next)
return render_to_response('generic_confirm.html', {
'source': staging_folder,
'delete_view': True,
'object': staging_file,
'next': next,
'previous': previous,
'form_icon': u'delete.png',
}, context_instance=RequestContext(request))