Refactor file metadata app
Add translatable label to the label admin method. Add access association from DocumentVersionDriverEntry to document version. Enclose process method and event commit in a transaction. Update process method to not error out if EXIF tool is not found. Update views and tests to use ExternalObjectMixin and comply with MERCs 5 and 6. Signed-off-by: Roberto Rosario <Roberto.Rosario.Gonzalez@gmail.com>
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user