diff --git a/apps/common/templates/generic_list.html b/apps/common/templates/generic_list.html index b6acb740ae..713205dcfd 100755 --- a/apps/common/templates/generic_list.html +++ b/apps/common/templates/generic_list.html @@ -5,4 +5,22 @@ {% block content %} {% include 'generic_list_subtemplate.html' %} + + {% for subtemplate in subtemplates_dict %} + {% with subtemplate.title as title %} + {% with subtemplate.object_list as object_list %} + {% with subtemplate.extra_columns as extra_columns %} + {% with subtemplate.hide_object as hide_object %} + {% with subtemplate.main_object as main_object %} + {% with subtemplate.hide_link as hide_link %} + {% include subtemplate.name %} + {% endwith %} + {% endwith %} + {% endwith %} + {% endwith %} + {% endwith %} + {% endwith %} + {% endfor %} + {% endblock %} + diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 78f2c9333a..b305855ab9 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -11,10 +11,12 @@ document_create_multiple = {'text':_('upload multiple documents'), 'view':'docum document_view = {'text':_('details'), 'view':'document_view', 'args':'object.id', 'famfam':'page'} document_delete = {'text':_('delete'), 'view':'document_delete', 'args':'object.id', 'famfam':'page_delete'} document_edit = {'text':_('edit'), 'view':'document_edit', 'args':'object.id', 'famfam':'page_edit'} +document_preview = {'text':_('preview'), 'class':'fancybox', 'view':'document_preview', 'args':'object.id', 'famfam':'magnifier'} +document_download = {'text':_('download'), 'view':'document_download', 'args':'object.id', 'famfam':'page_save'} -staging_file_preview = {'class':'fancybox', 'text':_('preview'), 'view':'staging_file_preview', 'args':'object.id', 'famfam':'drive_magnify'} +staging_file_preview = {'text':_('preview'), 'class':'fancybox', 'view':'staging_file_preview', 'args':'object.id', 'famfam':'drive_magnify'} -register_links(Document, [document_view, document_edit, document_delete]) +register_links(Document, [document_view, document_edit, document_delete, document_preview, document_download]) register_links(Document, [document_list, document_create, document_create_multiple], menu_name='sidebar') register_links(['document_list', 'document_create', 'document_create_multiple', 'upload_document_with_type', 'upload_multiple_documents_with_type'], [document_list, document_create, document_create_multiple], menu_name='sidebar') diff --git a/apps/documents/conf/settings.py b/apps/documents/conf/settings.py index a73adeb0f7..194412bafb 100644 --- a/apps/documents/conf/settings.py +++ b/apps/documents/conf/settings.py @@ -23,7 +23,6 @@ USE_STAGING_DIRECTORY = getattr(settings, 'DOCUMENTS_USE_STAGING_DIRECTORY', Fal STAGING_DIRECTORY = getattr(settings, 'DOCUMENTS_STAGING_DIRECTORY', u'/tmp/mayan/staging') DELETE_STAGING_FILE_AFTER_UPLOAD = getattr(settings, 'DOCUMENTS_DELETE_STAGING_FILE_AFTER_UPLOAD', False) STAGING_FILES_PREVIEW_SIZE = getattr(settings, 'DOCUMENTS_STAGING_FILES_PREVIEW_SIZE', '640x480') - DELETE_LOCAL_ORIGINAL = getattr(settings, 'DOCUMENTS_DELETE_LOCAL_ORIGINAL', False) # Saving CHECKSUM_FUNCTION = getattr(settings, 'DOCUMENTS_CHECKSUM_FUNCTION', lambda x: hashlib.sha256(x).hexdigest()) @@ -31,6 +30,8 @@ UUID_FUNCTION = getattr(settings, 'DOCUMENTS_UUID_FUNTION', lambda:unicode(uuid. # Storage STORAGE_BACKEND = getattr(settings, 'DOCUMENTS_STORAGE_BACKEND', DocumentStorage) STORAGE_DIRECTORY_NAME = getattr(settings, 'DOCUMENTS_STORAGE_DIRECTORY_NAME', 'documents') +# Usage +PREVIEW_SIZE = getattr(settings, 'DOCUMENTS_PREVIEW_SIZE', '640x480') # Serving FILESYSTEM_FILESERVING_ENABLE = getattr(settings, 'DOCUMENTS_FILESYSTEM_FILESERVING_ENABLE', True) FILESYSTEM_FILESERVING_PATH = getattr(settings, 'DOCUMENTS_FILESERVING_PATH', u'/tmp/mayan/documents') diff --git a/apps/documents/convert.py b/apps/documents/convert.py index ec42a3427d..58a1c8872d 100644 --- a/apps/documents/convert.py +++ b/apps/documents/convert.py @@ -6,6 +6,19 @@ import tempfile #from django.core.files.base import File from documents.conf.settings import TEMPORARY_DIRECTORY + +def in_cache(input_filepath, size, page=0, format='jpg'): + temp_directory = TEMPORARY_DIRECTORY if TEMPORARY_DIRECTORY else tempfile.mkdtemp() + temp_filename, separator = os.path.splitext(os.path.basename(input_filepath)) + temp_path = os.path.join(temp_directory, temp_filename) + output_arg = '%s_%s%s%s' % (temp_path, size, os.extsep, format) + input_arg = '%s[%s]' % (input_filepath, page) + if os.path.exists(output_arg): + return output_arg + else: + return None + + def convert(input_filepath, size, cache=True, page=0, format='jpg'): temp_directory = TEMPORARY_DIRECTORY if TEMPORARY_DIRECTORY else tempfile.mkdtemp() #TODO: generate output file using lightweight hash function on diff --git a/apps/documents/models.py b/apps/documents/models.py index 0e8e837a74..74931ffb29 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -73,6 +73,9 @@ class Document(models.Model): def __unicode__(self): return '%s.%s' % (self.file_filename, self.file_extension) + + def get_fullname(self): + return os.extsep.join([self.file_filename, self.file_extension]) @models.permalink def get_absolute_url(self): diff --git a/apps/documents/urls.py b/apps/documents/urls.py index f57713bd02..6cd82d8b27 100644 --- a/apps/documents/urls.py +++ b/apps/documents/urls.py @@ -12,6 +12,8 @@ urlpatterns = patterns('documents.views', url(r'^document/(?P\d+)/$', 'document_view', (), 'document_view'), url(r'^document/(?P\d+)/delete/$', 'document_delete', (), 'document_delete'), url(r'^document/(?P\d+)/edit/$', 'document_edit', (), 'document_edit'), + url(r'^document/(?P\d+)/preview/$', 'document_preview', (), 'document_preview'), + url(r'^document/(?P\d+)/download/$', 'document_download', (), 'document_download'), url(r'^staging_file/(?P\w+)/preview/$', 'staging_file_preview', (), 'staging_file_preview'), diff --git a/apps/documents/utils.py b/apps/documents/utils.py new file mode 100644 index 0000000000..c31bfdf694 --- /dev/null +++ b/apps/documents/utils.py @@ -0,0 +1,61 @@ +import os +import tempfile + +from documents.conf.settings import TEMPORARY_DIRECTORY + + +#http://stackoverflow.com/questions/123198/how-do-i-copy-a-file-in-python +def copyfile(source, dest, buffer_size=1024*1024): + """ + Copy a file from source to dest. source and dest + can either be strings or any object with a read or + write method, like StringIO for example. + """ + if not hasattr(source, 'read'): + source = open(source, 'rb') + if not hasattr(dest, 'write'): + dest = open(dest, 'wb') + + while 1: + copy_buffer = source.read(buffer_size) + if copy_buffer: + dest.write(copy_buffer) + else: + break + + source.close() + dest.close() + + +def from_descriptor_to_tempfile(input_descriptor, filename, buffer_size=1024*1024): + path = os.path.join(TEMPORARY_DIRECTORY, filename) + + output_descriptor = open(path, 'wb') + + while 1: + copy_buffer = input_descriptor.read(buffer_size) + if copy_buffer: + output_descriptor.write(copy_buffer) + else: + break + + input_descriptor.close() + output_descriptor.close() + return path + + + +def from_descriptor_to_new_tempfile(input_descriptor, buffer_size=1024*1024): + output_descriptor, tmp_filename = tempfile.mkstemp() + + while 1: + copy_buffer = input_descriptor.read(buffer_size) + if copy_buffer: + #output_descriptor.write(copy_buffer) + os.write(output_descriptor, copy_buffer) + else: + break + + input_descriptor.close() + os.close(output_descriptor) + return tmp_filename diff --git a/apps/documents/views.py b/apps/documents/views.py index 5a23357ce7..6f3e60de94 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -1,4 +1,3 @@ -from urlparse import urlparse from urllib import unquote_plus from django.utils.translation import ugettext as _ @@ -14,7 +13,8 @@ from django.core.files.base import File from filetransfers.api import serve_file -from convert import convert +from convert import convert, in_cache +from utils import from_descriptor_to_tempfile from models import Document, DocumentMetadata, DocumentType, MetadataType from forms import DocumentTypeSelectForm, DocumentCreateWizard, \ @@ -27,6 +27,7 @@ from documents.conf.settings import DELETE_STAGING_FILE_AFTER_UPLOAD from documents.conf.settings import USE_STAGING_DIRECTORY from documents.conf.settings import FILESYSTEM_FILESERVING_ENABLE from documents.conf.settings import STAGING_FILES_PREVIEW_SIZE +from documents.conf.settings import PREVIEW_SIZE def document_list(request): return object_list( @@ -39,10 +40,14 @@ def document_list(request): {'name':_(u'mimetype'), 'attribute':'file_mimetype'}, {'name':_(u'added'), 'attribute':lambda x: x.date_added.date()}, ], + 'subtemplates_dict':[ + { + 'name':'fancybox.html', + }, + ], }, ) - def document_create(request, multiple=True): MetadataFormSet = formset_factory(MetadataForm, extra=0) wizard = DocumentCreateWizard(form_list=[DocumentTypeSelectForm, MetadataFormSet], multiple=multiple) @@ -198,6 +203,9 @@ def document_view(request, document_id): ]) subtemplates_dict = [ + { + 'name':'fancybox.html', + }, { 'name':'generic_list_subtemplate.html', 'title':_(u'metadata'), @@ -274,6 +282,37 @@ def document_edit(request, document_id): }, context_instance=RequestContext(request)) +def document_preview(request, document_id): + document = get_object_or_404(Document, pk=document_id) + + filepath = in_cache(document.uuid, PREVIEW_SIZE) + + if filepath: + return serve_file(request, File(file=open(filepath, 'r'))) + else: + try: + document.file.open() + desc = document.file.storage.open(document.file.path) + filepath = from_descriptor_to_tempfile(desc, document.uuid) + output_file = convert(filepath, PREVIEW_SIZE) + return serve_file(request, File(file=open(output_file, 'r'))) + except Exception, e: + #messages.error(request, e) + return HttpResponse(e) + + + +def document_download(request, document_id): + document = get_object_or_404(Document, pk=document_id) + try: + #Test permissions and trigger exception + document.file.open() + return serve_file(request, document.file, save_as=document.get_fullname()) + except Exception, e: + messages.error(request, e) + return HttpResponseRedirect(request.META['HTTP_REFERER']) + + def staging_file_preview(request, staging_file_id): try: filepath = StagingFile.get(staging_file_id).filepath diff --git a/settings.py b/settings.py index 85d6bc9d91..d5511d3d0f 100644 --- a/settings.py +++ b/settings.py @@ -180,6 +180,8 @@ LOGIN_EXEMPT_URLS = ( #DOCUMENTS_UUID_FUNCTION = lambda:unicode(uuid.uuid4()) # Storage #DOCUMENTS_STORAGE_DIRECTORY_NAME = 'documents' +# Usage +#DOCUMENTS_PREVIEW_SIZE = '640x480' # Serving #DOCUMENTS_FILESYSTEM_FILESERVING_ENABLE = True #DOCUMENTS_FILESYSTEM_FILESERVING_PATH = u'/tmp/mayan/documents'