From 7417fca8353c3e30badcc2058c4ced171f38498c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 5 Jul 2011 19:34:05 -0400 Subject: [PATCH 01/47] First commit of new multiple document source app --- apps/sources/__init__.py | 0 apps/sources/admin.py | 8 +++ apps/sources/models.py | 122 +++++++++++++++++++++++++++++++++++++++ apps/sources/tests.py | 23 ++++++++ apps/sources/views.py | 1 + settings.py | 1 + 6 files changed, 155 insertions(+) create mode 100644 apps/sources/__init__.py create mode 100644 apps/sources/admin.py create mode 100644 apps/sources/models.py create mode 100644 apps/sources/tests.py create mode 100644 apps/sources/views.py diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/sources/admin.py b/apps/sources/admin.py new file mode 100644 index 0000000000..716d8224e5 --- /dev/null +++ b/apps/sources/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +from sources.models import StagingFolder, WebForm + + + +admin.site.register(StagingFolder) +admin.site.register(WebForm) diff --git a/apps/sources/models.py b/apps/sources/models.py new file mode 100644 index 0000000000..ae4cf1e9c7 --- /dev/null +++ b/apps/sources/models.py @@ -0,0 +1,122 @@ +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from documents.models import DocumentType +from metadata.models import MetadataType + + +SOURCE_UMCOMPRESS_CHOICE_Y = 'y' +SOURCE_UMCOMPRESS_CHOICE_N = 'n' +SOURCE_UMCOMPRESS_CHOICE_ASK = 'a' + +SOURCE_UNCOMPRESS_CHOICES = ( + (SOURCE_UMCOMPRESS_CHOICE_Y, _(u'Yes')), + (SOURCE_UMCOMPRESS_CHOICE_N, _(u'No')), +) + +SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES = ( + (SOURCE_UMCOMPRESS_CHOICE_Y, _(u'Yes')), + (SOURCE_UMCOMPRESS_CHOICE_N, _(u'No')), + (SOURCE_UMCOMPRESS_CHOICE_ASK, _(u'Ask')) +) + +SOURCE_ICON_DISK = 'disk' +SOURCE_ICON_DATABASE = 'database' +SOURCE_ICON_DRIVE = 'drive' +SOURCE_ICON_DRIVE_NETWORK = 'drive_network' +SOURCE_ICON_DRIVE_USER = 'drive_user' +SOURCE_ICON_EMAIL = 'email' +SOURCE_ICON_FOLDER = 'folder' +SOURCE_ICON_WORLD = 'world' + +SOURCE_ICON_CHOICES = ( + (SOURCE_ICON_DISK, _(u'disk')), + (SOURCE_ICON_DATABASE, _(u'database')), + (SOURCE_ICON_DRIVE, _(u'drive')), + (SOURCE_ICON_DRIVE_NETWORK, _(u'network drive')), + (SOURCE_ICON_DRIVE_USER, _(u'user drive')), + (SOURCE_ICON_EMAIL, _(u'envelope')), + (SOURCE_ICON_FOLDER, _(u'folder')), + (SOURCE_ICON_WORLD, _(u'world')) +) + +SOURCE_CHOICE_WEB_FORM = 'wform' +SOURCE_CHOICE_STAGING = 'stagn' + +SOURCE_CHOICES = ( + (SOURCE_CHOICE_WEB_FORM, _(u'Web form')), + (SOURCE_CHOICE_STAGING, _(u'Server staging folder')), +) + + +class BaseModel(models.Model): + title = models.CharField(max_length=64, verbose_name=_(u'title')) + enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) + whitelist = models.TextField(blank=True, verbose_name=_(u'whitelist')) + 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'] + abstract = True + + +#class MetadataValue(models.Model): +# source = models.ForeignKey(BaseModel, verbose_name=_(u'document source')) +# metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) +# value = models.CharField(max_length=256, blank=True, verbose_name=_(u'value')) +# +# def __unicode__(self): +# return self.source +# +# class Meta: +# verbose_name = _(u'source metadata') +# verbose_name_plural = _(u'sources metadata') + + +class InteractiveBaseModel(BaseModel): + icon = models.CharField(blank=True, null=True, max_length=24, choices=SOURCE_ICON_CHOICES, verbose_name=_(u'icon')) + + def save(self, *args, **kwargs): + if not self.icon: + self.icon = self.default_icon + super(BaseModel, self).save(*args, **kwargs) + + class Meta: + abstract = True + + +class StagingFolder(InteractiveBaseModel): + is_interactive = True + source_type = SOURCE_CHOICE_STAGING + default_icon = SOURCE_ICON_DRIVE + + folder_path = models.CharField(max_length=255, verbose_name=_(u'folder path')) + preview_width = models.IntegerField(verbose_name=_(u'preview width')) + preview_height = models.IntegerField(blank=True, null=True, verbose_name=_(u'preview height')) + 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')) + + class Meta: + verbose_name = _(u'staging folder') + verbose_name_plural = _(u'staging folder') + + +class WebForm(InteractiveBaseModel): + is_interactive = True + source_type = SOURCE_CHOICE_WEB_FORM + default_icon = SOURCE_ICON_DISK + + uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_(u'uncompress')) + #Default path + + class Meta: + verbose_name = _(u'web form') + verbose_name_plural = _(u'web forms') diff --git a/apps/sources/tests.py b/apps/sources/tests.py new file mode 100644 index 0000000000..2247054b35 --- /dev/null +++ b/apps/sources/tests.py @@ -0,0 +1,23 @@ +""" +This file demonstrates two different styles of tests (one doctest and one +unittest). These will both pass when you run "manage.py test". + +Replace these with more appropriate tests for your application. +""" + +from django.test import TestCase + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.failUnlessEqual(1 + 1, 2) + +__test__ = {"doctest": """ +Another way to test that 1 + 1 is equal to 2. + +>>> 1 + 1 == 2 +True +"""} + diff --git a/apps/sources/views.py b/apps/sources/views.py new file mode 100644 index 0000000000..60f00ef0ef --- /dev/null +++ b/apps/sources/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/settings.py b/settings.py index 2c9bcfd951..080a3c98f4 100644 --- a/settings.py +++ b/settings.py @@ -149,6 +149,7 @@ INSTALLED_APPS = ( 'grouping', 'mptt', 'document_indexing', + 'sources', ) TEMPLATE_CONTEXT_PROCESSORS = ( From 2816c1f86f52e2115854a9e41d81efd04d9a2b44 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 6 Jul 2011 01:31:27 -0400 Subject: [PATCH 02/47] Got upload view working, staging preview and delete working ok --- apps/documents/__init__.py | 17 +- apps/documents/conf/settings.py | 14 +- apps/documents/forms.py | 4 +- apps/documents/literals.py | 4 - apps/documents/urls.py | 11 +- apps/documents/views.py | 19 +- apps/documents/wizards.py | 8 +- .../templatetags/navigation_tags.py | 14 + apps/sources/__init__.py | 19 + apps/sources/admin.py | 2 - apps/sources/forms.py | 39 ++ apps/sources/models.py | 18 +- apps/{documents => sources}/staging.py | 43 +- apps/sources/urls.py | 23 ++ apps/sources/views.py | 369 +++++++++++++++++- urls.py | 1 + 16 files changed, 520 insertions(+), 85 deletions(-) create mode 100644 apps/sources/forms.py rename apps/{documents => sources}/staging.py (73%) create mode 100644 apps/sources/urls.py diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index ace7578129..24ef2a7c59 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -13,9 +13,6 @@ from metadata.api import get_metadata_string from documents.models import Document, DocumentPage, \ DocumentPageTransformation, DocumentType, DocumentTypeFilename -from documents.staging import StagingFile -from documents.conf.settings import USE_STAGING_DIRECTORY -from documents.conf.settings import PER_USER_STAGING_DIRECTORY from documents.literals import PERMISSION_DOCUMENT_CREATE, \ PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_VIEW, \ PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD, \ @@ -107,13 +104,6 @@ document_page_rotate_left = {'text': _(u'rotate left'), 'class': 'no-parent-hist document_missing_list = {'text': _(u'Find missing document files'), 'view': 'document_missing_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -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', 'object.id'], 'famfam': 'drive_magnify'} -staging_file_delete = {'text': _(u'delete'), 'view': 'staging_file_delete', 'args': ['source', 'object.id'], 'famfam': 'drive_delete'} - # Document type related links document_type_list = {'text': _(u'document type list'), 'view': 'document_type_list', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_VIEW]} document_type_document_list = {'text': _(u'documents of this type'), 'view': 'document_type_document_list', 'args': 'object.id', 'famfam': 'page_go', 'permissions': [PERMISSION_DOCUMENT_VIEW]} @@ -141,7 +131,7 @@ register_links(['document_type_filename_edit', 'document_type_filename_delete'], register_links(Document, [document_edit, document_print, document_delete, document_download, document_find_duplicates, document_clear_transformations, document_create_siblings]) register_multi_item_links(['folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [document_multiple_clear_transformations, document_multiple_delete]) -register_links(['document_list_recent', 'document_list', 'document_create', 'document_create_multiple', 'upload_document', 'upload_document_from_local', 'upload_document_from_staging', 'upload_document_from_user_staging', 'document_find_duplicates'], [document_list_recent, document_list, document_create_multiple], menu_name='secondary_menu') +register_links(['document_list_recent', 'document_list', 'document_create', 'document_create_multiple', 'upload_interactive', 'document_find_duplicates'], [document_list_recent, document_list, document_create_multiple], menu_name='secondary_menu') # Document page links register_links(DocumentPage, [ @@ -157,17 +147,12 @@ register_links(DocumentPage, [ register_links(['document_page_view'], [document_page_rotate_left, document_page_rotate_right, document_page_zoom_in, document_page_zoom_out], menu_name='form_header') -# Upload sources -register_links(['upload_document_from_local', 'upload_document_from_staging', 'upload_document_from_user_staging'], [upload_document_from_local, upload_document_from_staging, upload_document_from_user_staging], menu_name='form_header') - register_links(DocumentPageTransformation, [document_page_transformation_edit, document_page_transformation_delete]) register_links(DocumentPageTransformation, [document_page_transformation_page_edit, document_page_transformation_page_view], menu_name='sidebar') register_links('document_page_transformation_list', [document_page_transformation_create], menu_name='sidebar') register_links('document_page_transformation_create', [document_page_transformation_create], menu_name='sidebar') register_links(['document_page_transformation_edit', 'document_page_transformation_delete'], [document_page_transformation_page_transformation_list], menu_name='sidebar') -register_links(StagingFile, [staging_file_preview, staging_file_delete]) - register_diagnostic('documents', _(u'Documents'), document_missing_list) register_tool(document_find_all_duplicates, namespace='documents', title=_(u'documents')) diff --git a/apps/documents/conf/settings.py b/apps/documents/conf/settings.py index 49af295531..a8036b44ea 100644 --- a/apps/documents/conf/settings.py +++ b/apps/documents/conf/settings.py @@ -27,13 +27,13 @@ register_settings( module=u'documents.conf.settings', settings=[ # Upload - {'name': u'USE_STAGING_DIRECTORY', 'global_name': u'DOCUMENTS_USE_STAGING_DIRECTORY', 'default': False}, - {'name': u'STAGING_DIRECTORY', 'global_name': u'DOCUMENTS_STAGING_DIRECTORY', 'default': u'/tmp/mayan/staging', 'exists': True}, - {'name': u'PER_USER_STAGING_DIRECTORY', 'global_name': u'DOCUMENTS_PER_USER_STAGING_DIRECTORY', 'default': False}, - {'name': u'USER_STAGING_DIRECTORY_ROOT', 'global_name': u'DOCUMENTS_USER_STAGING_DIRECTORY_ROOT', 'default': u'/tmp/mayan/staging/users', 'exists': True}, - {'name': u'USER_STAGING_DIRECTORY_EXPRESSION', 'global_name': u'DOCUMENTS_USER_STAGING_DIRECTORY_EXPRESSION', 'default': u'user.username'}, - {'name': u'DELETE_STAGING_FILE_AFTER_UPLOAD', 'global_name': u'DOCUMENTS_DELETE_STAGING_FILE_AFTER_UPLOAD', 'default': False}, - {'name': u'STAGING_FILES_PREVIEW_SIZE', 'global_name': u'DOCUMENTS_STAGING_FILES_PREVIEW_SIZE', 'default': u'640x480'}, + #{'name': u'USE_STAGING_DIRECTORY', 'global_name': u'DOCUMENTS_USE_STAGING_DIRECTORY', 'default': False}, + #{'name': u'STAGING_DIRECTORY', 'global_name': u'DOCUMENTS_STAGING_DIRECTORY', 'default': u'/tmp/mayan/staging', 'exists': True}, + #{'name': u'PER_USER_STAGING_DIRECTORY', 'global_name': u'DOCUMENTS_PER_USER_STAGING_DIRECTORY', 'default': False}, + #{'name': u'USER_STAGING_DIRECTORY_ROOT', 'global_name': u'DOCUMENTS_USER_STAGING_DIRECTORY_ROOT', 'default': u'/tmp/mayan/staging/users', 'exists': True}, + #{'name': u'USER_STAGING_DIRECTORY_EXPRESSION', 'global_name': u'DOCUMENTS_USER_STAGING_DIRECTORY_EXPRESSION', 'default': u'user.username'}, + #{'name': u'DELETE_STAGING_FILE_AFTER_UPLOAD', 'global_name': u'DOCUMENTS_DELETE_STAGING_FILE_AFTER_UPLOAD', 'default': False}, + #{'name': u'STAGING_FILES_PREVIEW_SIZE', 'global_name': u'DOCUMENTS_STAGING_FILES_PREVIEW_SIZE', 'default': u'640x480'}, # Saving {'name': u'CHECKSUM_FUNCTION', 'global_name': u'DOCUMENTS_CHECKSUM_FUNCTION', 'default': default_checksum}, {'name': u'UUID_FUNCTION', 'global_name': u'DOCUMENTS_UUID_FUNCTION', 'default': default_uuid}, diff --git a/apps/documents/forms.py b/apps/documents/forms.py index 9553b2ce00..bfd4eb0d21 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -265,7 +265,7 @@ class PrintForm(forms.Form): page_orientation = forms.ChoiceField(choices=PAGE_ORIENTATION_CHOICES, initial=DEFAULT_PAGE_ORIENTATION, label=_(u'Page orientation'), required=True) page_range = forms.CharField(label=_(u'Page range'), required=False) - +''' class StagingDocumentForm(DocumentForm): """ Form that show all the files in the staging folder specified by the @@ -290,7 +290,7 @@ class StagingDocumentForm(DocumentForm): class Meta(DocumentForm.Meta): exclude = ('description', 'file', 'document_type', 'tags') - +''' class DocumentTypeForm(forms.ModelForm): """ diff --git a/apps/documents/literals.py b/apps/documents/literals.py index aff31396f3..b2c0f023c2 100644 --- a/apps/documents/literals.py +++ b/apps/documents/literals.py @@ -18,10 +18,6 @@ PERMISSION_DOCUMENT_TYPE_EDIT = {'namespace': 'documents', 'name': 'document_typ PERMISSION_DOCUMENT_TYPE_DELETE = {'namespace': 'documents', 'name': 'document_type_delete', 'label': _(u'Delete document types')} PERMISSION_DOCUMENT_TYPE_CREATE = {'namespace': 'documents', 'name': 'document_type_create', 'label': _(u'Create document types')} -UPLOAD_SOURCE_LOCAL = u'local' -UPLOAD_SOURCE_STAGING = u'staging' -UPLOAD_SOURCE_USER_STAGING = u'user_staging' - HISTORY_DOCUMENT_CREATED = { 'namespace': 'documents', 'name': 'document_created', 'label': _(u'Document creation'), diff --git a/apps/documents/urls.py b/apps/documents/urls.py index 1add9cd55b..4dc99f37de 100644 --- a/apps/documents/urls.py +++ b/apps/documents/urls.py @@ -7,18 +7,14 @@ 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 +#from documents.literals import UPLOAD_SOURCE_LOCAL, \ +# UPLOAD_SOURCE_STAGING, UPLOAD_SOURCE_USER_STAGING urlpatterns = patterns('documents.views', url(r'^list/$', 'document_list', (), 'document_list'), url(r'^list/recent/$', 'document_list_recent', (), 'document_list_recent'), url(r'^create/from/local/multiple/$', 'document_create', (), 'document_create_multiple'), - 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'^(?P\d+)/view/$', 'document_view', (), 'document_view_simple'), url(r'^(?P\d+)/view/advanced/$', 'document_view', {'advanced': True}, 'document_view_advanced'), url(r'^(?P\d+)/delete/$', 'document_delete', (), 'document_delete'), @@ -41,9 +37,6 @@ urlpatterns = patterns('documents.views', url(r'^multiple/clear_transformations/$', 'document_multiple_clear_transformations', (), 'document_multiple_clear_transformations'), url(r'^duplicates/list/$', 'document_find_all_duplicates', (), 'document_find_all_duplicates'), - url(r'^staging_file/type/(?P\w+)/(?P\w+)/preview/$', 'staging_file_preview', (), 'staging_file_preview'), - url(r'^staging_file/type/(?P\w+)/(?P\w+)/delete/$', 'staging_file_delete', (), 'staging_file_delete'), - url(r'^page/(?P\d+)/$', 'document_page_view', (), 'document_page_view'), url(r'^page/(?P\d+)/text/$', 'document_page_text', (), 'document_page_text'), url(r'^page/(?P\d+)/edit/$', 'document_page_edit', (), 'document_page_edit'), diff --git a/apps/documents/views.py b/apps/documents/views.py index d29e9eda18..594009b1b2 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -36,10 +36,6 @@ from permissions.api import check_permissions from document_indexing.api import update_indexes, delete_indexes from history.api import create_history -from documents.conf.settings import DELETE_STAGING_FILE_AFTER_UPLOAD -from documents.conf.settings import USE_STAGING_DIRECTORY -from documents.conf.settings import PER_USER_STAGING_DIRECTORY - from documents.conf.settings import PREVIEW_SIZE from documents.conf.settings import THUMBNAIL_SIZE from documents.conf.settings import STORAGE_BACKEND @@ -61,7 +57,7 @@ from documents.literals import HISTORY_DOCUMENT_CREATED, \ from documents.forms import DocumentTypeSelectForm, \ DocumentForm, DocumentForm_edit, DocumentPropertiesForm, \ - StagingDocumentForm, DocumentPreviewForm, \ + DocumentPreviewForm, \ DocumentPageForm, DocumentPageTransformationForm, \ DocumentContentForm, DocumentPageForm_edit, \ DocumentPageForm_text, PrintForm, DocumentTypeForm, \ @@ -69,11 +65,8 @@ from documents.forms import DocumentTypeSelectForm, \ from documents.wizards import DocumentCreateWizard from documents.models import Document, DocumentType, DocumentPage, \ DocumentPageTransformation, RecentDocument, DocumentTypeFilename -from documents.staging import create_staging_file_class from documents.literals import PICTURE_ERROR_SMALL, PICTURE_ERROR_MEDIUM, \ PICTURE_UNKNOWN_SMALL, PICTURE_UNKNOWN_MEDIUM -from documents.literals import UPLOAD_SOURCE_LOCAL, \ - UPLOAD_SOURCE_STAGING, UPLOAD_SOURCE_USER_STAGING # Document type permissions from documents.literals import PERMISSION_DOCUMENT_TYPE_EDIT, \ @@ -116,10 +109,10 @@ def document_create_siblings(request, document_id): if document.document_type_id: query_dict['document_type_id'] = document.document_type_id - url = reverse('upload_document_from_local') + url = reverse('upload_interactive') return HttpResponseRedirect('%s?%s' % (url, urlencode(query_dict))) - +''' def _handle_save_document(request, document, form=None): RecentDocument.objects.add_document_for_user(request.user, document) @@ -279,7 +272,7 @@ def upload_document_with_type(request, source): } return render_to_response('generic_form.html', context, context_instance=RequestContext(request)) - +''' def document_view(request, document_id, advanced=False): check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) @@ -545,7 +538,7 @@ def document_download(request, document_id): messages.error(request, e) return HttpResponseRedirect(request.META['HTTP_REFERER']) - +''' def staging_file_preview(request, source, staging_file_id): check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) StagingFile = create_staging_file_class(request, source) @@ -596,7 +589,7 @@ def staging_file_delete(request, source, staging_file_id): 'previous': previous, 'form_icon': u'drive_delete.png', }, context_instance=RequestContext(request)) - +''' def document_page_transformation_list(request, document_page_id): check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) diff --git a/apps/documents/wizards.py b/apps/documents/wizards.py index c2b76b9028..a61ba4960a 100644 --- a/apps/documents/wizards.py +++ b/apps/documents/wizards.py @@ -30,7 +30,6 @@ class DocumentCreateWizard(BoundFormWizard): def __init__(self, *args, **kwargs): self.query_dict = {} - self.multiple = kwargs.pop('multiple', True) self.step_titles = kwargs.pop('step_titles', [ _(u'step 1 of 3: Document type'), _(u'step 2 of 3: Metadata selection'), @@ -75,13 +74,8 @@ class DocumentCreateWizard(BoundFormWizard): return 'generic_wizard.html' def done(self, request, form_list): - if self.multiple: - view = 'upload_document_from_local' - else: - view = 'upload_document' - if self.document_type: self.query_dict['document_type_id'] = self.document_type.pk - url = urlquote(reverse(view), self.query_dict) + url = urlquote(reverse('upload_interactive'), self.query_dict) return HttpResponseRedirect(url) diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index b54ab6ddfc..f849f040f7 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -131,6 +131,9 @@ def _get_object_navigation_links(context, menu_name=None, links_dict=object_navi current_view = resolve_to_name(current_path) context_links = [] + # Don't fudge with the original global dictionary + links_dict = links_dict.copy() + query_string = urlparse.urlparse(request.get_full_path()).query or urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).query parsed_query_string = urlparse.parse_qs(query_string) @@ -155,6 +158,16 @@ def _get_object_navigation_links(context, menu_name=None, links_dict=object_navi except VariableDoesNotExist: obj = None + try: + """ + Check for and inject a temporary navigation dictionary + """ + temp_navigation_links = Variable('temporary_navigation_links').resolve(context) + if temp_navigation_links: + links_dict.update(temp_navigation_links) + except VariableDoesNotExist: + pass + try: links = links_dict[menu_name][current_view]['links'] for link in resolve_links(context, links, current_view, current_path, parsed_query_string): @@ -169,6 +182,7 @@ def _get_object_navigation_links(context, menu_name=None, links_dict=object_navi except KeyError: pass + return context_links diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index e69de29bb2..aa31d60f1d 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -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]) + diff --git a/apps/sources/admin.py b/apps/sources/admin.py index 716d8224e5..3cbf7078fb 100644 --- a/apps/sources/admin.py +++ b/apps/sources/admin.py @@ -2,7 +2,5 @@ from django.contrib import admin from sources.models import StagingFolder, WebForm - - admin.site.register(StagingFolder) admin.site.register(WebForm) diff --git a/apps/sources/forms.py b/apps/sources/forms.py new file mode 100644 index 0000000000..48f2a379c3 --- /dev/null +++ b/apps/sources/forms.py @@ -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') diff --git a/apps/sources/models.py b/apps/sources/models.py index ae4cf1e9c7..8dd162e8a1 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -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') diff --git a/apps/documents/staging.py b/apps/sources/staging.py similarity index 73% rename from apps/documents/staging.py rename to apps/sources/staging.py index ca11ddc20f..2dccf9d40a 100644 --- a/apps/documents/staging.py +++ b/apps/sources/staging.py @@ -11,24 +11,30 @@ 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 -from documents.conf.settings import DEFAULT_TRANSFORMATIONS -from documents.conf.settings import STAGING_FILES_PREVIEW_SIZE -from documents.conf.settings import USER_STAGING_DIRECTORY_ROOT -from documents.conf.settings import USER_STAGING_DIRECTORY_EXPRESSION +#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 +#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})) -} +#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): @@ -52,7 +58,8 @@ def _return_new_class(): def create_staging_file_class(request, source): cls = _return_new_class() - cls.set_path(evaluate_user_staging_path(request, source)) + #cls.set_path(evaluate_user_staging_path(request, source)) + cls.set_path(source) return cls @@ -120,8 +127,8 @@ class StagingFile(object): 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) + #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: @@ -130,9 +137,11 @@ class StagingFile(object): else: raise OSError(ugettext(u'Unable to delete staging file: %s') % exc) - def preview(self): - 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) + 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 diff --git a/apps/sources/urls.py b/apps/sources/urls.py new file mode 100644 index 0000000000..380d462d0e --- /dev/null +++ b/apps/sources/urls.py @@ -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\w+)/(?P\d+)/(?P\w+)/preview/$', 'staging_file_preview', (), 'staging_file_preview'), + url(r'^staging_file/type/(?P\w+)/(?P\d+)/(?P\w+)/delete/$', 'staging_file_delete', (), 'staging_file_delete'), + + url(r'^upload/interactive/(?P\w+)/(?P\d+)/$', 'upload_interactive', (), 'upload_interactive'), + url(r'^upload/interactive/$', 'upload_interactive', (), 'upload_interactive'), +) diff --git a/apps/sources/views.py b/apps/sources/views.py index 60f00ef0ef..b23cd8dfff 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -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)) diff --git a/urls.py b/urls.py index f8c245d097..86eedddb6f 100644 --- a/urls.py +++ b/urls.py @@ -25,6 +25,7 @@ urlpatterns = patterns('', (r'^document_indexing/', include('document_indexing.urls')), (r'^history/', include('history.urls')), (r'^converter/', include('converter.urls')), + (r'^sources/', include('sources.urls')), ) From ee3abd16ec441b1fe345224589c33acdac8fdff1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 6 Jul 2011 01:51:29 -0400 Subject: [PATCH 03/47] Document upload working from local and from staging folders --- apps/sources/models.py | 26 ++++++++-------- apps/sources/staging.py | 20 +++--------- apps/sources/urls.py | 14 --------- apps/sources/views.py | 68 +++++++++++++++++++++++++++++++++-------- 4 files changed, 72 insertions(+), 56 deletions(-) diff --git a/apps/sources/models.py b/apps/sources/models.py index 8dd162e8a1..54cb97436d 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -64,19 +64,6 @@ class BaseModel(models.Model): abstract = True -#class MetadataValue(models.Model): -# source = models.ForeignKey(BaseModel, verbose_name=_(u'document source')) -# metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) -# value = models.CharField(max_length=256, blank=True, verbose_name=_(u'value')) -# -# def __unicode__(self): -# return self.source -# -# class Meta: -# verbose_name = _(u'source metadata') -# verbose_name_plural = _(u'sources metadata') - - class InteractiveBaseModel(BaseModel): icon = models.CharField(blank=True, null=True, max_length=24, choices=SOURCE_ICON_CHOICES, verbose_name=_(u'icon')) @@ -111,6 +98,19 @@ class StagingFolder(InteractiveBaseModel): class Meta: verbose_name = _(u'staging folder') verbose_name_plural = _(u'staging folder') + + +#class StagingFolderMetadataValue(models.Model): +# source = models.ForeignKey(BaseModel, verbose_name=_(u'document source')) +# metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) +# value = models.CharField(max_length=256, blank=True, verbose_name=_(u'value')) +# +# def __unicode__(self): +# return self.source +# +# class Meta: +# verbose_name = _(u'source metadata') +# verbose_name_plural = _(u'sources metadata') class WebForm(InteractiveBaseModel): diff --git a/apps/sources/staging.py b/apps/sources/staging.py index 2dccf9d40a..3ac1ab1f48 100644 --- a/apps/sources/staging.py +++ b/apps/sources/staging.py @@ -11,20 +11,8 @@ 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' +DEFAULT_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 @@ -68,7 +56,7 @@ class StagingFile(object): Simple class to encapsulate the files in a directory and hide the specifics to the view """ - path = STAGING_DIRECTORY + path = DEFAULT_STAGING_DIRECTORY @classmethod def set_path(cls, path): @@ -126,9 +114,9 @@ class StagingFile(object): except Exception, exc: raise Exception(ugettext(u'Unable to upload staging file: %s') % exc) - def delete(self): + def delete(self, preview_size): #tranformation_string, errors = get_transformation_string(DEFAULT_TRANSFORMATIONS) - cache_cleanup(self.filepath, size=STAGING_FILES_PREVIEW_SIZE)#, extra_options=tranformation_string) + cache_cleanup(self.filepath, size=preview_size)#, extra_options=tranformation_string) try: os.unlink(self.filepath) except OSError, exc: diff --git a/apps/sources/urls.py b/apps/sources/urls.py index 380d462d0e..b3d6bd6fb4 100644 --- a/apps/sources/urls.py +++ b/apps/sources/urls.py @@ -1,20 +1,6 @@ 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\w+)/(?P\d+)/(?P\w+)/preview/$', 'staging_file_preview', (), 'staging_file_preview'), url(r'^staging_file/type/(?P\w+)/(?P\d+)/(?P\w+)/delete/$', 'staging_file_delete', (), 'staging_file_delete'), diff --git a/apps/sources/views.py b/apps/sources/views.py index b23cd8dfff..8bcb5b9434 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -8,19 +8,23 @@ 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 - +from documents.literals import PERMISSION_DOCUMENT_CREATE +from documents.literals import HISTORY_DOCUMENT_CREATED +from documents.models import RecentDocument, Document, DocumentType +from document_indexing.api import update_indexes +from history.api import create_history +from metadata.api import save_metadata_list, \ + decode_metadata_from_url, metadata_repr_as_list +from metadata.forms import MetadataFormSet, MetadataSelectionForm +from permissions.api import check_permissions +import sendfile + #TEMP from documents.forms import DocumentForm +#TEMP from sources.models import WebForm, StagingFolder from sources.models import SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING @@ -91,6 +95,23 @@ def upload_interactive(request, source_type=None, source_id=None): if source_type == SOURCE_CHOICE_WEB_FORM: web_form = get_object_or_404(WebForm, pk=source_id) context['source'] = web_form + if request.method == 'POST': + 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()) + form = DocumentForm(document_type=document_type) subtemplates_list.append({ @@ -104,6 +125,31 @@ def upload_interactive(request, source_type=None, source_id=None): staging_folder = get_object_or_404(StagingFolder, pk=source_id) context['source'] = staging_folder StagingFile = create_staging_file_class(request, staging_folder.folder_path) + if request.method == 'POST': + 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 staging_folder.delete_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']) + return HttpResponseRedirect(request.get_full_path()) + + form = StagingDocumentForm(cls=StagingFile, document_type=document_type) try: @@ -131,10 +177,6 @@ def upload_interactive(request, source_type=None, source_id=None): ] - - - - context.update({ 'document_type_id': document_type_id, 'subtemplates_list': subtemplates_list, @@ -352,7 +394,7 @@ def staging_file_delete(request, source_type, source_id, staging_file_id): if request.method == 'POST': try: - staging_file.delete() + staging_file.delete(staging_folder.get_preview_size()) messages.success(request, _(u'Staging file delete successfully.')) except Exception, e: messages.error(request, e) From 2739ad902705ceca71fb218af7a5268d24a930f8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 6 Jul 2011 03:11:48 -0400 Subject: [PATCH 04/47] Implmented conditional show of expand checkbox, initial support for conditional highlight (buggy) --- apps/documents/forms.py | 38 +--- apps/documents/views.py | 163 ----------------- .../templatetags/navigation_tags.py | 3 + apps/sources/__init__.py | 4 - apps/sources/forms.py | 19 ++ apps/sources/models.py | 16 +- apps/sources/views.py | 171 ++++-------------- 7 files changed, 66 insertions(+), 348 deletions(-) diff --git a/apps/documents/forms.py b/apps/documents/forms.py index bfd4eb0d21..6963280e2f 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -186,21 +186,11 @@ class DocumentForm(forms.ModelForm): queryset=filenames_qs, required=False, label=_(u'Quick document rename')) - - # Put the expand field last in the field order list - expand_field_index = self.fields.keyOrder.index('expand') - expand_field = self.fields.keyOrder.pop(expand_field_index) - self.fields.keyOrder.append(expand_field) new_filename = forms.CharField( label=_('New document filename'), required=False ) - - expand = forms.BooleanField( - label=_(u'Expand compressed files'), required=False, - help_text=ugettext(u'Upload a compressed file\'s contained files as individual documents') - ) - + class DocumentForm_edit(DocumentForm): """ @@ -265,32 +255,6 @@ class PrintForm(forms.Form): page_orientation = forms.ChoiceField(choices=PAGE_ORIENTATION_CHOICES, initial=DEFAULT_PAGE_ORIENTATION, label=_(u'Page orientation'), required=True) page_range = forms.CharField(label=_(u'Page range'), required=False) -''' -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') -''' class DocumentTypeForm(forms.ModelForm): """ diff --git a/apps/documents/views.py b/apps/documents/views.py index 594009b1b2..817164c693 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -1,5 +1,4 @@ import os -import zipfile import urlparse import copy @@ -13,7 +12,6 @@ from django.core.urlresolvers import reverse from django.views.generic.create_update import delete_object, update_object from django.conf import settings from django.utils.http import urlencode -from django.core.files.uploadedfile import SimpleUploadedFile import sendfile from common.utils import pretty_size, parse_range, urlquote, \ @@ -112,167 +110,6 @@ def document_create_siblings(request, document_id): url = reverse('upload_interactive') return HttpResponseRedirect('%s?%s' % (url, urlencode(query_dict))) -''' -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 document_view(request, document_id, advanced=False): check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index f849f040f7..d4c73b781b 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -115,6 +115,9 @@ def resolve_links(context, links, current_view, current_path, parsed_query_strin new_link['url'] = urlquote(new_link['url'], parsed_query_string) else: new_link['active'] = False + + if 'conditional_highlight' in link: + new_link['active'] = link['conditional_highlight'](context) if 'conditional_disable' in link: new_link['disabled'] = link['conditional_disable'](context) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index aa31d60f1d..fcd0f52fa0 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -8,10 +8,6 @@ from navigation.api import register_links, register_top_menu, \ 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'} diff --git a/apps/sources/forms.py b/apps/sources/forms.py index 48f2a379c3..3757af3854 100644 --- a/apps/sources/forms.py +++ b/apps/sources/forms.py @@ -20,6 +20,7 @@ class StagingDocumentForm(DocumentForm): """ def __init__(self, *args, **kwargs): cls = kwargs.pop('cls') + show_expand = kwargs.pop('show_expand', False) super(StagingDocumentForm, self).__init__(*args, **kwargs) try: self.fields['staging_file_id'].choices = [ @@ -28,6 +29,12 @@ class StagingDocumentForm(DocumentForm): except: pass + if show_expand: + self.fields['expand'] = forms.BooleanField( + label=_(u'Expand compressed files'), required=False, + help_text=ugettext(u'Upload a compressed file\'s contained files as individual documents') + ) + # 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) @@ -37,3 +44,15 @@ class StagingDocumentForm(DocumentForm): class Meta(DocumentForm.Meta): exclude = ('description', 'file', 'document_type', 'tags') + + +class WebFormForm(DocumentForm): + def __init__(self, *args, **kwargs): + show_expand = kwargs.pop('show_expand', False) + super(WebFormForm, self).__init__(*args, **kwargs) + + if show_expand: + self.fields['expand'] = forms.BooleanField( + label=_(u'Expand compressed files'), required=False, + help_text=ugettext(u'Upload a compressed file\'s contained files as individual documents') + ) diff --git a/apps/sources/models.py b/apps/sources/models.py index 54cb97436d..a755ed9ffa 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -5,19 +5,19 @@ from documents.models import DocumentType from metadata.models import MetadataType -SOURCE_UMCOMPRESS_CHOICE_Y = 'y' -SOURCE_UMCOMPRESS_CHOICE_N = 'n' -SOURCE_UMCOMPRESS_CHOICE_ASK = 'a' +SOURCE_UNCOMPRESS_CHOICE_Y = 'y' +SOURCE_UNCOMPRESS_CHOICE_N = 'n' +SOURCE_UNCOMPRESS_CHOICE_ASK = 'a' SOURCE_UNCOMPRESS_CHOICES = ( - (SOURCE_UMCOMPRESS_CHOICE_Y, _(u'Yes')), - (SOURCE_UMCOMPRESS_CHOICE_N, _(u'No')), + (SOURCE_UNCOMPRESS_CHOICE_Y, _(u'Yes')), + (SOURCE_UNCOMPRESS_CHOICE_N, _(u'No')), ) SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES = ( - (SOURCE_UMCOMPRESS_CHOICE_Y, _(u'Yes')), - (SOURCE_UMCOMPRESS_CHOICE_N, _(u'No')), - (SOURCE_UMCOMPRESS_CHOICE_ASK, _(u'Ask')) + (SOURCE_UNCOMPRESS_CHOICE_Y, _(u'Yes')), + (SOURCE_UNCOMPRESS_CHOICE_N, _(u'No')), + (SOURCE_UNCOMPRESS_CHOICE_ASK, _(u'Ask')) ) SOURCE_ICON_DISK = 'disk' diff --git a/apps/sources/views.py b/apps/sources/views.py index 8bcb5b9434..13fdf6932b 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -1,4 +1,5 @@ import os +import zipfile from django.http import HttpResponseRedirect from django.shortcuts import render_to_response, get_object_or_404 @@ -7,6 +8,7 @@ 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 django.core.files.uploadedfile import SimpleUploadedFile from converter.exceptions import UnkownConvertError, UnknownFormat from documents.literals import PICTURE_ERROR_SMALL, PICTURE_ERROR_MEDIUM, \ @@ -22,14 +24,12 @@ from metadata.forms import MetadataFormSet, MetadataSelectionForm from permissions.api import check_permissions import sendfile -#TEMP -from documents.forms import DocumentForm -#TEMP - from sources.models import WebForm, StagingFolder from sources.models import SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING +from sources.models import SOURCE_UNCOMPRESS_CHOICE_Y, \ + SOURCE_UNCOMPRESS_CHOICE_N, SOURCE_UNCOMPRESS_CHOICE_ASK from sources.staging import create_staging_file_class -from sources.forms import StagingDocumentForm +from sources.forms import StagingDocumentForm, WebFormForm def upload_interactive(request, source_type=None, source_id=None): @@ -48,7 +48,8 @@ def upload_interactive(request, source_type=None, source_id=None): 'view': 'upload_interactive', 'args': [u'"%s"' % web_form.source_type, web_form.pk], 'famfam': web_form.icon, - 'keep_query': True + 'keep_query': True, + 'conditional_highlight': lambda context: context['source'].source_type == web_form.source_type and context['source'].pk == web_form.pk, }) staging_folders = StagingFolder.objects.filter(enabled=True) @@ -58,7 +59,8 @@ def upload_interactive(request, source_type=None, source_id=None): 'view': 'upload_interactive', 'args': [u'"%s"' % staging_folder.source_type, staging_folder.pk], 'famfam': staging_folder.icon, - 'keep_query': True + 'keep_query': True, + 'conditional_highlight': lambda context: context['source'].source_type == staging_folder.source_type and context['source'].pk == staging_folder.pk, }) if web_forms.count() == 0 and staging_folders.count() == 0: @@ -90,16 +92,24 @@ def upload_interactive(request, source_type=None, source_id=None): 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 if request.method == 'POST': - form = DocumentForm(request.POST, request.FILES, document_type=document_type) + form = WebFormForm(request.POST, request.FILES, + document_type=document_type, + show_expand=(web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK) + ) if form.is_valid(): try: - expand = form.cleaned_data['expand'] + if web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK: + expand = form.cleaned_data['expand'] + else: + if web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_Y: + expand = True + else: + expand = False if (not expand) or (expand and not _handle_zip_file(request, request.FILES['file'], document_type)): instance = form.save() instance.save() @@ -112,7 +122,7 @@ def upload_interactive(request, source_type=None, source_id=None): return HttpResponseRedirect(request.get_full_path()) - form = DocumentForm(document_type=document_type) + form = WebFormForm(show_expand=(web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK), document_type=document_type) subtemplates_list.append({ 'name': 'generic_form_subtemplate.html', @@ -127,11 +137,19 @@ def upload_interactive(request, source_type=None, source_id=None): StagingFile = create_staging_file_class(request, staging_folder.folder_path) if request.method == 'POST': form = StagingDocumentForm(request.POST, request.FILES, - cls=StagingFile, document_type=document_type) + cls=StagingFile, document_type=document_type, + show_expand=(staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK) + ) if form.is_valid(): try: staging_file = StagingFile.get(form.cleaned_data['staging_file_id']) - expand = form.cleaned_data['expand'] + if staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK: + expand = form.cleaned_data['expand'] + else: + if staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_Y: + expand = True + else: + expand = False 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: @@ -141,17 +159,17 @@ def upload_interactive(request, source_type=None, source_id=None): messages.success(request, _(u'Staging file: %s, uploaded successfully.') % staging_file.filename) if staging_folder.delete_after_upload: - staging_file.delete() + staging_file.delete(staging_folder.get_preview_size()) 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']) return HttpResponseRedirect(request.get_full_path()) - form = StagingDocumentForm(cls=StagingFile, - document_type=document_type) + document_type=document_type, + show_expand=(staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK) + ) try: staging_filelist = StagingFile.get_all() except Exception, e: @@ -176,7 +194,6 @@ def upload_interactive(request, source_type=None, source_id=None): }, ] - context.update({ 'document_type_id': document_type_id, 'subtemplates_list': subtemplates_list, @@ -238,124 +255,6 @@ def _handle_zip_file(request, uploaded_file, document_type=None): 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) From 83de8c7b49269a67e89334e78d58e8366fee7745 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 6 Jul 2011 03:22:53 -0400 Subject: [PATCH 05/47] PEP8 Cleanups --- apps/documents/conf/settings.py | 8 -------- apps/sources/__init__.py | 5 +---- apps/sources/forms.py | 14 +++----------- apps/sources/models.py | 20 ++++++++++---------- apps/sources/staging.py | 20 ++++++++++---------- apps/sources/views.py | 23 +++++++++++------------ 6 files changed, 35 insertions(+), 55 deletions(-) diff --git a/apps/documents/conf/settings.py b/apps/documents/conf/settings.py index a8036b44ea..6a4907d985 100644 --- a/apps/documents/conf/settings.py +++ b/apps/documents/conf/settings.py @@ -26,14 +26,6 @@ register_settings( namespace=u'documents', module=u'documents.conf.settings', settings=[ - # Upload - #{'name': u'USE_STAGING_DIRECTORY', 'global_name': u'DOCUMENTS_USE_STAGING_DIRECTORY', 'default': False}, - #{'name': u'STAGING_DIRECTORY', 'global_name': u'DOCUMENTS_STAGING_DIRECTORY', 'default': u'/tmp/mayan/staging', 'exists': True}, - #{'name': u'PER_USER_STAGING_DIRECTORY', 'global_name': u'DOCUMENTS_PER_USER_STAGING_DIRECTORY', 'default': False}, - #{'name': u'USER_STAGING_DIRECTORY_ROOT', 'global_name': u'DOCUMENTS_USER_STAGING_DIRECTORY_ROOT', 'default': u'/tmp/mayan/staging/users', 'exists': True}, - #{'name': u'USER_STAGING_DIRECTORY_EXPRESSION', 'global_name': u'DOCUMENTS_USER_STAGING_DIRECTORY_EXPRESSION', 'default': u'user.username'}, - #{'name': u'DELETE_STAGING_FILE_AFTER_UPLOAD', 'global_name': u'DOCUMENTS_DELETE_STAGING_FILE_AFTER_UPLOAD', 'default': False}, - #{'name': u'STAGING_FILES_PREVIEW_SIZE', 'global_name': u'DOCUMENTS_STAGING_FILES_PREVIEW_SIZE', 'default': u'640x480'}, # Saving {'name': u'CHECKSUM_FUNCTION', 'global_name': u'DOCUMENTS_CHECKSUM_FUNCTION', 'default': default_checksum}, {'name': u'UUID_FUNCTION', 'global_name': u'DOCUMENTS_UUID_FUNCTION', 'default': default_uuid}, diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index fcd0f52fa0..78690ed3b9 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -1,8 +1,6 @@ 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, \ +from navigation.api import register_links, \ register_model_list_columns, register_multi_item_links, \ register_sidebar_template @@ -12,4 +10,3 @@ staging_file_preview = {'text': _(u'preview'), 'class': 'fancybox-noscaling', 'v 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]) - diff --git a/apps/sources/forms.py b/apps/sources/forms.py index 3757af3854..f239d4eaf9 100644 --- a/apps/sources/forms.py +++ b/apps/sources/forms.py @@ -1,14 +1,6 @@ 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 @@ -31,7 +23,7 @@ class StagingDocumentForm(DocumentForm): if show_expand: self.fields['expand'] = forms.BooleanField( - label=_(u'Expand compressed files'), required=False, + label=_(u'Expand compressed files'), required=False, help_text=ugettext(u'Upload a compressed file\'s contained files as individual documents') ) @@ -50,9 +42,9 @@ class WebFormForm(DocumentForm): def __init__(self, *args, **kwargs): show_expand = kwargs.pop('show_expand', False) super(WebFormForm, self).__init__(*args, **kwargs) - + if show_expand: self.fields['expand'] = forms.BooleanField( - label=_(u'Expand compressed files'), required=False, + label=_(u'Expand compressed files'), required=False, help_text=ugettext(u'Upload a compressed file\'s contained files as individual documents') ) diff --git a/apps/sources/models.py b/apps/sources/models.py index a755ed9ffa..e36c9e40e8 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -42,7 +42,7 @@ SOURCE_ICON_CHOICES = ( SOURCE_CHOICE_WEB_FORM = 'webform' SOURCE_CHOICE_STAGING = 'staging' - + SOURCE_CHOICES = ( (SOURCE_CHOICE_WEB_FORM, _(u'Web form')), (SOURCE_CHOICE_STAGING, _(u'Server staging folder')), @@ -55,10 +55,10 @@ class BaseModel(models.Model): whitelist = models.TextField(blank=True, verbose_name=_(u'whitelist')) blacklist = models.TextField(blank=True, verbose_name=_(u'blacklist')) document_type = models.ForeignKey(DocumentType, blank=True, null=True, verbose_name=_(u'document type')) - - def __unicode__(self): - return u'%s (%s)' % (self.title, dict(SOURCE_CHOICES).get(self.source_type)) + def __unicode__(self): + return u'%s (%s)' % (self.title, dict(SOURCE_CHOICES).get(self.source_type)) + class Meta: ordering = ('title',) abstract = True @@ -86,18 +86,18 @@ class StagingFolder(InteractiveBaseModel): preview_height = models.IntegerField(blank=True, null=True, verbose_name=_(u'preview height')) 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') + verbose_name_plural = _(u'staging folder') #class StagingFolderMetadataValue(models.Model): @@ -111,7 +111,7 @@ class StagingFolder(InteractiveBaseModel): # class Meta: # verbose_name = _(u'source metadata') # verbose_name_plural = _(u'sources metadata') - + class WebForm(InteractiveBaseModel): is_interactive = True @@ -123,4 +123,4 @@ class WebForm(InteractiveBaseModel): class Meta: verbose_name = _(u'web form') - verbose_name_plural = _(u'web forms') + verbose_name_plural = _(u'web forms') diff --git a/apps/sources/staging.py b/apps/sources/staging.py index 3ac1ab1f48..c6668455c9 100644 --- a/apps/sources/staging.py +++ b/apps/sources/staging.py @@ -25,12 +25,12 @@ HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest() #} -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 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): @@ -115,8 +115,8 @@ class StagingFile(object): raise Exception(ugettext(u'Unable to upload staging file: %s') % exc) def delete(self, preview_size): - #tranformation_string, errors = get_transformation_string(DEFAULT_TRANSFORMATIONS) - cache_cleanup(self.filepath, size=preview_size)#, extra_options=tranformation_string) + # tranformation_string, errors = get_transformation_string(DEFAULT_TRANSFORMATIONS) + cache_cleanup(self.filepath, size=preview_size)# , extra_options=tranformation_string) try: os.unlink(self.filepath) except OSError, exc: @@ -127,8 +127,8 @@ class StagingFile(object): 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) + # 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 diff --git a/apps/sources/views.py b/apps/sources/views.py index 13fdf6932b..23a2b97c21 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -20,14 +20,13 @@ from document_indexing.api import update_indexes from history.api import create_history from metadata.api import save_metadata_list, \ decode_metadata_from_url, metadata_repr_as_list -from metadata.forms import MetadataFormSet, MetadataSelectionForm from permissions.api import check_permissions import sendfile - + from sources.models import WebForm, StagingFolder from sources.models import SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING from sources.models import SOURCE_UNCOMPRESS_CHOICE_Y, \ - SOURCE_UNCOMPRESS_CHOICE_N, SOURCE_UNCOMPRESS_CHOICE_ASK + SOURCE_UNCOMPRESS_CHOICE_ASK from sources.staging import create_staging_file_class from sources.forms import StagingDocumentForm, WebFormForm @@ -38,7 +37,7 @@ def upload_interactive(request, source_type=None, source_id=None): subtemplates_list = [] tab_links = [] - + context = {} web_forms = WebForm.objects.filter(enabled=True) @@ -62,7 +61,7 @@ def upload_interactive(request, source_type=None, source_id=None): 'keep_query': True, 'conditional_highlight': lambda context: context['source'].source_type == staging_folder.source_type and context['source'].pk == staging_folder.pk, }) - + if web_forms.count() == 0 and staging_folders.count() == 0: subtemplates_list.append( { @@ -83,7 +82,7 @@ def upload_interactive(request, source_type=None, source_id=None): 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 @@ -99,14 +98,14 @@ def upload_interactive(request, source_type=None, source_id=None): if request.method == 'POST': form = WebFormForm(request.POST, request.FILES, document_type=document_type, - show_expand=(web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK) + show_expand=(web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK) ) if form.is_valid(): try: - if web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK: + if web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK: expand = form.cleaned_data['expand'] else: - if web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_Y: + if web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y: expand = True else: expand = False @@ -143,10 +142,10 @@ def upload_interactive(request, source_type=None, source_id=None): if form.is_valid(): try: staging_file = StagingFile.get(form.cleaned_data['staging_file_id']) - if staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK: + if staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK: expand = form.cleaned_data['expand'] else: - if staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_Y: + if staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y: expand = True else: expand = False @@ -306,4 +305,4 @@ def staging_file_delete(request, source_type, source_id, staging_file_id): 'next': next, 'previous': previous, 'form_icon': u'delete.png', - }, context_instance=RequestContext(request)) + }, context_instance=RequestContext(request)) From 98417434731ba4c7cc372c92d4d63f28fd6c7543 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 6 Jul 2011 14:30:20 -0400 Subject: [PATCH 06/47] Solved conditional highlight problem --- apps/sources/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/sources/views.py b/apps/sources/views.py index 23a2b97c21..2449928c3a 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -30,6 +30,9 @@ from sources.models import SOURCE_UNCOMPRESS_CHOICE_Y, \ from sources.staging import create_staging_file_class from sources.forms import StagingDocumentForm, WebFormForm +def return_function(obj): + return lambda context: context['source'].source_type == obj.source_type and context['source'].pk == obj.pk + def upload_interactive(request, source_type=None, source_id=None): check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) @@ -48,7 +51,7 @@ def upload_interactive(request, source_type=None, source_id=None): 'args': [u'"%s"' % web_form.source_type, web_form.pk], 'famfam': web_form.icon, 'keep_query': True, - 'conditional_highlight': lambda context: context['source'].source_type == web_form.source_type and context['source'].pk == web_form.pk, + 'conditional_highlight': return_function(web_form), }) staging_folders = StagingFolder.objects.filter(enabled=True) @@ -59,7 +62,7 @@ def upload_interactive(request, source_type=None, source_id=None): 'args': [u'"%s"' % staging_folder.source_type, staging_folder.pk], 'famfam': staging_folder.icon, 'keep_query': True, - 'conditional_highlight': lambda context: context['source'].source_type == staging_folder.source_type and context['source'].pk == staging_folder.pk, + 'conditional_highlight': return_function(staging_folder), }) if web_forms.count() == 0 and staging_folders.count() == 0: From 0afa35b2566c5c1fa244a3c04156889057d0bed4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 6 Jul 2011 16:37:48 -0400 Subject: [PATCH 07/47] Change metadata set setup link icons --- apps/metadata/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index e4d602bd90..bf7629d985 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -52,10 +52,10 @@ setup_metadata_type_edit = {'text': _(u'edit'), 'view': 'setup_metadata_type_edi setup_metadata_type_delete = {'text': _(u'delete'), 'view': 'setup_metadata_type_delete', 'args': 'object.pk', 'famfam': 'xhtml_delete', 'permissions': [PERMISSION_METADATA_TYPE_DELETE]} setup_metadata_type_create = {'text': _(u'create new'), 'view': 'setup_metadata_type_create', 'famfam': 'xhtml_add', 'permissions': [PERMISSION_METADATA_TYPE_CREATE]} -setup_metadata_set_list = {'text': _(u'metadata sets'), 'view': 'setup_metadata_set_list', 'famfam': 'application_form', 'permissions': [PERMISSION_METADATA_SET_VIEW]} -setup_metadata_set_edit = {'text': _(u'edit'), 'view': 'setup_metadata_set_edit', 'args': 'object.pk', 'famfam': 'application_form_edit', 'permissions': [PERMISSION_METADATA_SET_EDIT]} -setup_metadata_set_delete = {'text': _(u'delete'), 'view': 'setup_metadata_set_delete', 'args': 'object.pk', 'famfam': 'application_form_delete', 'permissions': [PERMISSION_METADATA_SET_DELETE]} -setup_metadata_set_create = {'text': _(u'create new'), 'view': 'setup_metadata_set_create', 'famfam': 'application_form_add', 'permissions': [PERMISSION_METADATA_SET_CREATE]} +setup_metadata_set_list = {'text': _(u'metadata sets'), 'view': 'setup_metadata_set_list', 'famfam': 'table', 'permissions': [PERMISSION_METADATA_SET_VIEW]} +setup_metadata_set_edit = {'text': _(u'edit'), 'view': 'setup_metadata_set_edit', 'args': 'object.pk', 'famfam': 'table_edit', 'permissions': [PERMISSION_METADATA_SET_EDIT]} +setup_metadata_set_delete = {'text': _(u'delete'), 'view': 'setup_metadata_set_delete', 'args': 'object.pk', 'famfam': 'table_delete', 'permissions': [PERMISSION_METADATA_SET_DELETE]} +setup_metadata_set_create = {'text': _(u'create new'), 'view': 'setup_metadata_set_create', 'famfam': 'table_add', 'permissions': [PERMISSION_METADATA_SET_CREATE]} setup_document_type_metadata = {'text': _(u'default metadata'), 'view': 'setup_document_type_metadata', 'args': 'object.pk', 'famfam': 'xhtml', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} From 0b4df317260e1d489255dafb18f264c15759eb9c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 6 Jul 2011 16:38:15 -0400 Subject: [PATCH 08/47] Finished document source setup views --- apps/main/__init__.py | 6 +- apps/sources/__init__.py | 25 +++++++ apps/sources/forms.py | 12 ++++ apps/sources/models.py | 8 +-- apps/sources/urls.py | 15 +++++ apps/sources/views.py | 136 ++++++++++++++++++++++++++++++++++++++- 6 files changed, 195 insertions(+), 7 deletions(-) diff --git a/apps/main/__init__.py b/apps/main/__init__.py index c25a86ec9e..7f9364129a 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -9,6 +9,7 @@ from converter import formats_list from documents import document_type_views from metadata import setup_metadata_type_list, metadata_type_setup_views from metadata import setup_metadata_set_list, metadata_set_setup_views +from sources import source_list, source_views from main.conf.settings import SIDE_BAR_SEARCH from main.conf.settings import DISABLE_HOME_VIEW @@ -45,18 +46,19 @@ if not SIDE_BAR_SEARCH: register_top_menu('tools', link=tools_menu, children_views=['statistics', 'history_list', 'formats_list']) #register_top_menu('setup_menu', link={'text': _(u'setup'), 'view': 'setting_list', 'famfam': 'cog'}, children=setup_views) -register_top_menu('setup_menu', link={'text': _(u'setup'), 'view': 'setting_list', 'famfam': 'cog'}, children_path_regex=[r'^settings/', r'^user_management/', r'^permissions', r'^documents/type', r'^metadata/setup']) +register_top_menu('setup_menu', link={'text': _(u'setup'), 'view': 'setting_list', 'famfam': 'cog'}, children_path_regex=[r'^settings/', r'^user_management/', r'^permissions', r'^documents/type', r'^metadata/setup', r'sources/setup']) register_top_menu('about', link={'text': _(u'about'), 'view': 'about', 'famfam': 'information'}) register_links(['tools_menu', 'statistics', 'history_list', 'history_view', 'formats_list'], [tools_menu, statistics, history_list, formats_list, sentry], menu_name='secondary_menu') -setup_links = [check_settings, role_list, user_list, group_list, document_types, setup_metadata_type_list, setup_metadata_set_list, admin_site] +setup_links = [check_settings, role_list, user_list, group_list, document_types, setup_metadata_type_list, setup_metadata_set_list, source_list, admin_site] register_links(['setting_list'], setup_links, menu_name='secondary_menu') register_links(permission_views, setup_links, menu_name='secondary_menu') register_links(user_management_views, setup_links, menu_name='secondary_menu') register_links(document_type_views, setup_links, menu_name='secondary_menu') register_links(metadata_type_setup_views, setup_links, menu_name='secondary_menu') register_links(metadata_set_setup_views, setup_links, menu_name='secondary_menu') +register_links(source_views, setup_links, menu_name='secondary_menu') def get_version(): diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index 78690ed3b9..000e52a0ec 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -5,8 +5,33 @@ from navigation.api import register_links, \ register_sidebar_template from sources.staging import StagingFile +from sources.models import WebForm, StagingFolder 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'} +setup_web_form_list = {'text': _(u'web forms'), 'view': 'setup_web_form_list', 'famfam': 'application_form'} +setup_web_form_edit = {'text': _(u'edit'), 'view': 'setup_web_form_edit', 'args': 'object.pk', 'famfam': 'application_form_edit'} +setup_web_form_delete = {'text': _(u'delete'), 'view': 'setup_web_form_delete', 'args': 'object.pk', 'famfam': 'application_form_delete'} +setup_web_form_create = {'text': _(u'add new'), 'view': 'setup_web_form_create', 'famfam': 'application_form_add'} + +setup_staging_folder_list = {'text': _(u'staging folders'), 'view': 'setup_staging_folder_list', 'famfam': 'folder_magnify'} +setup_staging_folder_edit = {'text': _(u'edit'), 'view': 'setup_staging_folder_edit', 'args': 'object.pk', 'famfam': 'folder_edit'} +setup_staging_folder_delete = {'text': _(u'delete'), 'view': 'setup_staging_folder_delete', 'args': 'object.pk', 'famfam': 'folder_delete'} +setup_staging_folder_create = {'text': _(u'add new'), 'view': 'setup_staging_folder_create', 'famfam': 'folder_add'} + +source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'famfam': 'page_add'} + register_links(StagingFile, [staging_file_preview, staging_file_delete]) + +register_links(['setup_web_form_list', 'setup_web_form_create', 'setup_staging_folder_list', 'setup_staging_folder_create'], [setup_web_form_list, setup_staging_folder_list], menu_name='form_header') + +register_links(WebForm, [setup_web_form_list, setup_staging_folder_list], menu_name='form_header') +register_links(WebForm, [setup_web_form_edit, setup_web_form_delete]) +register_links(['setup_web_form_list', 'setup_web_form_edit', 'setup_web_form_delete', 'setup_web_form_create'], [setup_web_form_create], menu_name='sidebar') + +register_links(StagingFolder, [setup_web_form_list, setup_staging_folder_list], menu_name='form_header') +register_links(StagingFolder, [setup_staging_folder_edit, setup_staging_folder_delete]) +register_links(['setup_staging_folder_list', 'setup_staging_folder_edit', 'setup_staging_folder_delete', 'setup_staging_folder_create'], [setup_staging_folder_create], menu_name='sidebar') + +source_views = ['setup_web_form_list', 'setup_web_form_edit', 'setup_web_form_delete', 'setup_web_form_create', 'setup_staging_folder_list', 'setup_staging_folder_edit', 'setup_staging_folder_delete', 'setup_staging_folder_create'] diff --git a/apps/sources/forms.py b/apps/sources/forms.py index f239d4eaf9..b759c3259d 100644 --- a/apps/sources/forms.py +++ b/apps/sources/forms.py @@ -4,6 +4,8 @@ from django.utils.translation import ugettext from documents.forms import DocumentForm +from sources.models import WebForm, StagingFolder + class StagingDocumentForm(DocumentForm): """ @@ -48,3 +50,13 @@ class WebFormForm(DocumentForm): label=_(u'Expand compressed files'), required=False, help_text=ugettext(u'Upload a compressed file\'s contained files as individual documents') ) + + +class WebFormSetupForm(forms.ModelForm): + class Meta: + model = WebForm + + +class StagingFolderSetupForm(forms.ModelForm): + class Meta: + model = StagingFolder diff --git a/apps/sources/models.py b/apps/sources/models.py index e36c9e40e8..666ea7cc30 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -57,7 +57,7 @@ class BaseModel(models.Model): document_type = models.ForeignKey(DocumentType, blank=True, null=True, verbose_name=_(u'document type')) def __unicode__(self): - return u'%s (%s)' % (self.title, dict(SOURCE_CHOICES).get(self.source_type)) + return u'%s' % self.title class Meta: ordering = ('title',) @@ -72,7 +72,7 @@ class InteractiveBaseModel(BaseModel): self.icon = self.default_icon super(BaseModel, self).save(*args, **kwargs) - class Meta: + class Meta(BaseModel.Meta): abstract = True @@ -95,7 +95,7 @@ class StagingFolder(InteractiveBaseModel): return u'x'.join(dimensions) - class Meta: + class Meta(InteractiveBaseModel.Meta): verbose_name = _(u'staging folder') verbose_name_plural = _(u'staging folder') @@ -121,6 +121,6 @@ class WebForm(InteractiveBaseModel): uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_(u'uncompress')) #Default path - class Meta: + class Meta(InteractiveBaseModel.Meta): verbose_name = _(u'web form') verbose_name_plural = _(u'web forms') diff --git a/apps/sources/urls.py b/apps/sources/urls.py index b3d6bd6fb4..c4f2fcd0d7 100644 --- a/apps/sources/urls.py +++ b/apps/sources/urls.py @@ -1,9 +1,24 @@ from django.conf.urls.defaults import patterns, url +from sources.models import SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING + urlpatterns = patterns('sources.views', url(r'^staging_file/type/(?P\w+)/(?P\d+)/(?P\w+)/preview/$', 'staging_file_preview', (), 'staging_file_preview'), url(r'^staging_file/type/(?P\w+)/(?P\d+)/(?P\w+)/delete/$', 'staging_file_delete', (), 'staging_file_delete'), url(r'^upload/interactive/(?P\w+)/(?P\d+)/$', 'upload_interactive', (), 'upload_interactive'), url(r'^upload/interactive/$', 'upload_interactive', (), 'upload_interactive'), + + #Setup views + + url(r'^setup/interactive/webforms/list/$', 'setup_source_list', {'source_type': SOURCE_CHOICE_WEB_FORM}, 'setup_web_form_list'), + url(r'^setup/interactive/webforms/(?P\w+)/edit/$', 'setup_source_edit', {'source_type': SOURCE_CHOICE_WEB_FORM}, 'setup_web_form_edit'), + url(r'^setup/interactive/webforms/(?P\w+)/delete/$', 'setup_source_delete', {'source_type': SOURCE_CHOICE_WEB_FORM}, 'setup_web_form_delete'), + url(r'^setup/interactive/webforms/create/$', 'setup_source_create', {'source_type': SOURCE_CHOICE_WEB_FORM}, 'setup_web_form_create'), + + url(r'^setup/interactive/staging_folder/list/$', 'setup_source_list', {'source_type': SOURCE_CHOICE_STAGING}, 'setup_staging_folder_list'), + url(r'^setup/interactive/staging_folder/(?P\w+)/edit/$', 'setup_source_edit', {'source_type': SOURCE_CHOICE_STAGING}, 'setup_staging_folder_edit'), + url(r'^setup/interactive/staging_folder/(?P\w+)/delete/$', 'setup_source_delete', {'source_type': SOURCE_CHOICE_STAGING}, 'setup_staging_folder_delete'), + url(r'^setup/interactive/staging_folder/create/$', 'setup_source_create', {'source_type': SOURCE_CHOICE_STAGING}, 'setup_staging_folder_create'), + ) diff --git a/apps/sources/views.py b/apps/sources/views.py index 2449928c3a..90468349cf 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -29,6 +29,8 @@ from sources.models import SOURCE_UNCOMPRESS_CHOICE_Y, \ SOURCE_UNCOMPRESS_CHOICE_ASK from sources.staging import create_staging_file_class from sources.forms import StagingDocumentForm, WebFormForm +from sources.forms import WebFormSetupForm, StagingFolderSetupForm + def return_function(obj): return lambda context: context['source'].source_type == obj.source_type and context['source'].pk == obj.pk @@ -72,7 +74,7 @@ def upload_interactive(request, source_type=None, source_id=None): 'context': { 'title': _(u'Upload sources'), 'paragraphs': [ - _(u'Not document sources have been defined or there are no sources enabled.') + _(u'No interactive document sources have been defined or none have been enabled.') # TODO: Add link to setup ], } @@ -309,3 +311,135 @@ def staging_file_delete(request, source_type, source_id, staging_file_id): 'previous': previous, 'form_icon': u'delete.png', }, context_instance=RequestContext(request)) + + +def setup_source_list(request, source_type): + #check_permissions(request.user, [PERMISSION_SOURCES_SETUP_VIEW]) + + if source_type == SOURCE_CHOICE_WEB_FORM: + cls = WebForm + title = _(u'web form sources') + elif source_type == SOURCE_CHOICE_STAGING: + cls = StagingFolder + title = _(u'staging folder sources') + + context = { + 'object_list': cls.objects.all(), + 'title': title, + #'multi_select_as_buttons': True, + #'hide_links': True, + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def setup_source_edit(request, source_type, source_id): + #check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT]) + + if source_type == SOURCE_CHOICE_WEB_FORM: + cls = WebForm + form_class = WebFormSetupForm + title = _(u'edit web form source: %s') + elif source_type == SOURCE_CHOICE_STAGING: + cls = StagingFolder + form_class = StagingFolderSetupForm + title = _(u'edit staging folder source: %s') + + source = get_object_or_404(cls, pk=source_id) + next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/'))) + + if request.method == 'POST': + form = form_class(instance=source, data=request.POST) + if form.is_valid(): + try: + form.save() + messages.success(request, _(u'Source edited successfully')) + return HttpResponseRedirect(next) + except Exception, e: + messages.error(request, _(u'Error editing source; %s') % e) + else: + form = form_class(instance=source) + + return render_to_response('generic_form.html', { + 'title': title % source, + 'form': form, + 'object': source, + 'next': next, + 'object_name': _(u'source'), + }, + context_instance=RequestContext(request)) + + +def setup_source_delete(request, source_type, source_id): + #check_permissions(request.user, [PERMISSION_SOURCES_SETUP_DELETE]) + if source_type == SOURCE_CHOICE_WEB_FORM: + cls = WebForm + title = _(u'Are you sure you wish to delete the web form source: %s?') + form_icon = u'application_form_delete.png' + redirect_view = 'setup_web_form_list' + elif source_type == SOURCE_CHOICE_STAGING: + cls = StagingFolder + title = _(u'Are you sure you wish to delete the staging folder source: %s?') + form_icon = u'folder_delete.png' + redirect_view = 'setup_staging_folder_list' + + source = get_object_or_404(cls, pk=source_id) + + if request.method == 'POST': + try: + source.delete() + messages.success(request, _(u'Source "%s" deleted successfully.') % source) + except Exception, e: + messages.error(request, _(u'Error deleting source "%(source)s": %(error)s') % { + 'source': source, 'error': e + }) + + return HttpResponseRedirect(reverse(redirect_view)) + + context = { + 'title': title % source, + 'object': source, + 'object_name': _(u'source'), + 'delete_view': True, + 'previous': next, + 'next': next, + 'form_icon': form_icon, + } + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) + + +def setup_source_create(request, source_type): + #check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT]) + + if source_type == SOURCE_CHOICE_WEB_FORM: + #cls = WebForm + form_class = WebFormSetupForm + title = _(u'Creating web form source') + elif source_type == SOURCE_CHOICE_STAGING: + #cls = StagingFolder + form_class = StagingFolderSetupForm + title = _(u'Creating staging folder source') + + #source = get_object_or_404(cls, pk=source_id) + + if request.method == 'POST': + form = form_class(data=request.POST) + if form.is_valid(): + try: + form.save() + messages.success(request, _(u'Source created successfully')) + return HttpResponseRedirect(reverse('setup_web_form_list')) + except Exception, e: + messages.error(request, _(u'Error creating source; %s') % e) + else: + form = form_class() + + return render_to_response('generic_form.html', { + 'title': title, + 'form': form, + #'object_name': _(u'source'), + }, + context_instance=RequestContext(request)) From 79cc9dd9c8f49cfd6f03dc375ac59230a9391134 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 7 Jul 2011 00:59:05 -0400 Subject: [PATCH 09/47] Implemented child url regex highlight for regular links, improve the document duplicate list, improved staging file delete view --- apps/documents/__init__.py | 8 ++- apps/documents/forms.py | 7 +- apps/documents/literals.py | 6 +- apps/documents/views.py | 72 +++++-------------- apps/metadata/__init__.py | 2 +- .../templatetags/navigation_tags.py | 7 ++ apps/sources/__init__.py | 4 +- apps/sources/views.py | 51 +++++++------ 8 files changed, 67 insertions(+), 90 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 24ef2a7c59..35007412d7 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -38,6 +38,7 @@ register_permission(PERMISSION_DOCUMENT_TRANSFORM) register_permission(PERMISSION_DOCUMENT_TOOLS) # Document type permissions +set_namespace_title('documents_setup', _(u'Documents setup')) register_permission(PERMISSION_DOCUMENT_TYPE_EDIT) register_permission(PERMISSION_DOCUMENT_TYPE_DELETE) register_permission(PERMISSION_DOCUMENT_TYPE_CREATE) @@ -129,9 +130,12 @@ register_links(['document_type_filename_edit', 'document_type_filename_delete'], # Register document links register_links(Document, [document_edit, document_print, document_delete, document_download, document_find_duplicates, document_clear_transformations, document_create_siblings]) -register_multi_item_links(['folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [document_multiple_clear_transformations, document_multiple_delete]) +register_multi_item_links(['document_find_duplicates', 'folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [document_multiple_clear_transformations, document_multiple_delete]) -register_links(['document_list_recent', 'document_list', 'document_create', 'document_create_multiple', 'upload_interactive', 'document_find_duplicates'], [document_list_recent, document_list, document_create_multiple], menu_name='secondary_menu') +secondary_menu_links = [document_list_recent, document_list, document_create_multiple] + +register_links(['document_list_recent', 'document_list', 'document_create', 'document_create_multiple', 'upload_interactive', 'staging_file_delete'], secondary_menu_links, menu_name='secondary_menu') +#register_links(Document, secondary_menu_links, menu_name='sidebar') # Document page links register_links(DocumentPage, [ diff --git a/apps/documents/forms.py b/apps/documents/forms.py index 6963280e2f..650c677148 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -198,12 +198,7 @@ class DocumentForm_edit(DocumentForm): """ class Meta: model = Document - exclude = ('file', 'document_type', 'tags', 'expand') - - - def __init__(self, *args, **kwargs): - super(DocumentForm_edit, self).__init__(*args, **kwargs) - self.fields.pop('expand') + exclude = ('file', 'document_type', 'tags') class DocumentPropertiesForm(DetailForm): diff --git a/apps/documents/literals.py b/apps/documents/literals.py index b2c0f023c2..cbb3b919d9 100644 --- a/apps/documents/literals.py +++ b/apps/documents/literals.py @@ -14,9 +14,9 @@ PERMISSION_DOCUMENT_DOWNLOAD = {'namespace': 'documents', 'name': 'document_down PERMISSION_DOCUMENT_TRANSFORM = {'namespace': 'documents', 'name': 'document_transform', 'label': _(u'Transform documents')} PERMISSION_DOCUMENT_TOOLS = {'namespace': 'documents', 'name': 'document_tools', 'label': _(u'Execute document modifying tools')} -PERMISSION_DOCUMENT_TYPE_EDIT = {'namespace': 'documents', 'name': 'document_type_edit', 'label': _(u'Edit document types')} -PERMISSION_DOCUMENT_TYPE_DELETE = {'namespace': 'documents', 'name': 'document_type_delete', 'label': _(u'Delete document types')} -PERMISSION_DOCUMENT_TYPE_CREATE = {'namespace': 'documents', 'name': 'document_type_create', 'label': _(u'Create document types')} +PERMISSION_DOCUMENT_TYPE_EDIT = {'namespace': 'documents_setup', 'name': 'document_type_edit', 'label': _(u'Edit document types')} +PERMISSION_DOCUMENT_TYPE_DELETE = {'namespace': 'documents_setup', 'name': 'document_type_delete', 'label': _(u'Delete document types')} +PERMISSION_DOCUMENT_TYPE_CREATE = {'namespace': 'documents_setup', 'name': 'document_type_create', 'label': _(u'Create document types')} HISTORY_DOCUMENT_CREATED = { 'namespace': 'documents', 'name': 'document_created', diff --git a/apps/documents/views.py b/apps/documents/views.py index 817164c693..4a3247c576 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -375,58 +375,6 @@ def document_download(request, document_id): messages.error(request, e) return HttpResponseRedirect(request.META['HTTP_REFERER']) -''' -def staging_file_preview(request, source, staging_file_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) - StagingFile = create_staging_file_class(request, source) - try: - output_file, errors = StagingFile.get(staging_file_id).preview() - 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, staging_file_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) - StagingFile = create_staging_file_class(request, source) - - 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': source, - 'delete_view': True, - 'object': staging_file, - 'next': next, - 'previous': previous, - 'form_icon': u'drive_delete.png', - }, context_instance=RequestContext(request)) -''' def document_page_transformation_list(request, document_page_id): check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) @@ -519,10 +467,14 @@ def document_find_duplicates(request, document_id): check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) - return _find_duplicate_list(request, [document], include_source=True, confirmation=False) + extra_context = { + 'title': _(u'duplicates of: %s') % document, + 'object': document, + } + return _find_duplicate_list(request, [document], include_source=True, confirmation=False, extra_context=extra_context) -def _find_duplicate_list(request, source_document_list=Document.objects.all(), include_source=False, confirmation=True): +def _find_duplicate_list(request, source_document_list=Document.objects.all(), include_source=False, confirmation=True, extra_context=None): previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None))) if confirmation and request.method != 'POST': @@ -542,10 +494,18 @@ def _find_duplicate_list(request, source_document_list=Document.objects.all(), i if include_source and results: duplicated.append(document.pk) - return render_to_response('generic_list.html', { + context = { 'object_list': Document.objects.filter(pk__in=duplicated), 'title': _(u'duplicated documents'), - }, context_instance=RequestContext(request)) + 'hide_links': True, + 'multi_select_as_buttons': True, + } + + if extra_context: + context.update(extra_context) + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) def document_find_all_duplicates(request): diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index bf7629d985..1001dc1977 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -62,7 +62,7 @@ setup_document_type_metadata = {'text': _(u'default metadata'), 'view': 'setup_d #register_links(Document, [metadata_add, metadata_edit, metadata_remove]) register_links(['metadata_add', 'metadata_edit', 'metadata_remove', 'metadata_view'], [metadata_add, metadata_edit, metadata_remove], menu_name='sidebar') register_links(Document, [metadata_view], menu_name='form_header')#, metadata_edit, metadata_remove]) -register_multi_item_links(['folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [metadata_multiple_add, metadata_multiple_edit, metadata_multiple_remove]) +register_multi_item_links(['document_find_duplicates', 'folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [metadata_multiple_add, metadata_multiple_edit, metadata_multiple_remove]) register_links(MetadataType, [setup_metadata_type_edit, setup_metadata_type_delete]) register_links(['setup_metadata_type_delete', 'setup_metadata_type_edit', 'setup_metadata_type_list', 'setup_metadata_type_create'], [setup_metadata_type_create], menu_name='sidebar') diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index d4c73b781b..2d9034bb16 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -123,6 +123,13 @@ def resolve_links(context, links, current_view, current_path, parsed_query_strin new_link['disabled'] = link['conditional_disable'](context) else: new_link['disabled'] = False + + if current_view in link.get('children_views', []): + new_link['active'] = True + + for child_url_regex in link.get('children_url_regex', []): + if re.compile(child_url_regex).match(current_path.lstrip('/')): + new_link['active'] = True context_links.append(new_link) return context_links diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index 000e52a0ec..075f7fad31 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -8,7 +8,7 @@ from sources.staging import StagingFile from sources.models import WebForm, StagingFolder 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'} +staging_file_delete = {'text': _(u'delete'), 'view': 'staging_file_delete', 'args': ['source.source_type', 'source.pk', 'object.id'], 'famfam': 'delete', 'keep_query': True} setup_web_form_list = {'text': _(u'web forms'), 'view': 'setup_web_form_list', 'famfam': 'application_form'} setup_web_form_edit = {'text': _(u'edit'), 'view': 'setup_web_form_edit', 'args': 'object.pk', 'famfam': 'application_form_edit'} @@ -20,7 +20,7 @@ setup_staging_folder_edit = {'text': _(u'edit'), 'view': 'setup_staging_folder_e setup_staging_folder_delete = {'text': _(u'delete'), 'view': 'setup_staging_folder_delete', 'args': 'object.pk', 'famfam': 'folder_delete'} setup_staging_folder_create = {'text': _(u'add new'), 'view': 'setup_staging_folder_create', 'famfam': 'folder_add'} -source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'famfam': 'page_add'} +source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'famfam': 'page_add', 'children_url_regex': [r'sources/setup']} register_links(StagingFile, [staging_file_preview, staging_file_delete]) diff --git a/apps/sources/views.py b/apps/sources/views.py index 90468349cf..3c8940cd24 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -27,24 +27,18 @@ from sources.models import WebForm, StagingFolder from sources.models import SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING from sources.models import SOURCE_UNCOMPRESS_CHOICE_Y, \ SOURCE_UNCOMPRESS_CHOICE_ASK -from sources.staging import create_staging_file_class +from sources.staging import create_staging_file_class, StagingFile from sources.forms import StagingDocumentForm, WebFormForm from sources.forms import WebFormSetupForm, StagingFolderSetupForm def return_function(obj): return lambda context: context['source'].source_type == obj.source_type and context['source'].pk == obj.pk - -def upload_interactive(request, source_type=None, source_id=None): - check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) - - subtemplates_list = [] +def get_active_tab_links(): tab_links = [] - context = {} - web_forms = WebForm.objects.filter(enabled=True) for web_form in web_forms: tab_links.append({ @@ -66,8 +60,24 @@ def upload_interactive(request, source_type=None, source_id=None): 'keep_query': True, 'conditional_highlight': return_function(staging_folder), }) + + return { + 'tab_links': tab_links, + 'web_forms': web_forms, + 'staging_folders': staging_folders + } + - if web_forms.count() == 0 and staging_folders.count() == 0: +def upload_interactive(request, source_type=None, source_id=None): + check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) + + subtemplates_list = [] + + context = {} + + results = get_active_tab_links() + + if results['web_forms'].count() == 0 and results['staging_folders'].count() == 0: subtemplates_list.append( { 'name': 'generic_subtemplate.html', @@ -89,12 +99,12 @@ def upload_interactive(request, source_type=None, source_id=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 results['web_forms'].count(): + source_type = results['web_forms'][0].source_type + source_id = results['web_forms'][0].pk + elif results['staging_folders'].count(): + source_type = results['staging_folders'][0].source_type + source_id = results['staging_folders'][0].pk if source_type and source_id: if source_type == SOURCE_CHOICE_WEB_FORM: @@ -210,7 +220,7 @@ def upload_interactive(request, source_type=None, source_id=None): 'side_bar': True, } }], - 'temporary_navigation_links': {'form_header': {'upload_interactive': {'links': tab_links}}} + 'temporary_navigation_links': {'form_header': {'upload_interactive': {'links': results['tab_links']}}}, }) return render_to_response('generic_form.html', context, context_instance=RequestContext(request)) @@ -303,6 +313,8 @@ def staging_file_delete(request, source_type, source_id, staging_file_id): messages.error(request, e) return HttpResponseRedirect(next) + results = get_active_tab_links() + return render_to_response('generic_confirm.html', { 'source': staging_folder, 'delete_view': True, @@ -310,6 +322,7 @@ def staging_file_delete(request, source_type, source_id, staging_file_id): 'next': next, 'previous': previous, 'form_icon': u'delete.png', + 'temporary_navigation_links': {'form_header': {'staging_file_delete': {'links': results['tab_links']}}}, }, context_instance=RequestContext(request)) @@ -326,8 +339,7 @@ def setup_source_list(request, source_type): context = { 'object_list': cls.objects.all(), 'title': title, - #'multi_select_as_buttons': True, - #'hide_links': True, + 'hide_link': True, } return render_to_response('generic_list.html', context, @@ -402,8 +414,7 @@ def setup_source_delete(request, source_type, source_id): 'object': source, 'object_name': _(u'source'), 'delete_view': True, - 'previous': next, - 'next': next, + 'previous': reverse(redirect_view), 'form_icon': form_icon, } From 9f1ef7cfa988c0aee1b6334dd65153bb04b3421e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 8 Jul 2011 03:13:27 -0400 Subject: [PATCH 10/47] Updated the upload_interactive view to conserve an invalid form to display its error on the template --- apps/sources/views.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/sources/views.py b/apps/sources/views.py index 3c8940cd24..f5d906c0f5 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -135,8 +135,8 @@ def upload_interactive(request, source_type=None, source_id=None): messages.error(request, e) return HttpResponseRedirect(request.get_full_path()) - - form = WebFormForm(show_expand=(web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK), document_type=document_type) + else: + form = WebFormForm(show_expand=(web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK), document_type=document_type) subtemplates_list.append({ 'name': 'generic_form_subtemplate.html', @@ -179,11 +179,11 @@ def upload_interactive(request, source_type=None, source_id=None): messages.error(request, e) return HttpResponseRedirect(request.get_full_path()) - - form = StagingDocumentForm(cls=StagingFile, - document_type=document_type, - show_expand=(staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK) - ) + else: + form = StagingDocumentForm(cls=StagingFile, + document_type=document_type, + show_expand=(staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK) + ) try: staging_filelist = StagingFile.get_all() except Exception, e: From c41b38b9abfeb173152664ac0a21d92fc74e8290 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 8 Jul 2011 03:34:43 -0400 Subject: [PATCH 11/47] Added the new children_url_regex option to more link for consistent highlighting --- apps/sources/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index 075f7fad31..77cb2a0a63 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -10,12 +10,12 @@ from sources.models import WebForm, StagingFolder 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', 'keep_query': True} -setup_web_form_list = {'text': _(u'web forms'), 'view': 'setup_web_form_list', 'famfam': 'application_form'} +setup_web_form_list = {'text': _(u'web forms'), 'view': 'setup_web_form_list', 'famfam': 'application_form', 'children_url_regex': [r'sources/setup/interactive/webforms']} setup_web_form_edit = {'text': _(u'edit'), 'view': 'setup_web_form_edit', 'args': 'object.pk', 'famfam': 'application_form_edit'} setup_web_form_delete = {'text': _(u'delete'), 'view': 'setup_web_form_delete', 'args': 'object.pk', 'famfam': 'application_form_delete'} setup_web_form_create = {'text': _(u'add new'), 'view': 'setup_web_form_create', 'famfam': 'application_form_add'} -setup_staging_folder_list = {'text': _(u'staging folders'), 'view': 'setup_staging_folder_list', 'famfam': 'folder_magnify'} +setup_staging_folder_list = {'text': _(u'staging folders'), 'view': 'setup_staging_folder_list', 'famfam': 'folder_magnify', 'children_url_regex': [r'sources/setup/interactive/staging_folder']} setup_staging_folder_edit = {'text': _(u'edit'), 'view': 'setup_staging_folder_edit', 'args': 'object.pk', 'famfam': 'folder_edit'} setup_staging_folder_delete = {'text': _(u'delete'), 'view': 'setup_staging_folder_delete', 'args': 'object.pk', 'famfam': 'folder_delete'} setup_staging_folder_create = {'text': _(u'add new'), 'view': 'setup_staging_folder_create', 'famfam': 'folder_add'} From aae3f3c147e99cc72cfa0f0dcd1aed14bd52a41b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 8 Jul 2011 03:35:22 -0400 Subject: [PATCH 12/47] Added help texts to the source models and added 2 new icons --- apps/sources/models.py | 46 +++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/apps/sources/models.py b/apps/sources/models.py index 666ea7cc30..f36692d9ec 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -10,14 +10,14 @@ SOURCE_UNCOMPRESS_CHOICE_N = 'n' SOURCE_UNCOMPRESS_CHOICE_ASK = 'a' SOURCE_UNCOMPRESS_CHOICES = ( - (SOURCE_UNCOMPRESS_CHOICE_Y, _(u'Yes')), - (SOURCE_UNCOMPRESS_CHOICE_N, _(u'No')), + (SOURCE_UNCOMPRESS_CHOICE_Y, _(u'Always')), + (SOURCE_UNCOMPRESS_CHOICE_N, _(u'Never')), ) SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES = ( - (SOURCE_UNCOMPRESS_CHOICE_Y, _(u'Yes')), - (SOURCE_UNCOMPRESS_CHOICE_N, _(u'No')), - (SOURCE_UNCOMPRESS_CHOICE_ASK, _(u'Ask')) + (SOURCE_UNCOMPRESS_CHOICE_Y, _(u'Always')), + (SOURCE_UNCOMPRESS_CHOICE_N, _(u'Never')), + (SOURCE_UNCOMPRESS_CHOICE_ASK, _(u'Ask user')) ) SOURCE_ICON_DISK = 'disk' @@ -28,16 +28,20 @@ SOURCE_ICON_DRIVE_USER = 'drive_user' SOURCE_ICON_EMAIL = 'email' SOURCE_ICON_FOLDER = 'folder' SOURCE_ICON_WORLD = 'world' +SOURCE_ICON_PRINTER = 'printer' +SOURCE_ICON_PRINTER_EMPTY = 'printer_empty' SOURCE_ICON_CHOICES = ( - (SOURCE_ICON_DISK, _(u'disk')), - (SOURCE_ICON_DATABASE, _(u'database')), - (SOURCE_ICON_DRIVE, _(u'drive')), - (SOURCE_ICON_DRIVE_NETWORK, _(u'network drive')), - (SOURCE_ICON_DRIVE_USER, _(u'user drive')), - (SOURCE_ICON_EMAIL, _(u'envelope')), - (SOURCE_ICON_FOLDER, _(u'folder')), - (SOURCE_ICON_WORLD, _(u'world')) + (SOURCE_ICON_DISK, _(u'Disk')), + (SOURCE_ICON_DATABASE, _(u'Database')), + (SOURCE_ICON_DRIVE, _(u'Drive')), + (SOURCE_ICON_DRIVE_NETWORK, _(u'Network drive')), + (SOURCE_ICON_DRIVE_USER, _(u'User drive')), + (SOURCE_ICON_EMAIL, _(u'Envelope')), + (SOURCE_ICON_FOLDER, _(u'Folder')), + (SOURCE_ICON_WORLD, _(u'World')), + (SOURCE_ICON_PRINTER, _(u'Printer')), + (SOURCE_ICON_PRINTER_EMPTY, _(u'Empty printer')), ) SOURCE_CHOICE_WEB_FORM = 'webform' @@ -54,7 +58,7 @@ class BaseModel(models.Model): enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) whitelist = models.TextField(blank=True, verbose_name=_(u'whitelist')) blacklist = models.TextField(blank=True, verbose_name=_(u'blacklist')) - document_type = models.ForeignKey(DocumentType, blank=True, null=True, verbose_name=_(u'document type')) + document_type = models.ForeignKey(DocumentType, blank=True, null=True, verbose_name=_(u'document type'), help_text=(u'Optional document type to be applied to documents uploaded from this source.')) def __unicode__(self): return u'%s' % self.title @@ -65,7 +69,7 @@ class BaseModel(models.Model): class InteractiveBaseModel(BaseModel): - icon = models.CharField(blank=True, null=True, max_length=24, choices=SOURCE_ICON_CHOICES, verbose_name=_(u'icon')) + icon = models.CharField(blank=True, null=True, max_length=24, choices=SOURCE_ICON_CHOICES, verbose_name=_(u'icon'), help_text=_(u'An icon to visually distinguish this source.')) def save(self, *args, **kwargs): if not self.icon: @@ -81,11 +85,11 @@ class StagingFolder(InteractiveBaseModel): source_type = SOURCE_CHOICE_STAGING default_icon = SOURCE_ICON_DRIVE - folder_path = models.CharField(max_length=255, verbose_name=_(u'folder path')) - preview_width = models.IntegerField(verbose_name=_(u'preview width')) - preview_height = models.IntegerField(blank=True, null=True, verbose_name=_(u'preview height')) - 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')) + folder_path = models.CharField(max_length=255, verbose_name=_(u'folder path'), help_text=_(u'Server side filesystem path.')) + preview_width = models.IntegerField(blank=True, null=True, verbose_name=_(u'preview width'), help_text=_(u'Width value to be passed to the converter backend.')) + preview_height = models.IntegerField(blank=True, null=True, verbose_name=_(u'preview height'), help_text=_(u'Height value to be passed to the converter backend.')) + uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_(u'uncompress'), help_text=_(u'Whether to expand or not compressed archives.')) + delete_after_upload = models.BooleanField(default=True, verbose_name=_(u'delete after upload'), help_text=_(u'Delete the file after is has been successfully uploaded.')) def get_preview_size(self): dimensions = [] @@ -118,7 +122,7 @@ class WebForm(InteractiveBaseModel): source_type = SOURCE_CHOICE_WEB_FORM default_icon = SOURCE_ICON_DISK - uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_(u'uncompress')) + uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_(u'uncompress'), help_text=_(u'Whether to expand or not compressed archives.')) #Default path class Meta(InteractiveBaseModel.Meta): From a15d3afd075193877d88391de299dad618f574e8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 8 Jul 2011 03:35:54 -0400 Subject: [PATCH 13/47] Added a new famfam graphics radioselect widget and applied it to the webform and stagingform edit and create forms --- apps/sources/forms.py | 15 +++++++++++++++ apps/sources/widgets.py | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 apps/sources/widgets.py diff --git a/apps/sources/forms.py b/apps/sources/forms.py index b759c3259d..88fe8f01cd 100644 --- a/apps/sources/forms.py +++ b/apps/sources/forms.py @@ -5,6 +5,7 @@ from django.utils.translation import ugettext from documents.forms import DocumentForm from sources.models import WebForm, StagingFolder +from sources.widgets import FamFamRadioSelect class StagingDocumentForm(DocumentForm): @@ -53,10 +54,24 @@ class WebFormForm(DocumentForm): class WebFormSetupForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super(WebFormSetupForm, self).__init__(*args, **kwargs) + self.fields['icon'].widget = FamFamRadioSelect( + attrs=self.fields['icon'].widget.attrs, + choices=self.fields['icon'].widget.choices, + ) + class Meta: model = WebForm class StagingFolderSetupForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super(StagingFolderSetupForm, self).__init__(*args, **kwargs) + self.fields['icon'].widget = FamFamRadioSelect( + attrs=self.fields['icon'].widget.attrs, + choices=self.fields['icon'].widget.choices, + ) + class Meta: model = StagingFolder diff --git a/apps/sources/widgets.py b/apps/sources/widgets.py new file mode 100644 index 0000000000..01626a9b4b --- /dev/null +++ b/apps/sources/widgets.py @@ -0,0 +1,22 @@ +from django import forms +from django.utils.safestring import mark_safe +from django.utils.encoding import force_unicode + + +class FamFamRadioFieldRenderer(forms.widgets.RadioFieldRenderer): + def render(self): + results = [] + results.append(u'
    \n') + for w in self: + if w.choice_value: + famfam_template = u'' % w.choice_value + else: + famfam_template = u'' + results.append(u'
  • %s%s
  • ' % (famfam_template, force_unicode(w))) + + results.append(u'\n
') + return mark_safe(u'\n'.join(results)) + + +class FamFamRadioSelect(forms.widgets.RadioSelect): + renderer = FamFamRadioFieldRenderer From eef6400c22c72ba0e70f4deb111378cfb0ef3b54 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 8 Jul 2011 04:19:16 -0400 Subject: [PATCH 14/47] Initial whitelist/blacklist support --- apps/sources/forms.py | 10 ++++++++++ apps/sources/utils.py | 37 +++++++++++++++++++++++++++++++++++++ apps/sources/views.py | 15 +++++++++++---- 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 apps/sources/utils.py diff --git a/apps/sources/forms.py b/apps/sources/forms.py index 88fe8f01cd..f12ef25c96 100644 --- a/apps/sources/forms.py +++ b/apps/sources/forms.py @@ -6,6 +6,7 @@ from documents.forms import DocumentForm from sources.models import WebForm, StagingFolder from sources.widgets import FamFamRadioSelect +from sources.utils import validate_whitelist_blacklist class StagingDocumentForm(DocumentForm): @@ -16,6 +17,7 @@ class StagingDocumentForm(DocumentForm): def __init__(self, *args, **kwargs): cls = kwargs.pop('cls') show_expand = kwargs.pop('show_expand', False) + self.source = kwargs.pop('source') super(StagingDocumentForm, self).__init__(*args, **kwargs) try: self.fields['staging_file_id'].choices = [ @@ -44,13 +46,21 @@ class StagingDocumentForm(DocumentForm): class WebFormForm(DocumentForm): def __init__(self, *args, **kwargs): show_expand = kwargs.pop('show_expand', False) + self.source = kwargs.pop('source') super(WebFormForm, self).__init__(*args, **kwargs) + print self.instance if show_expand: self.fields['expand'] = forms.BooleanField( label=_(u'Expand compressed files'), required=False, help_text=ugettext(u'Upload a compressed file\'s contained files as individual documents') ) + + def clean_file(self): + data = self.cleaned_data['file'] + validate_whitelist_blacklist(data.name, self.source.whitelist.split(','), self.source.blacklist.split(',')) + + return data class WebFormSetupForm(forms.ModelForm): diff --git a/apps/sources/utils.py b/apps/sources/utils.py new file mode 100644 index 0000000000..574d81771f --- /dev/null +++ b/apps/sources/utils.py @@ -0,0 +1,37 @@ +import re + +from django.core.exceptions import ValidationError +from django.utils.translation import ugettext + +# From http://www.peterbe.com/plog/whitelist-blacklist-logic +def accept_item(value, whitelist, blacklist, default_accept=True): + """ return true if this item is either whitelisted or + not blacklisted """ + if not whitelist: + whitelist = [] + + if not blacklist: + blacklist = [] + + # note the order + for reject, item_list in ([False, whitelist], [True, blacklist]): + print 'item_list: %s' % item_list + print 'reject: %s' % reject + for okpattern in item_list: + print 'okpattern: %s' % okpattern + if re.findall(okpattern.replace('*','\S+'), value, re.I): + # match! + print 'MATCH' + if reject: + return False + else: + return True + + # default is to accept all + return default_accept + + +def validate_whitelist_blacklist(value, whitelist, blacklist): + print 'blacklist', blacklist + if not accept_item(value, whitelist, blacklist): + raise ValidationError(ugettext(u'Whitelist Blacklist validation error.')) diff --git a/apps/sources/views.py b/apps/sources/views.py index f5d906c0f5..accd288c7e 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -113,7 +113,8 @@ def upload_interactive(request, source_type=None, source_id=None): if request.method == 'POST': form = WebFormForm(request.POST, request.FILES, document_type=document_type, - show_expand=(web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK) + show_expand=(web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK), + source=web_form ) if form.is_valid(): try: @@ -136,7 +137,11 @@ def upload_interactive(request, source_type=None, source_id=None): return HttpResponseRedirect(request.get_full_path()) else: - form = WebFormForm(show_expand=(web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK), document_type=document_type) + form = WebFormForm( + show_expand=(web_form.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK), + document_type=document_type, + source=web_form + ) subtemplates_list.append({ 'name': 'generic_form_subtemplate.html', @@ -152,7 +157,8 @@ def upload_interactive(request, source_type=None, source_id=None): if request.method == 'POST': form = StagingDocumentForm(request.POST, request.FILES, cls=StagingFile, document_type=document_type, - show_expand=(staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK) + show_expand=(staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK), + source=staging_folder ) if form.is_valid(): try: @@ -182,7 +188,8 @@ def upload_interactive(request, source_type=None, source_id=None): else: form = StagingDocumentForm(cls=StagingFile, document_type=document_type, - show_expand=(staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK) + show_expand=(staging_folder.uncompress==SOURCE_UNCOMPRESS_CHOICE_ASK), + source=staging_folder ) try: staging_filelist = StagingFile.get_all() From 1e944c7130a13d4c48d1c5eb10ad1139b4239cc3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 8 Jul 2011 15:30:52 -0400 Subject: [PATCH 15/47] Initial commit of document source transformations --- apps/documents/conf/settings.py | 1 - apps/documents/models.py | 1 - apps/sources/admin.py | 4 +- apps/sources/forms.py | 11 +++- apps/sources/managers.py | 8 +++ apps/sources/models.py | 55 ++++++++++++++---- apps/sources/urls.py | 1 + apps/sources/views.py | 98 ++++++++++++++++++++++++++++++++- 8 files changed, 163 insertions(+), 16 deletions(-) create mode 100644 apps/sources/managers.py diff --git a/apps/documents/conf/settings.py b/apps/documents/conf/settings.py index 6a4907d985..7a253f52de 100644 --- a/apps/documents/conf/settings.py +++ b/apps/documents/conf/settings.py @@ -33,7 +33,6 @@ register_settings( {'name': u'STORAGE_BACKEND', 'global_name': u'DOCUMENTS_STORAGE_BACKEND', 'default': FileBasedStorage}, # Transformations {'name': u'AVAILABLE_TRANSFORMATIONS', 'global_name': u'DOCUMENTS_AVAILABLE_TRANSFORMATIONS', 'default': available_transformations}, - {'name': u'DEFAULT_TRANSFORMATIONS', 'global_name': u'DOCUMENTS_DEFAULT_TRANSFORMATIONS', 'default': []}, # Usage {'name': u'PREVIEW_SIZE', 'global_name': u'DOCUMENTS_PREVIEW_SIZE', 'default': u'640x480'}, {'name': u'PRINT_SIZE', 'global_name': u'DOCUMENTS_PRINT_SIZE', 'default': u'1400'}, diff --git a/apps/documents/models.py b/apps/documents/models.py index 39306893c0..96d988bfdb 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -18,7 +18,6 @@ from documents.conf.settings import CHECKSUM_FUNCTION from documents.conf.settings import UUID_FUNCTION from documents.conf.settings import STORAGE_BACKEND from documents.conf.settings import AVAILABLE_TRANSFORMATIONS -from documents.conf.settings import DEFAULT_TRANSFORMATIONS from documents.managers import RecentDocumentManager available_transformations = ([(name, data['label']) for name, data in AVAILABLE_TRANSFORMATIONS.items()]) diff --git a/apps/sources/admin.py b/apps/sources/admin.py index 3cbf7078fb..e0522e62ab 100644 --- a/apps/sources/admin.py +++ b/apps/sources/admin.py @@ -1,6 +1,8 @@ from django.contrib import admin -from sources.models import StagingFolder, WebForm +from sources.models import StagingFolder, WebForm, SourceTransformation + admin.site.register(StagingFolder) admin.site.register(WebForm) +admin.site.register(SourceTransformation) diff --git a/apps/sources/forms.py b/apps/sources/forms.py index f12ef25c96..6da2d7853f 100644 --- a/apps/sources/forms.py +++ b/apps/sources/forms.py @@ -4,7 +4,7 @@ from django.utils.translation import ugettext from documents.forms import DocumentForm -from sources.models import WebForm, StagingFolder +from sources.models import WebForm, StagingFolder, SourceTransformation from sources.widgets import FamFamRadioSelect from sources.utils import validate_whitelist_blacklist @@ -85,3 +85,12 @@ class StagingFolderSetupForm(forms.ModelForm): class Meta: model = StagingFolder + + +class SourceTransformationForm(forms.ModelForm): + class Meta: + model = SourceTransformation + + #def __init__(self, *args, **kwargs): + # super(SourceTransformationForm, self).__init__(*args, **kwargs) + # self.fields['document_page'].widget = forms.HiddenInput() diff --git a/apps/sources/managers.py b/apps/sources/managers.py new file mode 100644 index 0000000000..aee45cf4c1 --- /dev/null +++ b/apps/sources/managers.py @@ -0,0 +1,8 @@ +from django.db import models +from django.contrib.contenttypes.models import ContentType + + +class SourceTransformationManager(models.Manager): + def get_for_object(self, obj): + ct = ContentType.objects.get_for_model(obj) + return self.model.objects.filter(content_type=ct).filter(object_id=obj.pk) diff --git a/apps/sources/models.py b/apps/sources/models.py index f36692d9ec..82598a290b 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -1,9 +1,16 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from django.contrib.contenttypes.models import ContentType +from django.contrib.contenttypes import generic from documents.models import DocumentType +from documents.conf.settings import AVAILABLE_TRANSFORMATIONS +from documents.managers import RecentDocumentManager from metadata.models import MetadataType +from sources.managers import SourceTransformationManager + +available_transformations = ([(name, data['label']) for name, data in AVAILABLE_TRANSFORMATIONS.items()]) SOURCE_UNCOMPRESS_CHOICE_Y = 'y' SOURCE_UNCOMPRESS_CHOICE_N = 'n' @@ -103,19 +110,21 @@ class StagingFolder(InteractiveBaseModel): verbose_name = _(u'staging folder') verbose_name_plural = _(u'staging folder') +''' +class SourceMetadata(models.Model): + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey('content_type', 'object_id') + metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) + value = models.CharField(max_length=256, blank=True, verbose_name=_(u'value')) -#class StagingFolderMetadataValue(models.Model): -# source = models.ForeignKey(BaseModel, verbose_name=_(u'document source')) -# metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) -# value = models.CharField(max_length=256, blank=True, verbose_name=_(u'value')) -# -# def __unicode__(self): -# return self.source -# -# class Meta: -# verbose_name = _(u'source metadata') -# verbose_name_plural = _(u'sources metadata') + def __unicode__(self): + return self.source + class Meta: + verbose_name = _(u'source metadata') + verbose_name_plural = _(u'sources metadata') +''' class WebForm(InteractiveBaseModel): is_interactive = True @@ -128,3 +137,27 @@ class WebForm(InteractiveBaseModel): class Meta(InteractiveBaseModel.Meta): verbose_name = _(u'web form') verbose_name_plural = _(u'web forms') + + +class SourceTransformation(models.Model): + """ + Model that stores the transformation and transformation arguments + for a given document source + """ + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey('content_type', 'object_id') + order = models.PositiveIntegerField(default=0, blank=True, null=True, verbose_name=_(u'order'), db_index=True) + transformation = models.CharField(choices=available_transformations, max_length=128, verbose_name=_(u'transformation')) + arguments = models.TextField(blank=True, null=True, verbose_name=_(u'arguments'), help_text=_(u'Use dictionaries to indentify arguments, example: {\'degrees\':90}')) + + objects = SourceTransformationManager() + + def __unicode__(self): + #return u'"%s" for %s' % (self.get_transformation_display(), unicode(self.content_object)) + return self.get_transformation_display() + + class Meta: + ordering = ('order',) + verbose_name = _(u'document source transformation') + verbose_name_plural = _(u'document source transformations') diff --git a/apps/sources/urls.py b/apps/sources/urls.py index c4f2fcd0d7..f8a9794684 100644 --- a/apps/sources/urls.py +++ b/apps/sources/urls.py @@ -15,6 +15,7 @@ urlpatterns = patterns('sources.views', url(r'^setup/interactive/webforms/(?P\w+)/edit/$', 'setup_source_edit', {'source_type': SOURCE_CHOICE_WEB_FORM}, 'setup_web_form_edit'), url(r'^setup/interactive/webforms/(?P\w+)/delete/$', 'setup_source_delete', {'source_type': SOURCE_CHOICE_WEB_FORM}, 'setup_web_form_delete'), url(r'^setup/interactive/webforms/create/$', 'setup_source_create', {'source_type': SOURCE_CHOICE_WEB_FORM}, 'setup_web_form_create'), + url(r'^setup/interactive/webforms/(?P\w+)/transformation/list/$', 'setup_source_transformation_list', {'source_type': SOURCE_CHOICE_WEB_FORM}, 'setup_web_form_transformation_list'), url(r'^setup/interactive/staging_folder/list/$', 'setup_source_list', {'source_type': SOURCE_CHOICE_STAGING}, 'setup_staging_folder_list'), url(r'^setup/interactive/staging_folder/(?P\w+)/edit/$', 'setup_source_edit', {'source_type': SOURCE_CHOICE_STAGING}, 'setup_staging_folder_edit'), diff --git a/apps/sources/views.py b/apps/sources/views.py index accd288c7e..a2cf68b0d6 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -23,13 +23,14 @@ from metadata.api import save_metadata_list, \ from permissions.api import check_permissions import sendfile -from sources.models import WebForm, StagingFolder +from sources.models import WebForm, StagingFolder, SourceTransformation from sources.models import SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING from sources.models import SOURCE_UNCOMPRESS_CHOICE_Y, \ SOURCE_UNCOMPRESS_CHOICE_ASK from sources.staging import create_staging_file_class, StagingFile from sources.forms import StagingDocumentForm, WebFormForm from sources.forms import WebFormSetupForm, StagingFolderSetupForm +from sources.forms import SourceTransformationForm def return_function(obj): @@ -461,3 +462,98 @@ def setup_source_create(request, source_type): #'object_name': _(u'source'), }, context_instance=RequestContext(request)) + + +def setup_source_transformation_list(request, source_type, source_id): + #check_permissions(request.user, [PERMISSION_SOURCES_SETUP_VIEW]) + + if source_type == SOURCE_CHOICE_WEB_FORM: + cls = WebForm + #title = _(u'web form sources') + elif source_type == SOURCE_CHOICE_STAGING: + cls = StagingFolder + #title = _(u'staging folder sources') + + source = get_object_or_404(cls, pk=source_id) + + context = { + 'object_list': SourceTransformation.objects.get_for_object(source), + 'title': _(u'default transformations for: %s') % source, + 'object': source, + 'extra_columns': [ + {'name': _(u'order'), 'attribute': 'order'}, + {'name': _(u'transformation'), 'attribute': lambda x: x.get_transformation_display()}, + {'name': _(u'arguments'), 'attribute': 'arguments'} + ], + 'hide_link': True, + 'hide_object': True, + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def setup_source_transformation_edit(request, source_transformation_id): + #check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + + source_transformation = get_object_or_404(SourceTransformation, pk=source_transformation_id) + return update_object(request, template_name='generic_form.html', + form_class=DocumentPageTransformationForm, + object_id=document_page_transformation_id, + post_save_redirect=reverse('document_page_view', args=[document_page_transformation.document_page_id]), + extra_context={ + 'object_name': _(u'transformation'), + 'title': _(u'Edit transformation "%(transformation)s" for: %(document_page)s') % { + 'transformation': document_page_transformation.get_transformation_display(), + 'document_page': document_page_transformation.document_page}, + 'web_theme_hide_menus': True, + } + ) +''' +def document_page_transformation_create(request, document_page_id): + check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + + document_page = get_object_or_404(DocumentPage, pk=document_page_id) + + if request.method == 'POST': + form = DocumentPageTransformationForm(request.POST, initial={'document_page': document_page}) + if form.is_valid(): + form.save() + return HttpResponseRedirect(reverse('document_page_view', args=[document_page_id])) + else: + form = DocumentPageTransformationForm(initial={'document_page': document_page}) + + return render_to_response('generic_form.html', { + 'form': form, + 'object': document_page, + 'title': _(u'Create new transformation for page: %(page)s of document: %(document)s') % { + 'page': document_page.page_number, 'document': document_page.document}, + 'web_theme_hide_menus': True, + }, context_instance=RequestContext(request)) + + + + + +def document_page_transformation_delete(request, document_page_transformation_id): + check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None))) + + document_page_transformation = get_object_or_404(DocumentPageTransformation, pk=document_page_transformation_id) + + return delete_object(request, model=DocumentPageTransformation, object_id=document_page_transformation_id, + template_name='generic_confirm.html', + post_delete_redirect=reverse('document_page_view', args=[document_page_transformation.document_page_id]), + extra_context={ + 'delete_view': True, + 'object': document_page_transformation, + 'object_name': _(u'document transformation'), + 'title': _(u'Are you sure you wish to delete transformation "%(transformation)s" for: %(document_page)s') % { + 'transformation': document_page_transformation.get_transformation_display(), + 'document_page': document_page_transformation.document_page}, + 'previous': previous, + 'web_theme_hide_menus': True, + 'form_icon': u'pencil_delete.png', + }) +''' From ee46653578738b7cdfb2da54799c0271068ebd81 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 9 Jul 2011 04:31:08 -0400 Subject: [PATCH 16/47] Added support for handling navigation for view with more than one main object class --- .../templates/generic_list_subtemplate.html | 7 +- apps/common/templatetags/variable_tags.py | 42 ++++++ apps/main/templates/base.html | 120 +++++++++++++----- .../templatetags/navigation_tags.py | 35 +++-- 4 files changed, 157 insertions(+), 47 deletions(-) create mode 100644 apps/common/templatetags/variable_tags.py diff --git a/apps/common/templates/generic_list_subtemplate.html b/apps/common/templates/generic_list_subtemplate.html index 2ac52b2dd7..29213c1d97 100644 --- a/apps/common/templates/generic_list_subtemplate.html +++ b/apps/common/templates/generic_list_subtemplate.html @@ -3,6 +3,7 @@ {% load pagination_tags %} {% load navigation_tags %} {% load non_breakable %} +{% load variable_tags %} {% if side_bar %}
@@ -122,13 +123,17 @@ {% endif %} {% endfor %} {% if not hide_links %} + {% if list_object_variable_name %} + {% copy_variable object as list_object_variable_name %} + {% copy_variable list_object_variable_name as "navigation_object_name" %} + {% endif %} {% if navigation_object_links %} {% with navigation_object_links as overrided_object_links %} {% object_navigation_template %} {% endwith %} {% else %} - {% object_navigation_template %} + {% object_navigation_template %} {% endif %} {% endif %} diff --git a/apps/common/templatetags/variable_tags.py b/apps/common/templatetags/variable_tags.py new file mode 100644 index 0000000000..b483834c3a --- /dev/null +++ b/apps/common/templatetags/variable_tags.py @@ -0,0 +1,42 @@ +import re + +from django.template import Node, TemplateSyntaxError, Library, Variable + +register = Library() + + +class CopyNode(Node): + def __init__(self, source_variable, var_name, delete_old=False): + self.source_variable = source_variable + self.var_name = var_name + self.delete_old = delete_old + + def render(self, context): + context[Variable(self.var_name).resolve(context)] = Variable(self.source_variable).resolve(context) + if self.delete_old: + context[Variable(self.source_variable).resolve(context)] = u'' + return '' + + +@register.tag +def copy_variable(parser, token): + return parse_tag(parser, token) + + +@register.tag +def rename_variable(parser, token): + return parse_tag(parser, token, {'delete_old': True}) + + +def parse_tag(parser, token, *args, **kwargs): + # This version uses a regular expression to parse tag contents. + try: + # Splitting by None == splitting by spaces. + tag_name, arg = token.contents.split(None, 1) + except ValueError: + raise TemplateSyntaxError('%r tag requires arguments' % token.contents.split()[0]) + m = re.search(r'(.*?) as ([\'"]*\w+[\'"]*)', arg) + if not m: + raise TemplateSyntaxError('%r tag had invalid arguments' % tag_name) + source_variable, var_name = m.groups() + return CopyNode(source_variable, var_name, *args, **kwargs) diff --git a/apps/main/templates/base.html b/apps/main/templates/base.html index deb49781c8..5c2c4ca43a 100644 --- a/apps/main/templates/base.html +++ b/apps/main/templates/base.html @@ -5,6 +5,8 @@ {% load settings %} {% load search_tags %} {% load main_settings_tags %} +{% load variable_tags %} + {% block web_theme_head %} {% if new_window_url %}