diff --git a/mayan/apps/file_metadata/admin.py b/mayan/apps/file_metadata/admin.py index c563ce4c47..056143ec82 100644 --- a/mayan/apps/file_metadata/admin.py +++ b/mayan/apps/file_metadata/admin.py @@ -1,13 +1,15 @@ from __future__ import unicode_literals from django.contrib import admin +from django.utils.translation import ugettext_lazy as _ from .models import StoredDriver @admin.register(StoredDriver) class StoredDriverAdmin(admin.ModelAdmin): - list_display = ('internal_name', 'label', 'driver_path') + list_display = ('internal_name', 'get_label', 'driver_path') - def label(self, instance): + def get_label(self, instance): return instance.driver_label + get_label.short_description = _('Label') diff --git a/mayan/apps/file_metadata/apps.py b/mayan/apps/file_metadata/apps.py index 9a42d789a3..b66244c28c 100644 --- a/mayan/apps/file_metadata/apps.py +++ b/mayan/apps/file_metadata/apps.py @@ -121,6 +121,9 @@ class FileMetadataApp(MayanAppConfig): ModelPermission.register_inheritance( model=DocumentTypeSettings, related='document_type', ) + ModelPermission.register_inheritance( + model=DocumentVersionDriverEntry, related='document_version', + ) SourceColumn(attribute='key', source=FileMetadataEntry) SourceColumn(attribute='value', source=FileMetadataEntry) diff --git a/mayan/apps/file_metadata/classes.py b/mayan/apps/file_metadata/classes.py index 656ab11966..e1a789c812 100644 --- a/mayan/apps/file_metadata/classes.py +++ b/mayan/apps/file_metadata/classes.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import logging from django.apps import apps +from django.db import transaction from .events import event_file_metadata_document_version_finish from .exceptions import FileMetadataDriverError @@ -14,35 +15,36 @@ logger = logging.getLogger(__name__) class FileMetadataDriver(object): _registry = {} - @classmethod - def register(cls, mimetypes): - for mimetype in mimetypes: - cls._registry.setdefault(mimetype, []).append(cls) - @classmethod def process_document_version(cls, document_version): for driver_class in cls._registry.get(document_version.mimetype, ()): try: driver = driver_class() - driver.process(document_version=document_version) + + with transaction.atomic(): + driver.process(document_version=document_version) + event_file_metadata_document_version_finish.commit( + action_object=document_version.document, + target=document_version + ) + + post_document_version_file_metadata_processing.send( + sender=document_version.__class__, + instance=document_version + ) except FileMetadataDriverError: # If driver raises error, try next in the list pass else: # If driver was successfull there is no need to try # others in the list for this mimetype - - event_file_metadata_document_version_finish.commit( - action_object=document_version.document, - target=document_version - ) - - post_document_version_file_metadata_processing.send( - sender=document_version.__class__, - instance=document_version - ) return + @classmethod + def register(cls, mimetypes): + for mimetype in mimetypes: + cls._registry.setdefault(mimetype, []).append(cls) + def process(self, document_version): logger.info( 'Starting processing document version: %s', document_version @@ -68,7 +70,9 @@ class FileMetadataDriver(object): document_version=document_version ) - for key, value in self._process(document_version=document_version).items(): + results = self._process(document_version=document_version) or {} + + for key, value in results.items(): document_version_driver_entry.entries.create( key=key, value=value ) diff --git a/mayan/apps/file_metadata/drivers/exiftool.py b/mayan/apps/file_metadata/drivers/exiftool.py index 9b60e0c1cc..6c83f20ee4 100644 --- a/mayan/apps/file_metadata/drivers/exiftool.py +++ b/mayan/apps/file_metadata/drivers/exiftool.py @@ -30,14 +30,20 @@ class EXIFToolDriver(FileMetadataDriver): self.command_exiftool = self.command_exiftool.bake('-j') def _process(self, document_version): - new_file_object, temp_filename = mkstemp() + if self.command_exiftool: + new_file_object, temp_filename = mkstemp() - try: - document_version.save_to_file(filepath=temp_filename) - result = self.command_exiftool(temp_filename) - return json.loads(s=result.stdout)[0] - finally: - fs_cleanup(filename=temp_filename) + try: + document_version.save_to_file(filepath=temp_filename) + result = self.command_exiftool(temp_filename) + return json.loads(s=result.stdout)[0] + finally: + fs_cleanup(filename=temp_filename) + else: + logger.warning( + 'EXIFTool binary not found, not processing document version: %s', + document_version + ) EXIFToolDriver.register( diff --git a/mayan/apps/file_metadata/exceptions.py b/mayan/apps/file_metadata/exceptions.py index 1f80c50b0d..a778a2313d 100644 --- a/mayan/apps/file_metadata/exceptions.py +++ b/mayan/apps/file_metadata/exceptions.py @@ -1,5 +1,9 @@ from __future__ import unicode_literals -class FileMetadataDriverError(Exception): +class FileMetadataError(Exception): """Base file metadata driver exception""" + + +class FileMetadataDriverError(FileMetadataError): + """Exception raised when a driver encounters an unexpected error""" diff --git a/mayan/apps/file_metadata/handlers.py b/mayan/apps/file_metadata/handlers.py index 01a95417e2..84d304f975 100644 --- a/mayan/apps/file_metadata/handlers.py +++ b/mayan/apps/file_metadata/handlers.py @@ -12,7 +12,7 @@ def handler_initialize_new_document_type_settings(sender, instance, **kwargs): if kwargs['created']: DocumentTypeSettings.objects.create( - document_type=instance, auto_process=setting_auto_process.value + auto_process=setting_auto_process.value, document_type=instance ) diff --git a/mayan/apps/file_metadata/tests/test_views.py b/mayan/apps/file_metadata/tests/test_views.py index 5971bf657c..d2dbe87add 100644 --- a/mayan/apps/file_metadata/tests/test_views.py +++ b/mayan/apps/file_metadata/tests/test_views.py @@ -14,10 +14,6 @@ from .literals import TEST_FILE_METADATA_KEY @override_settings(FILE_METADATA_AUTO_PROCESS=True) class FileMetadataViewsTestCase(GenericDocumentViewTestCase): - def setUp(self): - super(FileMetadataViewsTestCase, self).setUp() - self.login_user() - def _request_document_version_driver_list_view(self): return self.get( viewname='file_metadata:document_driver_list', @@ -26,7 +22,7 @@ class FileMetadataViewsTestCase(GenericDocumentViewTestCase): def test_document_version_driver_list_view_no_permission(self): response = self._request_document_version_driver_list_view() - self.assertEqual(response.status_code, 403) + self.assertEqual(response.status_code, 404) def test_document_version_driver_list_view_with_access(self): self.grant_access( @@ -46,12 +42,12 @@ class FileMetadataViewsTestCase(GenericDocumentViewTestCase): def test_document_version_file_metadata_list_view_no_permission(self): response = self._request_document_version_file_metadata_list_view() self.assertNotContains( - response=response, text=TEST_FILE_METADATA_KEY, status_code=403 + response=response, text=TEST_FILE_METADATA_KEY, status_code=404 ) def test_document_version_file_metadata_list_view_with_access(self): self.grant_access( - permission=permission_file_metadata_view, obj=self.document + obj=self.document, permission=permission_file_metadata_view ) response = self._request_document_version_file_metadata_list_view() self.assertContains( @@ -67,7 +63,7 @@ class FileMetadataViewsTestCase(GenericDocumentViewTestCase): def test_document_submit_view_no_permission(self): self.document.latest_version.file_metadata_drivers.all().delete() response = self._request_document_submit_view() - self.assertEqual(response.status_code, 302) + self.assertEqual(response.status_code, 404) self.assertEqual( self.document.latest_version.file_metadata_drivers.count(), 0 ) @@ -94,7 +90,7 @@ class FileMetadataViewsTestCase(GenericDocumentViewTestCase): def test_multiple_document_submit_view_no_permission(self): self.document.latest_version.file_metadata_drivers.all().delete() response = self._request_multiple_document_submit_view() - self.assertEqual(response.status_code, 302) + self.assertEqual(response.status_code, 404) self.assertEqual( self.document.latest_version.file_metadata_drivers.count(), 0 ) @@ -124,7 +120,7 @@ class DocumentTypeViewsTestCase(GenericDocumentViewTestCase): def test_document_type_settings_view_no_permission(self): response = self._request_document_type_settings_view() - self.assertEqual(response.status_code, 403) + self.assertEqual(response.status_code, 404) def test_document_type_settings_view_with_access(self): self.grant_access( diff --git a/mayan/apps/file_metadata/views.py b/mayan/apps/file_metadata/views.py index 7afdf6ee65..879ad5ba34 100644 --- a/mayan/apps/file_metadata/views.py +++ b/mayan/apps/file_metadata/views.py @@ -12,6 +12,7 @@ from mayan.apps.common.generics import ( FormView, MultipleObjectConfirmActionView, SingleObjectEditView, SingleObjectListView ) +from mayan.apps.common.mixins import ExternalObjectMixin from mayan.apps.documents.forms import DocumentTypeFilteredSelectForm from mayan.apps.documents.models import Document, DocumentType @@ -23,7 +24,11 @@ from .permissions import ( ) -class DocumentDriverListView(SingleObjectListView): +class DocumentDriverListView(ExternalObjectMixin, SingleObjectListView): + external_object_class = Document + external_object_permission = permission_file_metadata_view + external_object_pk_url_kwarg = 'document_id' + def get_extra_context(self): return { 'hide_object': True, @@ -38,54 +43,36 @@ class DocumentDriverListView(SingleObjectListView): 'reside in the database.' ), 'no_results_title': _('No file metadata available.'), - 'object': self.get_object(), + 'object': self.external_object, 'title': _( 'File metadata drivers for: %s' - ) % self.get_object(), + ) % self.external_object, } - def get_object(self): - document = get_object_or_404( - klass=Document, pk=self.kwargs['document_id'] - ) - AccessControlList.objects.check_access( - permissions=permission_file_metadata_view, - user=self.request.user, obj=document - ) - return document - def get_source_queryset(self): - return self.get_object().latest_version.file_metadata_drivers.all() + return self.external_object.latest_version.file_metadata_drivers.all() -class DocumentVersionDriverEntryFileMetadataListView(SingleObjectListView): +class DocumentVersionDriverEntryFileMetadataListView(ExternalObjectMixin, SingleObjectListView): + external_object_class = DocumentVersionDriverEntry + external_object_permission = permission_file_metadata_view + external_object_pk_url_kwarg = 'document_version_driver_id' + def get_extra_context(self): return { 'hide_object': True, 'no_results_title': _('No file metadata available.'), - 'object': self.get_object().document_version.document, + 'object': self.external_object.document_version.document, 'title': _( 'File metadata attribures for: %(document)s, for driver: %(driver)s' ) % { - 'document': self.get_object().document_version.document, - 'driver': self.get_object().driver + 'document': self.external_object.document_version.document, + 'driver': self.external_object.driver }, } - def get_object(self): - document_version_driver_entry = get_object_or_404( - klass=DocumentVersionDriverEntry, - pk=self.kwargs['document_version_driver_id'] - ) - AccessControlList.objects.check_access( - obj=document_version_driver_entry.document_version, - permissions=permission_file_metadata_view, - user=self.request.user, - ) - return document_version_driver_entry - def get_source_queryset(self): - return self.get_object().entries.all() + return self.external_object.entries.all() class DocumentSubmitView(MultipleObjectConfirmActionView): @@ -96,13 +83,13 @@ class DocumentSubmitView(MultipleObjectConfirmActionView): success_message_plural = '%(count)d documents submitted to the file metadata queue.' def get_extra_context(self): - queryset = self.get_queryset() + queryset = self.get_object_list() result = { 'title': ungettext( - 'Submit the selected document to the file metadata queue?', - 'Submit the selected documents to the file metadata queue?', - queryset.count() + singular='Submit the selected document to the file metadata queue?', + plural='Submit the selected documents to the file metadata queue?', + number=queryset.count() ) } @@ -112,26 +99,23 @@ class DocumentSubmitView(MultipleObjectConfirmActionView): instance.submit_for_file_metadata_processing() -class DocumentTypeSettingsEditView(SingleObjectEditView): +class DocumentTypeSettingsEditView(ExternalObjectMixin, SingleObjectEditView): + external_object_class = DocumentType + external_object_permission = permission_document_type_file_metadata_setup + external_object_pk_url_kwarg = 'document_type_id' fields = ('auto_process',) - object_permission = permission_document_type_file_metadata_setup post_action_redirect = reverse_lazy(viewname='documents:document_type_list') - def get_document_type(self): - return get_object_or_404( - klass=DocumentType, pk=self.kwargs['document_type_id'] - ) - def get_extra_context(self): return { - 'object': self.get_document_type(), + 'object': self.external_object, 'title': _( 'Edit file metadata settings for document type: %s' - ) % self.get_document_type() + ) % self.external_object } def get_object(self, queryset=None): - return self.get_document_type().file_metadata_settings + return self.external_object.file_metadata_settings class DocumentTypeSubmitView(FormView):