diff --git a/mayan/apps/common/views.py b/mayan/apps/common/views.py index 89030ee068..25dab758e7 100644 --- a/mayan/apps/common/views.py +++ b/mayan/apps/common/views.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -from json import dumps, loads +from json import dumps from django.conf import settings from django.contrib import messages diff --git a/mayan/apps/converter/backends/python.py b/mayan/apps/converter/backends/python.py index 5c5069ef61..9f8173bc83 100644 --- a/mayan/apps/converter/backends/python.py +++ b/mayan/apps/converter/backends/python.py @@ -56,7 +56,10 @@ class Python(ConverterBase): image_buffer = io.BytesIO() try: - pdftoppm(input_filepath, f=self.page_number + 1, l=self.page_number + 1, _out=image_buffer) + pdftoppm( + input_filepath, f=self.page_number + 1, + l=self.page_number + 1, _out=image_buffer + ) image_buffer.seek(0) return Image.open(image_buffer) finally: diff --git a/mayan/apps/converter/managers.py b/mayan/apps/converter/managers.py index 3b942b20db..c01a0e8f3a 100644 --- a/mayan/apps/converter/managers.py +++ b/mayan/apps/converter/managers.py @@ -86,7 +86,8 @@ class TransformationManager(models.Manager): ) except Exception as exception: logger.error( - 'Error while parsing transformation "%s", arguments "%s", for object "%s"; %s', + 'Error while parsing transformation "%s", ' + 'arguments "%s", for object "%s"; %s', transformation, transformation.arguments, obj, exception ) diff --git a/mayan/apps/django_gpg/api.py b/mayan/apps/django_gpg/api.py index b2fd04625d..7a388e607b 100644 --- a/mayan/apps/django_gpg/api.py +++ b/mayan/apps/django_gpg/api.py @@ -96,7 +96,9 @@ class Key(object): return ', '.join(self.uids) def __str__(self): - return '%s "%s" (%s)' % (self.key_id, self.user_ids, KEY_TYPES.get(self.type, _('Unknown'))) + return '%s "%s" (%s)' % ( + self.key_id, self.user_ids, KEY_TYPES.get(self.type, _('Unknown')) + ) def __unicode__(self): return unicode(self.__str__()) @@ -133,9 +135,13 @@ class GPG(object): try: self.gpg = gnupg.GPG(**kwargs) except OSError as exception: - raise GPGException('ERROR: GPG initialization error; Make sure the GPG binary is properly installed; %s' % exception) + raise GPGException( + 'ERROR: GPG initialization error; Make sure the GPG binary is properly installed; %s' % exception + ) except Exception as exception: - raise GPGException('ERROR: GPG initialization error; %s' % exception) + raise GPGException( + 'ERROR: GPG initialization error; %s' % exception + ) def verify_file(self, file_input, detached_signature=None, fetch_key=False): """ @@ -155,7 +161,9 @@ class GPG(object): signature_file = StringIO() signature_file.write(detached_signature.read()) signature_file.seek(0) - verify = self.gpg.verify_file(signature_file, data_filename=filename) + verify = self.gpg.verify_file( + signature_file, data_filename=filename + ) signature_file.close() else: verify = self.gpg.verify_file(input_descriptor) @@ -169,7 +177,9 @@ class GPG(object): if fetch_key: try: self.receive_key(verify.key_id) - return self.verify_file(input_descriptor, detached_signature, fetch_key=False) + return self.verify_file( + input_descriptor, detached_signature, fetch_key=False + ) except KeyFetchingError: return verify else: @@ -259,7 +269,9 @@ class GPG(object): return Key.get(self, key.fingerprint) def delete_key(self, key): - status = self.gpg.delete_keys(key.fingerprint, key.type == 'sec').status + status = self.gpg.delete_keys( + key.fingerprint, key.type == 'sec' + ).status if status == 'Must delete secret key first': self.delete_key(Key.get(self, key.fingerprint, secret=True)) self.delete_key(key) @@ -270,7 +282,9 @@ class GPG(object): for keyserver in self.keyservers: import_result = self.gpg.recv_keys(keyserver, key_id) if import_result: - return Key.get(self, import_result.fingerprints[0], secret=False) + return Key.get( + self, import_result.fingerprints[0], secret=False + ) raise KeyFetchingError diff --git a/mayan/apps/django_gpg/apps.py b/mayan/apps/django_gpg/apps.py index 5fa4499be0..4a3c4f4c9f 100644 --- a/mayan/apps/django_gpg/apps.py +++ b/mayan/apps/django_gpg/apps.py @@ -22,4 +22,10 @@ class DjangoGPGApp(MayanAppConfig): menu_object.bind_links(links=[link_key_delete], sources=[Key]) menu_object.bind_links(links=[link_key_receive], sources=[KeyStub]) menu_setup.bind_links(links=[link_key_setup]) - menu_sidebar.bind_links(links=[link_public_keys, link_key_query], sources=['django_gpg:key_delete', 'django_gpg:key_public_list', 'django_gpg:key_query']) + menu_sidebar.bind_links( + links=[link_public_keys, link_key_query], + sources=[ + 'django_gpg:key_delete', 'django_gpg:key_public_list', + 'django_gpg:key_query' + ] + ) diff --git a/mayan/apps/django_gpg/links.py b/mayan/apps/django_gpg/links.py index 751f21e24c..2fc53ab3e4 100644 --- a/mayan/apps/django_gpg/links.py +++ b/mayan/apps/django_gpg/links.py @@ -9,9 +9,28 @@ from .permissions import ( permission_keyserver_query ) -link_private_keys = Link(icon='fa fa-key', permissions=[permission_key_view], text=_('Private keys'), view='django_gpg:key_private_list') -link_public_keys = Link(icon='fa fa-key', permissions=[permission_key_view], text=_('Public keys'), view='django_gpg:key_public_list') -link_key_delete = Link(permissions=[permission_key_delete], tags='dangerous', text=_('Delete'), view='django_gpg:key_delete', args=['object.fingerprint', 'object.type']) -link_key_query = Link(permissions=[permission_keyserver_query], text=_('Query keyservers'), view='django_gpg:key_query') -link_key_receive = Link(keep_query=True, permissions=[permission_key_receive], text=_('Import'), view='django_gpg:key_receive', args='object.key_id') -link_key_setup = Link(icon='fa fa-key', permissions=[permission_key_view], text=_('Key management'), view='django_gpg:key_public_list') +link_private_keys = Link( + icon='fa fa-key', permissions=[permission_key_view], + text=_('Private keys'), view='django_gpg:key_private_list' +) +link_public_keys = Link( + icon='fa fa-key', permissions=[permission_key_view], text=_('Public keys'), + view='django_gpg:key_public_list' +) +link_key_delete = Link( + permissions=[permission_key_delete], tags='dangerous', text=_('Delete'), + view='django_gpg:key_delete', args=['object.fingerprint', 'object.type'] +) + +link_key_query = Link( + permissions=[permission_keyserver_query], text=_('Query keyservers'), + view='django_gpg:key_query' +) +link_key_receive = Link( + keep_query=True, permissions=[permission_key_receive], text=_('Import'), + view='django_gpg:key_receive', args='object.key_id' +) +link_key_setup = Link( + icon='fa fa-key', permissions=[permission_key_view], + text=_('Key management'), view='django_gpg:key_public_list' +) diff --git a/mayan/apps/django_gpg/literals.py b/mayan/apps/django_gpg/literals.py index 35fb872e47..85b75e061f 100644 --- a/mayan/apps/django_gpg/literals.py +++ b/mayan/apps/django_gpg/literals.py @@ -41,7 +41,10 @@ SIGNATURE_STATES = { 'text': _('Signature error.'), }, SIGNATURE_STATE_NO_PUBLIC_KEY: { - 'text': _('Document is signed but no public key is available for verification.'), + 'text': _( + 'Document is signed but no public key is available for ' + 'verification.' + ), }, SIGNATURE_STATE_GOOD: { 'text': _('Document is signed, and signature is good.'), diff --git a/mayan/apps/django_gpg/permissions.py b/mayan/apps/django_gpg/permissions.py index ed527e11f5..dc5536b2ca 100644 --- a/mayan/apps/django_gpg/permissions.py +++ b/mayan/apps/django_gpg/permissions.py @@ -6,7 +6,15 @@ from permissions import PermissionNamespace namespace = PermissionNamespace('django_gpg', _('Key management')) -permission_key_view = namespace.add_permission(name='key_view', label=_('View keys')) -permission_key_delete = namespace.add_permission(name='key_delete', label=_('Delete keys')) -permission_keyserver_query = namespace.add_permission(name='keyserver_query', label=_('Query keyservers')) -permission_key_receive = namespace.add_permission(name='key_receive', label=_('Import keys from keyservers')) +permission_key_view = namespace.add_permission( + name='key_view', label=_('View keys') +) +permission_key_delete = namespace.add_permission( + name='key_delete', label=_('Delete keys') +) +permission_keyserver_query = namespace.add_permission( + name='keyserver_query', label=_('Query keyservers') +) +permission_key_receive = namespace.add_permission( + name='key_receive', label=_('Import keys from keyservers') +) diff --git a/mayan/apps/django_gpg/runtime.py b/mayan/apps/django_gpg/runtime.py index d5e4f2b5e2..af8bfe4c42 100644 --- a/mayan/apps/django_gpg/runtime.py +++ b/mayan/apps/django_gpg/runtime.py @@ -1,4 +1,7 @@ from .api import GPG from .settings import setting_gpg_home, setting_gpg_path, setting_keyservers -gpg = GPG(binary_path=setting_gpg_path.value, home=setting_gpg_home.value, keyservers=setting_keyservers.value) +gpg = GPG( + binary_path=setting_gpg_path.value, home=setting_gpg_home.value, + keyservers=setting_keyservers.value +) diff --git a/mayan/apps/django_gpg/settings.py b/mayan/apps/django_gpg/settings.py index 93efbfa4f9..10d7464fb1 100644 --- a/mayan/apps/django_gpg/settings.py +++ b/mayan/apps/django_gpg/settings.py @@ -8,6 +8,19 @@ from django.utils.translation import ugettext_lazy as _ from smart_settings import Namespace namespace = Namespace(name='django_gpg', label=_('Signatures')) -setting_keyservers = namespace.add_setting(global_name='SIGNATURES_KEYSERVERS', default=['pool.sks-keyservers.net'], help_text=_('List of keyservers to be queried for unknown keys.')) -setting_gpg_home = namespace.add_setting(global_name='SIGNATURES_GPG_HOME', default=os.path.join(settings.MEDIA_ROOT, 'gpg_home'), help_text=_('Home directory used to store keys as well as configuration files.'), is_path=True) -setting_gpg_path = namespace.add_setting(global_name='SIGNATURES_GPG_PATH', default='/usr/bin/gpg', help_text=_('Path to the GPG binary.'), is_path=True) +setting_keyservers = namespace.add_setting( + global_name='SIGNATURES_KEYSERVERS', default=['pool.sks-keyservers.net'], + help_text=_('List of keyservers to be queried for unknown keys.') +) +setting_gpg_home = namespace.add_setting( + global_name='SIGNATURES_GPG_HOME', + default=os.path.join(settings.MEDIA_ROOT, 'gpg_home'), + help_text=_( + 'Home directory used to store keys as well as configuration files.' + ), + is_path=True +) +setting_gpg_path = namespace.add_setting( + global_name='SIGNATURES_GPG_PATH', default='/usr/bin/gpg', + help_text=_('Path to the GPG binary.'), is_path=True +) diff --git a/mayan/apps/django_gpg/tests.py b/mayan/apps/django_gpg/tests.py index 0ad33f0f69..2359b6a42d 100644 --- a/mayan/apps/django_gpg/tests.py +++ b/mayan/apps/django_gpg/tests.py @@ -20,7 +20,10 @@ class DjangoGPGTestCase(TestCase): except OSError: pass - self.gpg = GPG(binary_path=setting_gpg_path.value, home=TEST_GPG_HOME, keyservers=TEST_KEYSERVERS) + self.gpg = GPG( + binary_path=setting_gpg_path.value, home=TEST_GPG_HOME, + keyservers=TEST_KEYSERVERS + ) def test_main(self): # No private or public keys in the keyring @@ -28,10 +31,14 @@ class DjangoGPGTestCase(TestCase): self.assertEqual(Key.get_all(self.gpg), []) # Test querying the keyservers - self.assertTrue(TEST_KEY_ID in [key_stub.key_id for key_stub in self.gpg.query(TEST_UIDS)]) + self.assertTrue( + TEST_KEY_ID in [key_stub.key_id for key_stub in self.gpg.query(TEST_UIDS)] + ) # Receive a public key from the keyserver self.gpg.receive_key(key_id=TEST_KEY_ID[-8:]) # Check that the received key is indeed in the keyring - self.assertTrue(TEST_KEY_ID[-16:] in [key_stub.key_id for key_stub in Key.get_all(self.gpg)]) + self.assertTrue( + TEST_KEY_ID[-16:] in [key_stub.key_id for key_stub in Key.get_all(self.gpg)] + ) diff --git a/mayan/apps/django_gpg/urls.py b/mayan/apps/django_gpg/urls.py index 39ed308180..a2007fcc7b 100644 --- a/mayan/apps/django_gpg/urls.py +++ b/mayan/apps/django_gpg/urls.py @@ -2,7 +2,10 @@ from django.conf.urls import patterns, url urlpatterns = patterns( 'django_gpg.views', - url(r'^delete/(?P.+)/(?P\w+)/$', 'key_delete', name='key_delete'), + url( + r'^delete/(?P.+)/(?P\w+)/$', 'key_delete', + name='key_delete' + ), url(r'^list/private/$', 'key_list', {'secret': True}, 'key_private_list'), url(r'^list/public/$', 'key_list', {'secret': False}, 'key_public_list'), url(r'^query/$', 'key_query', name='key_query'), diff --git a/mayan/apps/django_gpg/views.py b/mayan/apps/django_gpg/views.py index 4bebecc53f..5eb6e2288e 100644 --- a/mayan/apps/django_gpg/views.py +++ b/mayan/apps/django_gpg/views.py @@ -112,7 +112,10 @@ def key_delete(request, fingerprint, key_type): return render_to_response('appearance/generic_confirm.html', { 'title': _('Delete key'), 'delete_view': True, - 'message': _('Delete key %s? If you delete a public key that is part of a public/private pair the private key will be deleted as well.') % key, + 'message': _( + 'Delete key %s? If you delete a public key that is part of a ' + 'public/private pair the private key will be deleted as well.' + ) % key, 'next': next, 'previous': previous, }, context_instance=RequestContext(request)) @@ -148,7 +151,9 @@ def key_query(request): 'extra_columns': [ { 'name': _('ID'), - 'attribute': encapsulate(lambda item: '...{0}'.format(item.key_id[-16:])), + 'attribute': encapsulate( + lambda item: '...{0}'.format(item.key_id[-16:]) + ), }, { 'name': _('Type'), @@ -156,11 +161,15 @@ def key_query(request): }, { 'name': _('Creation date'), - 'attribute': encapsulate(lambda x: datetime.fromtimestamp(int(x.date))) + 'attribute': encapsulate( + lambda x: datetime.fromtimestamp(int(x.date)) + ) }, { 'name': _('Expiration date'), - 'attribute': encapsulate(lambda x: datetime.fromtimestamp(int(x.expires)) if x.expires else _('No expiration')) + 'attribute': encapsulate( + lambda x: datetime.fromtimestamp(int(x.expires)) if x.expires else _('No expiration') + ) }, { 'name': _('Length'), @@ -168,7 +177,9 @@ def key_query(request): }, { 'name': _('Identities'), - 'attribute': encapsulate(lambda x: ', '.join(x.uids)), + 'attribute': encapsulate( + lambda x: ', '.join(x.uids) + ), }, ] }, diff --git a/mayan/apps/document_comments/apps.py b/mayan/apps/document_comments/apps.py index 50d8b04884..e04ac07c45 100644 --- a/mayan/apps/document_comments/apps.py +++ b/mayan/apps/document_comments/apps.py @@ -38,10 +38,15 @@ class DocumentCommentsApp(MayanAppConfig): ) ) - ModelAttribute(Document, label=_('Comments'), name='comments', type_name='related') + ModelAttribute( + Document, label=_('Comments'), name='comments', type_name='related' + ) SourceColumn(source=Comment, label=_('Date'), attribute='submit_date') - SourceColumn(source=Comment, label=_('User'), attribute=encapsulate(lambda x: x.user.get_full_name() if x.user.get_full_name() else x.user)) + SourceColumn( + source=Comment, label=_('User'), + attribute=encapsulate(lambda x: x.user.get_full_name() if x.user.get_full_name() else x.user) + ) SourceColumn(source=Comment, label=_('Comment'), attribute='comment') ModelPermission.register( @@ -51,6 +56,14 @@ class DocumentCommentsApp(MayanAppConfig): ) ) - menu_sidebar.bind_links(links=[link_comment_add], sources=['comments:comments_for_document', 'comments:comment_add', 'comments:comment_delete', 'comments:comment_multiple_delete']) + menu_sidebar.bind_links( + links=[link_comment_add], + sources=[ + 'comments:comments_for_document', 'comments:comment_add', + 'comments:comment_delete', 'comments:comment_multiple_delete' + ] + ) menu_object.bind_links(links=[link_comment_delete], sources=[Comment]) - menu_facet.bind_links(links=[link_comments_for_document], sources=[Document]) + menu_facet.bind_links( + links=[link_comments_for_document], sources=[Document] + ) diff --git a/mayan/apps/document_comments/links.py b/mayan/apps/document_comments/links.py index ed1ca06455..7992719fdb 100644 --- a/mayan/apps/document_comments/links.py +++ b/mayan/apps/document_comments/links.py @@ -9,7 +9,19 @@ from .permissions import ( permission_comment_view ) -link_comment_add = Link(permissions=[permission_comment_create], text=_('Add comment'), view='comments:comment_add', args='object.pk') -link_comment_delete = Link(permissions=[permission_comment_delete], tags='dangerous', text=_('Delete'), view='comments:comment_delete', args='object.pk') -link_comment_multiple_delete = Link(permissions=[permission_comment_delete], tags='dangerous', text=_('Delete'), view='comments:comment_multiple_delete', args='object.pk') -link_comments_for_document = Link(permissions=[permission_comment_view], text=_('Comments'), view='comments:comments_for_document', args='object.pk') +link_comment_add = Link( + permissions=[permission_comment_create], text=_('Add comment'), + view='comments:comment_add', args='object.pk' +) +link_comment_delete = Link( + permissions=[permission_comment_delete], tags='dangerous', + text=_('Delete'), view='comments:comment_delete', args='object.pk' +) +link_comment_multiple_delete = Link( + permissions=[permission_comment_delete], tags='dangerous', + text=_('Delete'), view='comments:comment_multiple_delete', args='object.pk' +) +link_comments_for_document = Link( + permissions=[permission_comment_view], text=_('Comments'), + view='comments:comments_for_document', args='object.pk' +) diff --git a/mayan/apps/document_comments/permissions.py b/mayan/apps/document_comments/permissions.py index 0f8cf08453..2a9fe8c1ac 100644 --- a/mayan/apps/document_comments/permissions.py +++ b/mayan/apps/document_comments/permissions.py @@ -6,6 +6,12 @@ from permissions import PermissionNamespace namespace = PermissionNamespace('comments', _('Comments')) -permission_comment_create = namespace.add_permission(name='comment_create', label=_('Create new comments')) -permission_comment_delete = namespace.add_permission(name='comment_delete', label=_('Delete comments')) -permission_comment_view = namespace.add_permission(name='comment_view', label=_('View comments')) +permission_comment_create = namespace.add_permission( + name='comment_create', label=_('Create new comments') +) +permission_comment_delete = namespace.add_permission( + name='comment_delete', label=_('Delete comments') +) +permission_comment_view = namespace.add_permission( + name='comment_view', label=_('View comments') +) diff --git a/mayan/apps/document_comments/urls.py b/mayan/apps/document_comments/urls.py index 188ca85d72..cb99576a9a 100644 --- a/mayan/apps/document_comments/urls.py +++ b/mayan/apps/document_comments/urls.py @@ -4,8 +4,20 @@ from django.conf.urls import patterns, url urlpatterns = patterns( 'document_comments.views', - url(r'^comment/(?P\d+)/delete/$', 'comment_delete', name='comment_delete'), - url(r'^comment/multiple/delete/$', 'comment_multiple_delete', name='comment_multiple_delete'), - url(r'^(?P\d+)/comment/add/$', 'comment_add', name='comment_add'), - url(r'^(?P\d+)/comment/list/$', 'comments_for_document', name='comments_for_document'), + url( + r'^comment/(?P\d+)/delete/$', 'comment_delete', + name='comment_delete' + ), + url( + r'^comment/multiple/delete/$', 'comment_multiple_delete', + name='comment_multiple_delete' + ), + url( + r'^(?P\d+)/comment/add/$', 'comment_add', + name='comment_add' + ), + url( + r'^(?P\d+)/comment/list/$', 'comments_for_document', + name='comments_for_document' + ), ) diff --git a/mayan/apps/document_comments/views.py b/mayan/apps/document_comments/views.py index b1f1c6b2d9..c57b5576e5 100644 --- a/mayan/apps/document_comments/views.py +++ b/mayan/apps/document_comments/views.py @@ -82,7 +82,9 @@ def comment_add(request, document_id): try: Permission.check_permissions(request.user, [permission_comment_create]) except PermissionDenied: - AccessControlList.objects.check_access(permission_comment_create, request.user, document) + AccessControlList.objects.check_access( + permission_comment_create, request.user, document + ) post_action_redirect = None @@ -120,7 +122,9 @@ def comments_for_document(request, document_id): try: Permission.check_permissions(request.user, [permission_comment_view]) except PermissionDenied: - AccessControlList.objects.check_access(permission_comment_view, request.user, document) + AccessControlList.objects.check_access( + permission_comment_view, request.user, document + ) return render_to_response('appearance/generic_list.html', { 'object': document, diff --git a/mayan/apps/document_indexing/api_views.py b/mayan/apps/document_indexing/api_views.py index 940723c3cb..0b6fdeeec2 100644 --- a/mayan/apps/document_indexing/api_views.py +++ b/mayan/apps/document_indexing/api_views.py @@ -13,12 +13,13 @@ from rest_api.filters import MayanObjectPermissionsFilter from rest_api.permissions import MayanPermission from .models import Index, IndexInstanceNode, IndexTemplateNode -from .permissions import (permission_document_indexing_create, - permission_document_indexing_delete, - permission_document_indexing_edit, - permission_document_indexing_view) -from .serializers import (IndexInstanceNodeSerializer, IndexSerializer, - IndexTemplateNodeSerializer) +from .permissions import ( + permission_document_indexing_create, permission_document_indexing_delete, + permission_document_indexing_edit, permission_document_indexing_view +) +from .serializers import ( + IndexInstanceNodeSerializer, IndexSerializer, IndexTemplateNodeSerializer +) class APIIndexListView(generics.ListCreateAPIView): @@ -69,7 +70,8 @@ class APIIndexView(generics.RetrieveUpdateDestroyAPIView): class APIIndexNodeInstanceDocumentListView(generics.ListAPIView): """ - Returns a list of all the documents contained by a particular index node instance. + Returns a list of all the documents contained by a particular index node + instance. """ filter_backends = (MayanObjectPermissionsFilter,) @@ -80,11 +82,18 @@ class APIIndexNodeInstanceDocumentListView(generics.ListAPIView): return DocumentSerializer def get_queryset(self): - index_node_instance = get_object_or_404(IndexInstanceNode, pk=self.kwargs['pk']) + index_node_instance = get_object_or_404( + IndexInstanceNode, pk=self.kwargs['pk'] + ) try: - Permission.check_permissions(self.request.user, [permission_document_indexing_view]) + Permission.check_permissions( + self.request.user, [permission_document_indexing_view] + ) except PermissionDenied: - AccessControlList.objects.check_access(permission_document_indexing_view, self.request.user, index_node_instance.index) + AccessControlList.objects.check_access( + permission_document_indexing_view, self.request.user, + index_node_instance.index + ) return index_node_instance.documents.all() @@ -142,8 +151,12 @@ class APIDocumentIndexListView(generics.ListAPIView): def get_queryset(self): document = get_object_or_404(Document, pk=self.kwargs['pk']) try: - Permission.check_permissions(self.request.user, [permission_document_view]) + Permission.check_permissions( + self.request.user, [permission_document_view] + ) except PermissionDenied: - AccessControlList.objects.check_access(permission_document_view, self.request.user, document) + AccessControlList.objects.check_access( + permission_document_view, self.request.user, document + ) return document.node_instances.all() diff --git a/mayan/apps/document_indexing/apps.py b/mayan/apps/document_indexing/apps.py index 66e750c63d..463d6acf26 100644 --- a/mayan/apps/document_indexing/apps.py +++ b/mayan/apps/document_indexing/apps.py @@ -59,15 +59,47 @@ class DocumentIndexingApp(MayanAppConfig): } ) - menu_facet.bind_links(links=[link_document_index_list], sources=[Document]) - menu_object.bind_links(links=[link_index_setup_edit, link_index_setup_view, link_index_setup_document_types, link_index_setup_delete], sources=[Index]) - menu_object.bind_links(links=[link_template_node_create, link_template_node_edit, link_template_node_delete], sources=[IndexTemplateNode]) + menu_facet.bind_links( + links=[link_document_index_list], sources=[Document] + ) + menu_object.bind_links( + links=[ + link_index_setup_edit, link_index_setup_view, + link_index_setup_document_types, link_index_setup_delete + ], sources=[Index] + ) + menu_object.bind_links( + links=[ + link_template_node_create, link_template_node_edit, + link_template_node_delete + ], sources=[IndexTemplateNode] + ) menu_main.bind_links(links=[link_index_main_menu]) - menu_secondary.bind_links(links=[link_index_setup_list, link_index_setup_create], sources=[Index, 'indexing:index_setup_list', 'indexing:index_setup_create']) + menu_secondary.bind_links( + links=[link_index_setup_list, link_index_setup_create], + sources=[ + Index, 'indexing:index_setup_list', + 'indexing:index_setup_create' + ] + ) menu_setup.bind_links(links=[link_index_setup]) menu_tools.bind_links(links=[link_rebuild_index_instances]) - post_document_created.connect(document_created_index_update, dispatch_uid='document_created_index_update', sender=Document) - post_save.connect(document_metadata_index_update, dispatch_uid='document_metadata_index_update', sender=DocumentMetadata) - post_delete.connect(document_index_delete, dispatch_uid='document_index_delete', sender=Document) - post_delete.connect(document_metadata_index_post_delete, dispatch_uid='document_metadata_index_post_delete', sender=DocumentMetadata) + post_document_created.connect( + document_created_index_update, + dispatch_uid='document_created_index_update', sender=Document + ) + post_save.connect( + document_metadata_index_update, + dispatch_uid='document_metadata_index_update', + sender=DocumentMetadata + ) + post_delete.connect( + document_index_delete, dispatch_uid='document_index_delete', + sender=Document + ) + post_delete.connect( + document_metadata_index_post_delete, + dispatch_uid='document_metadata_index_post_delete', + sender=DocumentMetadata + ) diff --git a/mayan/apps/document_indexing/forms.py b/mayan/apps/document_indexing/forms.py index 0a3f85e6af..aa8acf3ade 100644 --- a/mayan/apps/document_indexing/forms.py +++ b/mayan/apps/document_indexing/forms.py @@ -16,7 +16,12 @@ class IndexTemplateNodeForm(forms.ModelForm): super(IndexTemplateNodeForm, self).__init__(*args, **kwargs) self.fields['index'].widget = forms.widgets.HiddenInput() self.fields['parent'].widget = forms.widgets.HiddenInput() - self.fields['expression'].help_text = ' '.join([unicode(self.fields['expression'].help_text), ModelAttribute.help_text_for(Document, type_names=['indexing'])]) + self.fields['expression'].help_text = ' '.join( + [ + unicode(self.fields['expression'].help_text), + ModelAttribute.help_text_for(Document, type_names=['indexing']) + ] + ) class Meta: fields = ('parent', 'index', 'expression', 'enabled', 'link_documents') diff --git a/mayan/apps/document_indexing/handlers.py b/mayan/apps/document_indexing/handlers.py index 245513097d..77322cfb65 100644 --- a/mayan/apps/document_indexing/handlers.py +++ b/mayan/apps/document_indexing/handlers.py @@ -4,7 +4,9 @@ from .tasks import task_delete_empty_index_nodes, task_index_document def document_created_index_update(sender, **kwargs): - task_index_document.apply_async(kwargs=dict(document_id=kwargs['instance'].pk)) + task_index_document.apply_async( + kwargs=dict(document_id=kwargs['instance'].pk) + ) def document_index_delete(sender, **kwargs): @@ -12,8 +14,12 @@ def document_index_delete(sender, **kwargs): def document_metadata_index_update(sender, **kwargs): - task_index_document.apply_async(kwargs=dict(document_id=kwargs['instance'].document.pk)) + task_index_document.apply_async( + kwargs=dict(document_id=kwargs['instance'].document.pk) + ) def document_metadata_index_post_delete(sender, **kwargs): - task_index_document.apply_async(kwargs=dict(document_id=kwargs['instance'].document.pk)) + task_index_document.apply_async( + kwargs=dict(document_id=kwargs['instance'].document.pk) + ) diff --git a/mayan/apps/document_indexing/links.py b/mayan/apps/document_indexing/links.py index f043017542..c6cc44a1f0 100644 --- a/mayan/apps/document_indexing/links.py +++ b/mayan/apps/document_indexing/links.py @@ -17,22 +17,65 @@ def is_not_root_node(context): return not context['resolved_object'].is_root_node() -link_document_index_list = Link(permissions=[permission_document_view], text=_('Indexes'), view='indexing:document_index_list', args='object.pk') -link_index_list = Link(permissions=[permission_document_indexing_view], text=_('Index list'), view='indexing:index_list') -link_index_main_menu = Link(icon='fa fa-list-ul', text=_('Indexes'), view='indexing:index_list') -link_index_setup = Link(icon='fa fa-list-ul', permissions=[permission_document_indexing_setup], text=_('Indexes'), view='indexing:index_setup_list') -link_index_setup_list = Link(permissions=[permission_document_indexing_setup], text=_('Indexes'), view='indexing:index_setup_list') -link_index_setup_create = Link(permissions=[permission_document_indexing_create], text=_('Create index'), view='indexing:index_setup_create') -link_index_setup_edit = Link(permissions=[permission_document_indexing_edit], text=_('Edit'), view='indexing:index_setup_edit', args='resolved_object.pk') -link_index_setup_delete = Link(permissions=[permission_document_indexing_delete], tags='dangerous', text=_('Delete'), view='indexing:index_setup_delete', args='resolved_object.pk') -link_index_setup_view = Link(permissions=[permission_document_indexing_setup], text=_('Tree template'), view='indexing:index_setup_view', args='resolved_object.pk') -link_index_setup_document_types = Link(permissions=[permission_document_indexing_edit], text=_('Document types'), view='indexing:index_setup_document_types', args='resolved_object.pk') +link_document_index_list = Link( + permissions=[permission_document_view], text=_('Indexes'), + view='indexing:document_index_list', args='object.pk' +) +link_index_list = Link( + permissions=[permission_document_indexing_view], text=_('Index list'), + view='indexing:index_list' +) +link_index_main_menu = Link( + icon='fa fa-list-ul', text=_('Indexes'), view='indexing:index_list' +) +link_index_setup = Link( + icon='fa fa-list-ul', permissions=[permission_document_indexing_setup], + text=_('Indexes'), view='indexing:index_setup_list' +) +link_index_setup_list = Link( + permissions=[permission_document_indexing_setup], text=_('Indexes'), + view='indexing:index_setup_list' +) +link_index_setup_create = Link( + permissions=[permission_document_indexing_create], text=_('Create index'), + view='indexing:index_setup_create' +) +link_index_setup_edit = Link( + permissions=[permission_document_indexing_edit], text=_('Edit'), + view='indexing:index_setup_edit', args='resolved_object.pk' +) +link_index_setup_delete = Link( + permissions=[permission_document_indexing_delete], tags='dangerous', + text=_('Delete'), view='indexing:index_setup_delete', + args='resolved_object.pk' +) +link_index_setup_view = Link( + permissions=[permission_document_indexing_setup], text=_('Tree template'), + view='indexing:index_setup_view', args='resolved_object.pk' +) +link_index_setup_document_types = Link( + permissions=[permission_document_indexing_edit], text=_('Document types'), + view='indexing:index_setup_document_types', args='resolved_object.pk' +) link_rebuild_index_instances = Link( icon='fa fa-database', description=_('Deletes and creates from scratch all the document indexes.'), permissions=[permission_document_indexing_rebuild_indexes], text=_('Rebuild indexes'), view='indexing:rebuild_index_instances' ) -link_template_node_create = Link(permissions=[permission_document_indexing_setup], text=_('New child node'), view='indexing:template_node_create', args='resolved_object.pk') -link_template_node_edit = Link(condition=is_not_root_node, permissions=[permission_document_indexing_setup], text=_('Edit'), view='indexing:template_node_edit', args='resolved_object.pk') -link_template_node_delete = Link(condition=is_not_root_node, permissions=[permission_document_indexing_setup], tags='dangerous', text=_('Delete'), view='indexing:template_node_delete', args='resolved_object.pk') +link_template_node_create = Link( + permissions=[permission_document_indexing_setup], text=_('New child node'), + view='indexing:template_node_create', args='resolved_object.pk' +) +link_template_node_edit = Link( + condition=is_not_root_node, + permissions=[permission_document_indexing_setup], text=_('Edit'), + view='indexing:template_node_edit', args='resolved_object.pk' +) +link_template_node_delete = Link( + condition=is_not_root_node, permissions=[ + permission_document_indexing_setup + ], + tags='dangerous', text=_('Delete'), view='indexing:template_node_delete', + args='resolved_object.pk' +) diff --git a/mayan/apps/document_indexing/managers.py b/mayan/apps/document_indexing/managers.py index 40c3678eee..ef6e4d9285 100644 --- a/mayan/apps/document_indexing/managers.py +++ b/mayan/apps/document_indexing/managers.py @@ -30,7 +30,9 @@ class IndexInstanceNodeManager(models.Manager): parent = instance_node.parent if parent: instance_node.delete() - IndexInstanceNodeManager.delete_empty_index_nodes_recursive(parent) + IndexInstanceNodeManager.delete_empty_index_nodes_recursive( + parent + ) def cascade_eval(self, document, template_node, parent_index_instance=None): """ @@ -41,14 +43,26 @@ class IndexInstanceNodeManager(models.Manager): if template_node.enabled: try: - result = eval(template_node.expression, {'document': document}, setting_available_indexing_functions.value) + result = eval( + template_node.expression, {'document': document}, + setting_available_indexing_functions.value + ) except Exception as exception: - error_message = _('Error indexing document: %(document)s; expression: %(expression)s; %(exception)s') % { - 'document': document, 'expression': template_node.expression, 'exception': exception} + error_message = _( + 'Error indexing document: %(document)s; expression: ' + '%(expression)s; %(exception)s' + ) % { + 'document': document, + 'expression': template_node.expression, + 'exception': exception + } logger.debug(error_message) else: if result: - index_instance, created = self.get_or_create(index_template_node=template_node, value=result, parent=parent_index_instance) + index_instance, created = self.get_or_create( + index_template_node=template_node, value=result, + parent=parent_index_instance + ) if template_node.link_documents: index_instance.documents.add(document) @@ -66,7 +80,9 @@ class IndexInstanceNodeManager(models.Manager): """ for instance_node in self.filter(documents__isnull=True, parent__isnull=False): - IndexInstanceNodeManager.delete_empty_index_nodes_recursive(instance_node) + IndexInstanceNodeManager.delete_empty_index_nodes_recursive( + instance_node + ) def index_document(self, document): """ @@ -80,7 +96,9 @@ class IndexInstanceNodeManager(models.Manager): # Only update indexes where the document type is found for index in Index.objects.filter(enabled=True, document_types=document.document_type): - root_instance, created = self.get_or_create(index_template_node=index.template_root, parent=None) + root_instance, created = self.get_or_create( + index_template_node=index.template_root, parent=None + ) for template_node in index.template_root.get_children(): self.cascade_eval(document, template_node, root_instance) diff --git a/mayan/apps/document_indexing/models.py b/mayan/apps/document_indexing/models.py index 969a5414b0..58f23357ad 100644 --- a/mayan/apps/document_indexing/models.py +++ b/mayan/apps/document_indexing/models.py @@ -15,9 +15,20 @@ from .managers import IndexManager, IndexInstanceNodeManager @python_2_unicode_compatible class Index(models.Model): - label = models.CharField(max_length=128, unique=True, verbose_name=_('Label')) - enabled = models.BooleanField(default=True, help_text=_('Causes this index to be visible and updated when document data changes.'), verbose_name=_('Enabled')) - document_types = models.ManyToManyField(DocumentType, verbose_name=_('Document types')) + label = models.CharField( + max_length=128, unique=True, verbose_name=_('Label') + ) + enabled = models.BooleanField( + default=True, + help_text=_( + 'Causes this index to be visible and updated when document data ' + 'changes.' + ), + verbose_name=_('Enabled') + ) + document_types = models.ManyToManyField( + DocumentType, verbose_name=_('Document types') + ) objects = IndexManager() @@ -34,7 +45,10 @@ class Index(models.Model): def get_absolute_url(self): try: - return reverse('indexing:index_instance_node_view', args=[self.instance_root.pk]) + return reverse( + 'indexing:index_instance_node_view', + args=[self.instance_root.pk] + ) except IndexInstanceNode.DoesNotExist: return '#' @@ -44,7 +58,9 @@ class Index(models.Model): IndexTemplateNode.objects.get_or_create(parent=None, index=self) def get_document_types_names(self): - return ', '.join([unicode(document_type) for document_type in self.document_types.all()] or ['None']) + return ', '.join( + [unicode(document_type) for document_type in self.document_types.all()] or ['None'] + ) def get_instance_node_count(self): try: @@ -59,11 +75,31 @@ class Index(models.Model): @python_2_unicode_compatible class IndexTemplateNode(MPTTModel): - parent = TreeForeignKey('self', null=True, blank=True) - index = models.ForeignKey(Index, verbose_name=_('Index'), related_name='node_templates') - expression = models.CharField(max_length=128, verbose_name=_('Indexing expression'), help_text=_('Enter a python string expression to be evaluated.')) - enabled = models.BooleanField(default=True, verbose_name=_('Enabled'), help_text=_('Causes this node to be visible and updated when document data changes.')) - link_documents = models.BooleanField(default=False, verbose_name=_('Link documents'), help_text=_('Check this option to have this node act as a container for documents and not as a parent for further nodes.')) + parent = TreeForeignKey('self', blank=True, null=True) + index = models.ForeignKey( + Index, related_name='node_templates', verbose_name=_('Index') + ) + expression = models.CharField( + max_length=128, + help_text=_('Enter a python string expression to be evaluated.'), + verbose_name=_('Indexing expression') + ) + enabled = models.BooleanField( + default=True, + help_text=_( + 'Causes this node to be visible and updated when document data ' + 'changes.' + ), + verbose_name=_('Enabled') + ) + link_documents = models.BooleanField( + default=False, + help_text=_( + 'Check this option to have this node act as a container for ' + 'documents and not as a parent for further nodes.' + ), + verbose_name=_('Link documents') + ) def __str__(self): if self.is_root_node(): @@ -79,9 +115,16 @@ class IndexTemplateNode(MPTTModel): @python_2_unicode_compatible class IndexInstanceNode(MPTTModel): parent = TreeForeignKey('self', null=True, blank=True) - index_template_node = models.ForeignKey(IndexTemplateNode, related_name='node_instance', verbose_name=_('Index template node')) - value = models.CharField(max_length=128, blank=True, verbose_name=_('Value')) - documents = models.ManyToManyField(Document, related_name='node_instances', verbose_name=_('Documents')) + index_template_node = models.ForeignKey( + IndexTemplateNode, related_name='node_instance', + verbose_name=_('Index template node') + ) + value = models.CharField( + blank=True, max_length=128, verbose_name=_('Value') + ) + documents = models.ManyToManyField( + Document, related_name='node_instances', verbose_name=_('Documents') + ) objects = IndexInstanceNodeManager() diff --git a/mayan/apps/document_indexing/permissions.py b/mayan/apps/document_indexing/permissions.py index 4d6442cb50..ab735647a8 100644 --- a/mayan/apps/document_indexing/permissions.py +++ b/mayan/apps/document_indexing/permissions.py @@ -6,9 +6,21 @@ from permissions import PermissionNamespace namespace = PermissionNamespace('document_indexing', _('Indexing')) -permission_document_indexing_setup = namespace.add_permission(name='document_index_setup', label=_('Configure document indexes')) -permission_document_indexing_create = namespace.add_permission(name='document_index_create', label=_('Create new document indexes')) -permission_document_indexing_edit = namespace.add_permission(name='document_index_edit', label=_('Edit document indexes')) -permission_document_indexing_delete = namespace.add_permission(name='document_index_delete', label=_('Delete document indexes')) -permission_document_indexing_view = namespace.add_permission(name='document_index_view', label=_('View document indexes')) -permission_document_indexing_rebuild_indexes = namespace.add_permission(name='document_rebuild_indexes', label=_('Rebuild document indexes')) +permission_document_indexing_setup = namespace.add_permission( + name='document_index_setup', label=_('Configure document indexes') +) +permission_document_indexing_create = namespace.add_permission( + name='document_index_create', label=_('Create new document indexes') +) +permission_document_indexing_edit = namespace.add_permission( + name='document_index_edit', label=_('Edit document indexes') +) +permission_document_indexing_delete = namespace.add_permission( + name='document_index_delete', label=_('Delete document indexes') +) +permission_document_indexing_view = namespace.add_permission( + name='document_index_view', label=_('View document indexes') +) +permission_document_indexing_rebuild_indexes = namespace.add_permission( + name='document_rebuild_indexes', label=_('Rebuild document indexes') +) diff --git a/mayan/apps/document_indexing/serializers.py b/mayan/apps/document_indexing/serializers.py index 188adac3a0..7a6c784075 100644 --- a/mayan/apps/document_indexing/serializers.py +++ b/mayan/apps/document_indexing/serializers.py @@ -21,7 +21,10 @@ IndexInstanceNodeSerializer.base_fields['children'] = IndexInstanceNodeSerialize class IndexTemplateNodeSerializer(serializers.ModelSerializer): class Meta: - fields = ('id', 'parent', 'index', 'expression', 'enabled', 'link_documents', 'level') + fields = ( + 'id', 'parent', 'index', 'expression', 'enabled', 'link_documents', + 'level' + ) model = IndexTemplateNode @@ -30,5 +33,8 @@ class IndexSerializer(serializers.ModelSerializer): instance_root = IndexInstanceNodeSerializer(read_only=True) class Meta: - fields = ('id', 'label', 'enabled', 'document_types', 'node_templates', 'instance_root') + fields = ( + 'id', 'label', 'enabled', 'document_types', 'node_templates', + 'instance_root' + ) model = Index diff --git a/mayan/apps/document_indexing/settings.py b/mayan/apps/document_indexing/settings.py index aa075e85f7..9ec7c9274f 100644 --- a/mayan/apps/document_indexing/settings.py +++ b/mayan/apps/document_indexing/settings.py @@ -8,4 +8,7 @@ available_indexing_functions = { } namespace = Namespace(name='document_indexing', label=_('Indexing')) -setting_available_indexing_functions = namespace.add_setting(global_name='DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS', default=available_indexing_functions) +setting_available_indexing_functions = namespace.add_setting( + global_name='DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS', + default=available_indexing_functions +) diff --git a/mayan/apps/document_indexing/tasks.py b/mayan/apps/document_indexing/tasks.py index be47dbe1d2..f405ddb1d7 100644 --- a/mayan/apps/document_indexing/tasks.py +++ b/mayan/apps/document_indexing/tasks.py @@ -17,7 +17,9 @@ logger = logging.getLogger(__name__) @app.task(bind=True, default_retry_delay=RETRY_DELAY, max_retries=None, ignore_result=True) def task_delete_empty_index_nodes(self): try: - rebuild_lock = Lock.acquire_lock('document_indexing_task_do_rebuild_all_indexes') + rebuild_lock = Lock.acquire_lock( + 'document_indexing_task_do_rebuild_all_indexes' + ) except LockError as exception: # A rebuild is happening, retry later raise self.retry(exc=exception) @@ -31,13 +33,17 @@ def task_delete_empty_index_nodes(self): @app.task(bind=True, default_retry_delay=RETRY_DELAY, max_retries=None, ignore_result=True) def task_index_document(self, document_id): try: - rebuild_lock = Lock.acquire_lock('document_indexing_task_do_rebuild_all_indexes') + rebuild_lock = Lock.acquire_lock( + 'document_indexing_task_do_rebuild_all_indexes' + ) except LockError as exception: # A rebuild is happening, retry later raise self.retry(exc=exception) else: try: - lock = Lock.acquire_lock('document_indexing_task_update_index_document_%d' % document_id) + lock = Lock.acquire_lock( + 'document_indexing_task_update_index_document_%d' % document_id + ) except LockError as exception: # This document is being reindexed by another task, retry later raise self.retry(exc=exception) @@ -45,13 +51,17 @@ def task_index_document(self, document_id): try: document = Document.objects.get(pk=document_id) except Document.DoesNotExist: - # Document was deleted before we could execute, abort about updating + # Document was deleted before we could execute, abort about + # updating pass else: try: IndexInstanceNode.objects.index_document(document) except OperationalError as exception: - logger.warning('Operational error while trying to index document: %s; %s', document, exception) + logger.warning( + 'Operational error while trying to index document: %s; %s', + document, exception + ) lock.release() raise self.retry(exc=exception) else: @@ -69,7 +79,9 @@ def task_do_rebuild_all_indexes(self): raise self.retry() try: - lock = Lock.acquire_lock('document_indexing_task_do_rebuild_all_indexes') + lock = Lock.acquire_lock( + 'document_indexing_task_do_rebuild_all_indexes' + ) except LockError as exception: # Another rebuild is happening, retry later raise self.retry(exc=exception) diff --git a/mayan/apps/document_indexing/test_models.py b/mayan/apps/document_indexing/test_models.py index 58b3a515a2..9b43468a82 100644 --- a/mayan/apps/document_indexing/test_models.py +++ b/mayan/apps/document_indexing/test_models.py @@ -12,14 +12,18 @@ from .models import Index, IndexInstanceNode, IndexTemplateNode class IndexTestCase(TestCase): def setUp(self): - self.document_type = DocumentType.objects.create(label=TEST_DOCUMENT_TYPE) + self.document_type = DocumentType.objects.create( + label=TEST_DOCUMENT_TYPE + ) ocr_settings = self.document_type.ocr_settings ocr_settings.auto_ocr = False ocr_settings.save() with open(TEST_SMALL_DOCUMENT_PATH) as file_object: - self.document = self.document_type.new_document(file_object=File(file_object)) + self.document = self.document_type.new_document( + file_object=File(file_object) + ) def tearDown(self): for document_type in DocumentType.objects.all(): @@ -27,7 +31,9 @@ class IndexTestCase(TestCase): def test_indexing(self): metadata_type = MetadataType.objects.create(name='test', label='test') - DocumentTypeMetadataType.objects.create(document_type=self.document_type, metadata_type=metadata_type) + DocumentTypeMetadataType.objects.create( + document_type=self.document_type, metadata_type=metadata_type + ) # Create empty index index = Index.objects.create(label='test') diff --git a/mayan/apps/mailer/apps.py b/mayan/apps/mailer/apps.py index e14f5af1a4..9ad93ee285 100644 --- a/mayan/apps/mailer/apps.py +++ b/mayan/apps/mailer/apps.py @@ -40,4 +40,8 @@ class MailerApp(MayanAppConfig): } ) - menu_object.bind_links(links=[link_send_document_link, link_send_document], sources=[Document]) + menu_object.bind_links( + links=[ + link_send_document_link, link_send_document + ], sources=[Document] + ) diff --git a/mayan/apps/mailer/forms.py b/mayan/apps/mailer/forms.py index 046ed74cf0..d63b60d344 100644 --- a/mayan/apps/mailer/forms.py +++ b/mayan/apps/mailer/forms.py @@ -22,4 +22,6 @@ class DocumentMailForm(forms.Form): email = forms.EmailField(label=_('Email address')) subject = forms.CharField(label=_('Subject'), required=False) - body = forms.CharField(label=_('Body'), widget=forms.widgets.Textarea(), required=False) + body = forms.CharField( + label=_('Body'), widget=forms.widgets.Textarea(), required=False + ) diff --git a/mayan/apps/mailer/links.py b/mayan/apps/mailer/links.py index aea8d26566..d469a24d67 100644 --- a/mayan/apps/mailer/links.py +++ b/mayan/apps/mailer/links.py @@ -4,7 +4,15 @@ from django.utils.translation import ugettext_lazy as _ from navigation import Link -from .permissions import permission_mailing_link, permission_mailing_send_document +from .permissions import ( + permission_mailing_link, permission_mailing_send_document +) -link_send_document = Link(permissions=[permission_mailing_send_document], text=_('Email document'), view='mailer:send_document', args='object.pk') -link_send_document_link = Link(permissions=[permission_mailing_link], text=_('Email link'), view='mailer:send_document_link', args='object.pk') +link_send_document = Link( + permissions=[permission_mailing_send_document], text=_('Email document'), + view='mailer:send_document', args='object.pk' +) +link_send_document_link = Link( + permissions=[permission_mailing_link], text=_('Email link'), + view='mailer:send_document_link', args='object.pk' +) diff --git a/mayan/apps/mailer/permissions.py b/mayan/apps/mailer/permissions.py index 6e15c0c0e0..4108257d40 100644 --- a/mayan/apps/mailer/permissions.py +++ b/mayan/apps/mailer/permissions.py @@ -6,5 +6,9 @@ from permissions import PermissionNamespace namespace = PermissionNamespace('mailing', _('Mailing')) -permission_mailing_link = namespace.add_permission(name='mail_link', label=_('Send document link via email')) -permission_mailing_send_document = namespace.add_permission(name='mail_document', label=_('Send document via email')) +permission_mailing_link = namespace.add_permission( + name='mail_link', label=_('Send document link via email') +) +permission_mailing_send_document = namespace.add_permission( + name='mail_document', label=_('Send document via email') +) diff --git a/mayan/apps/mailer/tasks.py b/mayan/apps/mailer/tasks.py index 9bc09613c8..5d3fd51ae4 100644 --- a/mayan/apps/mailer/tasks.py +++ b/mayan/apps/mailer/tasks.py @@ -6,11 +6,15 @@ from mayan.celery import app @app.task(ignore_result=True) def task_send_document(subject_text, body_text_content, sender, recipient, document_id, as_attachment=False): - email_msg = EmailMultiAlternatives(subject_text, body_text_content, sender, [recipient]) + email_msg = EmailMultiAlternatives( + subject_text, body_text_content, sender, [recipient] + ) if as_attachment: document = Document.objects.get(pk=document_id) with document.open() as descriptor: - email_msg.attach(document.label, descriptor.read(), document.file_mimetype) + email_msg.attach( + document.label, descriptor.read(), document.file_mimetype + ) email_msg.send() diff --git a/mayan/apps/mailer/urls.py b/mayan/apps/mailer/urls.py index 3de1fa9b77..2ecdd4817b 100644 --- a/mayan/apps/mailer/urls.py +++ b/mayan/apps/mailer/urls.py @@ -4,6 +4,12 @@ from django.conf.urls import patterns, url urlpatterns = patterns( 'mailer.views', - url(r'^(?P\d+)/send/link/$', 'send_document_link', name='send_document_link'), - url(r'^(?P\d+)/send/document/$', 'send_document_link', {'as_attachment': True}, 'send_document'), + url( + r'^(?P\d+)/send/link/$', 'send_document_link', + name='send_document_link' + ), + url( + r'^(?P\d+)/send/document/$', 'send_document_link', + {'as_attachment': True}, 'send_document' + ), ) diff --git a/mayan/apps/metadata/forms.py b/mayan/apps/metadata/forms.py index 7930ddab00..2161929480 100644 --- a/mayan/apps/metadata/forms.py +++ b/mayan/apps/metadata/forms.py @@ -120,7 +120,6 @@ class MetadataForm(forms.Form): attrs={'readonly': 'readonly'} ) - id = forms.CharField(label=_('ID'), widget=forms.HiddenInput) name = forms.CharField( diff --git a/mayan/apps/metadata/views.py b/mayan/apps/metadata/views.py index 0c010caa1c..2f3083f136 100644 --- a/mayan/apps/metadata/views.py +++ b/mayan/apps/metadata/views.py @@ -344,7 +344,7 @@ def metadata_remove(request, document_id=None, document_id_list=None): try: Permission.check_permissions( request.user, [permission_metadata_document_remove] - ) + ) except PermissionDenied: documents = AccessControlList.objects.filter_by_access( permission_metadata_document_remove, request.user, documents diff --git a/mayan/apps/navigation/classes.py b/mayan/apps/navigation/classes.py index 8e089cad94..0a580f53dc 100644 --- a/mayan/apps/navigation/classes.py +++ b/mayan/apps/navigation/classes.py @@ -77,12 +77,16 @@ class Menu(object): if source: resolved_navigation_object_list = [source] else: - navigation_object_list = context.get('navigation_object_list', ['object']) + navigation_object_list = context.get( + 'navigation_object_list', ['object'] + ) # Multiple objects for navigation_object in navigation_object_list: try: - resolved_navigation_object_list.append(Variable(navigation_object).resolve(context)) + resolved_navigation_object_list.append( + Variable(navigation_object).resolve(context) + ) except VariableDoesNotExist: pass @@ -93,10 +97,14 @@ class Menu(object): try: if inspect.isclass(bound_source) and type(resolved_navigation_object) == bound_source or source == CombinedSource(obj=resolved_navigation_object.__class__, view=current_view): for link in links: - resolved_link = link.resolve(context=context, resolved_object=resolved_navigation_object) + resolved_link = link.resolve( + context=context, + resolved_object=resolved_navigation_object + ) if resolved_link: resolved_links.append(resolved_link) - break # No need for further content object match testing + # No need for further content object match testing + break except TypeError: # When source is a dictionary pass @@ -164,7 +172,9 @@ class Link(object): # access to the instance. if resolved_object: try: - AccessControlList.objects.check_access(self.permissions, request.user, resolved_object) + AccessControlList.objects.check_access( + self.permissions, request.user, resolved_object + ) except PermissionDenied: return None else: @@ -205,7 +215,9 @@ class Link(object): kwargs = {key: Variable(value) for key, value in kwargs.iteritems()} # Use Django's exact {% url %} code to resolve the link - node = URLNode(view_name=view_name, args=args, kwargs=kwargs, asvar=None) + node = URLNode( + view_name=view_name, args=args, kwargs=kwargs, asvar=None + ) resolved_link.url = node.render(context) @@ -218,7 +230,18 @@ class Link(object): # Lets a new link keep the same URL query string of the current URL if self.keep_query: # Sometimes we are required to remove a key from the URL QS - previous_path = smart_unicode(urllib.unquote_plus(smart_str(request.get_full_path()) or smart_str(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))) + previous_path = smart_unicode( + urllib.unquote_plus( + smart_str( + request.get_full_path() + ) or smart_str( + request.META.get( + 'HTTP_REFERER', + reverse(settings.LOGIN_REDIRECT_URL) + ) + ) + ) + ) query_string = urlparse.urlparse(previous_path).query parsed_query_string = urlparse.parse_qs(query_string) @@ -228,7 +251,10 @@ class Link(object): except KeyError: pass - resolved_link.url = '%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True)) + resolved_link.url = '%s?%s' % ( + urlquote(resolved_link.url), + urlencode(parsed_query_string, doseq=True) + ) # Helps highligh in the UI the current link in effect resolved_link.active = self.view == current_view @@ -257,7 +283,9 @@ class SourceColumn(object): def __init__(self, source, label, attribute): self.__class__._registry.setdefault(source, []) - self.__class__._registry[source].append({'label': label, 'attribute': attribute}) + self.__class__._registry[source].append( + {'label': label, 'attribute': attribute} + ) class CombinedSource(object): diff --git a/mayan/apps/ocr/apps.py b/mayan/apps/ocr/apps.py index 1e7a17136b..e6b675d5a9 100644 --- a/mayan/apps/ocr/apps.py +++ b/mayan/apps/ocr/apps.py @@ -113,7 +113,7 @@ class OCRApp(MayanAppConfig): links=[link_document_submit], sources=[Document] ) menu_object.bind_links( - links=[link_entry_re_queue, link_entry_delete],\ + links=[link_entry_re_queue, link_entry_delete], sources=[DocumentVersionOCRError] ) menu_object.bind_links( @@ -121,7 +121,10 @@ class OCRApp(MayanAppConfig): ) menu_secondary.bind_links( links=[link_entry_list], - sources=['ocr:entry_list', 'ocr:entry_delete_multiple', 'ocr:entry_re_queue_multiple', DocumentVersionOCRError] + sources=[ + 'ocr:entry_list', 'ocr:entry_delete_multiple', + 'ocr:entry_re_queue_multiple', DocumentVersionOCRError + ] ) menu_tools.bind_links( links=[link_document_submit_all, link_entry_list] diff --git a/mayan/apps/ocr/backends/tesseract.py b/mayan/apps/ocr/backends/tesseract.py index 719f417b91..45fd9d152c 100644 --- a/mayan/apps/ocr/backends/tesseract.py +++ b/mayan/apps/ocr/backends/tesseract.py @@ -22,7 +22,9 @@ class Tesseract(OCRBackendBase): # TODO: pass tesseract binary path to the pytesseract image = Image.open(self.converter.get_page()) try: - result = pytesseract.image_to_string(image=image, lang=self.language) + result = pytesseract.image_to_string( + image=image, lang=self.language + ) # If tesseract gives an error with a language parameter # re-run it with no language parameter except Exception as exception: diff --git a/mayan/apps/ocr/settings.py b/mayan/apps/ocr/settings.py index d959740a6b..132e89e490 100644 --- a/mayan/apps/ocr/settings.py +++ b/mayan/apps/ocr/settings.py @@ -15,7 +15,10 @@ setting_unpaper_path = namespace.add_setting( ) setting_pdftotext_path = namespace.add_setting( global_name='OCR_PDFTOTEXT_PATH', default='/usr/bin/pdftotext', - help_text=_('File path to poppler\'s pdftotext program used to extract text from PDF files.'), + help_text=_( + 'File path to poppler\'s pdftotext program used to extract text ' + 'from PDF files.' + ), is_path=True ) setting_ocr_backend = namespace.add_setting( diff --git a/mayan/apps/ocr/tasks.py b/mayan/apps/ocr/tasks.py index ec8fdee85d..631833422a 100644 --- a/mayan/apps/ocr/tasks.py +++ b/mayan/apps/ocr/tasks.py @@ -31,16 +31,27 @@ def task_do_ocr(self, document_version_pk): document_version = None try: document_version = DocumentVersion.objects.get(pk=document_version_pk) - logger.info('Starting document OCR for document version: %s', document_version) + logger.info( + 'Starting document OCR for document version: %s', + document_version + ) backend = ocr_backend_class() backend.process_document_version(document_version) except OperationalError as exception: - logger.warning('OCR error for document version: %s; %s. Retrying.', document_version, exception) + logger.warning( + 'OCR error for document version: %s; %s. Retrying.', + document_version, exception + ) raise self.retry(exc=exception) except Exception as exception: - logger.error('OCR error for document version: %s; %s', document_version, exception) + logger.error( + 'OCR error for document version: %s; %s', document_version, + exception + ) if document_version: - entry, created = DocumentVersionOCRError.objects.get_or_create(document_version=document_version) + entry, created = DocumentVersionOCRError.objects.get_or_create( + document_version=document_version + ) if settings.DEBUG: result = [] @@ -53,15 +64,21 @@ def task_do_ocr(self, document_version_pk): entry.save() else: - logger.info('OCR complete for document version: %s', document_version) + logger.info( + 'OCR complete for document version: %s', document_version + ) try: - entry = DocumentVersionOCRError.objects.get(document_version=document_version) + entry = DocumentVersionOCRError.objects.get( + document_version=document_version + ) except DocumentVersionOCRError.DoesNotExist: pass else: entry.delete() - post_document_version_ocr.send(sender=self, instance=document_version) + post_document_version_ocr.send( + sender=self, instance=document_version + ) finally: lock.release() except LockError: diff --git a/mayan/apps/ocr/test_models.py b/mayan/apps/ocr/test_models.py index e2f9fdd467..def2d78150 100644 --- a/mayan/apps/ocr/test_models.py +++ b/mayan/apps/ocr/test_models.py @@ -13,7 +13,9 @@ from documents.test_models import ( class DocumentOCRTestCase(TestCase): def setUp(self): - self.document_type = DocumentType.objects.create(label=TEST_DOCUMENT_TYPE) + self.document_type = DocumentType.objects.create( + label=TEST_DOCUMENT_TYPE + ) with open(TEST_SMALL_DOCUMENT_PATH) as file_object: self.document = self.document_type.new_document( @@ -38,7 +40,9 @@ class GermanOCRSupportTestCase(TestCase): # Get corresponding language code for German from the default language # choices list - language_code = [language for language in setting_language_choices.value if language[1] == 'German'][0][0] + language_code = [ + language for language in setting_language_choices.value if language[1] == 'German' + ][0][0] self.assertEqual('deu', language_code) diff --git a/mayan/apps/ocr/views.py b/mayan/apps/ocr/views.py index d52ba45f9a..58ea61481e 100644 --- a/mayan/apps/ocr/views.py +++ b/mayan/apps/ocr/views.py @@ -44,7 +44,7 @@ class DocumentSubmitView(ConfirmView): document.submit_for_ocr() messages.success( request, - _('Document: %(document)s was added to the OCR queue.') % { + _('Document: %(document)s was added to the OCR queue.') % { 'document': document } ) @@ -158,7 +158,11 @@ def entry_delete(request, pk=None, pk_list=None): if pk: entries = [get_object_or_404(DocumentVersionOCRError, pk=pk)] elif pk_list: - entries = [get_object_or_404(DocumentVersionOCRError, pk=pk) for pk in pk_list.split(',')] + entries = [ + get_object_or_404( + DocumentVersionOCRError, pk=pk + ) for pk in pk_list.split(',') + ] else: messages.error(request, _('Make at least one selection.')) return HttpResponseRedirect( diff --git a/mayan/apps/permissions/classes.py b/mayan/apps/permissions/classes.py index 30ae8958c3..e8659a0708 100644 --- a/mayan/apps/permissions/classes.py +++ b/mayan/apps/permissions/classes.py @@ -24,7 +24,9 @@ class PermissionNamespace(object): return cls._registry[name] except KeyError: raise InvalidNamespace( - 'Invalid namespace name. This is probably an obsolete permission namespace, execute the management command "purge_permissions" and try again.' + 'Invalid namespace name. This is probably an obsolete ' + 'permission namespace, execute the management command ' + '"purge_permissions" and try again.' ) def __init__(self, name, label): @@ -106,5 +108,7 @@ class Permission(object): name=self.name, ) stored_permission.volatile_permission = self - self.__class__._stored_permissions_cache[self.uuid] = stored_permission + self.__class__._stored_permissions_cache[ + self.uuid + ] = stored_permission return stored_permission diff --git a/mayan/apps/tags/views.py b/mayan/apps/tags/views.py index 48176bf002..0215e92e60 100644 --- a/mayan/apps/tags/views.py +++ b/mayan/apps/tags/views.py @@ -171,7 +171,9 @@ def tag_delete(request, tag_id=None, tag_id_list=None): tags = [get_object_or_404(Tag, pk=tag_id)] post_action_redirect = reverse('tags:tag_list') elif tag_id_list: - tags = [get_object_or_404(Tag, pk=tag_id) for tag_id in tag_id_list.split(',')] + tags = [ + get_object_or_404(Tag, pk=tag_id) for tag_id in tag_id_list.split(',') + ] else: messages.error(request, _('Must provide at least one tag.')) return HttpResponseRedirect( @@ -274,7 +276,9 @@ class DocumentTagListView(TagListView): permission_document_view, request.user, self.document ) - return super(DocumentTagListView, self).dispatch(request, *args, **kwargs) + return super( + DocumentTagListView, self + ).dispatch(request, *args, **kwargs) def get_extra_context(self): return { @@ -301,7 +305,9 @@ def tag_remove(request, document_id=None, document_id_list=None, tag_id=None, ta if document_id: documents = [get_object_or_404(Document, pk=document_id)] elif document_id_list: - documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] + documents = [ + get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',') + ] else: messages.error( request, _('Must provide at least one tagged document.') @@ -400,10 +406,11 @@ def tag_remove(request, document_id=None, document_id_list=None, tag_id=None, ta for tag in tags: if tag not in document.tags.all(): messages.warning( - request, _('Document "%(document)s" wasn\'t tagged as "%(tag)s"' - ) % { - 'document': document, 'tag': tag - } + request, _( + 'Document "%(document)s" wasn\'t tagged as "%(tag)s"' + ) % { + 'document': document, 'tag': tag + } ) else: tag.documents.remove(document) @@ -417,8 +424,9 @@ def tag_remove(request, document_id=None, document_id_list=None, tag_id=None, ta return HttpResponseRedirect(next) else: - return render_to_response(template, context, - context_instance=RequestContext(request)) + return render_to_response( + template, context, context_instance=RequestContext(request) + ) def single_document_multiple_tag_remove(request, document_id): diff --git a/mayan/apps/user_management/urls.py b/mayan/apps/user_management/urls.py index fc26bb6520..69aaf7b976 100644 --- a/mayan/apps/user_management/urls.py +++ b/mayan/apps/user_management/urls.py @@ -39,7 +39,7 @@ urlpatterns = patterns( url( r'^user/multiple/delete/$', 'user_multiple_delete', name='user_multiple_delete' - ), + ), url( r'^user/(?P\d+)/set_password/$', 'user_set_password', name='user_set_password'