diff --git a/mayan/apps/metadata/api_views.py b/mayan/apps/metadata/api_views.py index 959c2bc486..8b7fac31d0 100644 --- a/mayan/apps/metadata/api_views.py +++ b/mayan/apps/metadata/api_views.py @@ -38,11 +38,15 @@ class APIMetadataTypeListView(generics.ListCreateAPIView): mayan_view_permissions = {'POST': [permission_metadata_type_create]} def get(self, *args, **kwargs): - """Returns a list of all the metadata types.""" + """ + Returns a list of all the metadata types. + """ return super(APIMetadataTypeListView, self).get(*args, **kwargs) def post(self, *args, **kwargs): - """Create a new metadata type.""" + """ + Create a new metadata type. + """ return super(APIMetadataTypeListView, self).post(*args, **kwargs) @@ -59,19 +63,27 @@ class APIMetadataTypeView(generics.RetrieveUpdateDestroyAPIView): } def delete(self, *args, **kwargs): - """Delete the selected metadata type.""" + """ + Delete the selected metadata type. + """ return super(APIMetadataTypeView, self).delete(*args, **kwargs) def get(self, *args, **kwargs): - """Return the details of the selected metadata type.""" + """ + Return the details of the selected metadata type. + """ return super(APIMetadataTypeView, self).get(*args, **kwargs) def patch(self, *args, **kwargs): - """Edit the selected metadata type.""" + """ + Edit the selected metadata type. + """ return super(APIMetadataTypeView, self).patch(*args, **kwargs) def put(self, *args, **kwargs): - """Edit the selected metadata type.""" + """ + Edit the selected metadata type. + """ return super(APIMetadataTypeView, self).put(*args, **kwargs) @@ -86,19 +98,31 @@ class APIDocumentMetadataListView(generics.ListCreateAPIView): document = self.get_document() if self.request == 'GET': - # Make sure the use has the permission to see the metadata for this document + # Make sure the use has the permission to see the metadata for + # this document try: - Permission.check_permissions(self.request.user, [permission_metadata_document_view]) + Permission.check_permissions( + self.request.user, [permission_metadata_document_view] + ) except PermissionDenied: - AccessControlList.objects.check_access(permission_metadata_document_view, self.request.user, document) + AccessControlList.objects.check_access( + permission_metadata_document_view, self.request.user, + document + ) else: return document.metadata.all() elif self.request == 'POST': - # Make sure the use has the permission to add metadata to this document + # Make sure the use has the permission to add metadata to this + # document try: - Permission.check_permissions(self.request.user, [permission_metadata_document_add]) + Permission.check_permissions( + self.request.user, [permission_metadata_document_add] + ) except PermissionDenied: - AccessControlList.objects.check_access(permission_metadata_document_add, self.request.user, document) + AccessControlList.objects.check_access( + permission_metadata_document_add, self.request.user, + document + ) else: return document.metadata.all() @@ -106,11 +130,15 @@ class APIDocumentMetadataListView(generics.ListCreateAPIView): serializer.document = self.get_document() def get(self, *args, **kwargs): - """Returns a list of selected document's metadata types and values.""" + """ + Returns a list of selected document's metadata types and values. + """ return super(APIDocumentMetadataListView, self).get(*args, **kwargs) def post(self, *args, **kwargs): - """Add an existing metadata type and value to the selected document.""" + """ + Add an existing metadata type and value to the selected document. + """ return super(APIDocumentMetadataListView, self).post(*args, **kwargs) @@ -127,29 +155,53 @@ class APIDocumentMetadataView(generics.RetrieveUpdateDestroyAPIView): } def delete(self, *args, **kwargs): - """Delete the selected document metadata type and value.""" + """ + Delete the selected document metadata type and value. + """ try: - return super(APIDocumentMetadataView, self).delete(*args, **kwargs) + return super( + APIDocumentMetadataView, self + ).delete(*args, **kwargs) except Exception as exception: - return Response(status=status.HTTP_400_BAD_REQUEST, data={'non_fields_errors': unicode(exception)}) + return Response( + status=status.HTTP_400_BAD_REQUEST, data={ + 'non_fields_errors': unicode(exception) + } + ) def get(self, *args, **kwargs): - """Return the details of the selected document metadata type and value.""" + """ + Return the details of the selected document metadata type and value. + """ return super(APIDocumentMetadataView, self).get(*args, **kwargs) def patch(self, *args, **kwargs): - """Edit the selected document metadata type and value.""" + """ + Edit the selected document metadata type and value. + """ try: - return super(APIDocumentMetadataView, self).patch(*args, **kwargs) + return super( + APIDocumentMetadataView, self + ).patch(*args, **kwargs) except Exception as exception: - return Response(status=status.HTTP_400_BAD_REQUEST, data={'non_fields_errors': unicode(exception)}) + return Response( + status=status.HTTP_400_BAD_REQUEST, data={ + 'non_fields_errors': unicode(exception) + } + ) def put(self, *args, **kwargs): - """Edit the selected document metadata type and value.""" + """ + Edit the selected document metadata type and value. + """ try: return super(APIDocumentMetadataView, self).put(*args, **kwargs) except Exception as exception: - return Response(status=status.HTTP_400_BAD_REQUEST, data={'non_fields_errors': unicode(exception)}) + return Response( + status=status.HTTP_400_BAD_REQUEST, data={ + 'non_fields_errors': unicode(exception) + } + ) class APIDocumentTypeMetadataTypeOptionalListView(generics.ListCreateAPIView): @@ -160,17 +212,28 @@ class APIDocumentTypeMetadataTypeOptionalListView(generics.ListCreateAPIView): required_metadata = False def get_queryset(self): - document_type = get_object_or_404(DocumentType, pk=self.kwargs['document_type_pk']) + document_type = get_object_or_404( + DocumentType, pk=self.kwargs['document_type_pk'] + ) try: - Permission.check_permissions(self.request.user, [permission_document_type_view]) + Permission.check_permissions( + self.request.user, [permission_document_type_view] + ) except PermissionDenied: - AccessControlList.objects.check_access(permission_document_type_view, self.request.user, document_type) + AccessControlList.objects.check_access( + permission_document_type_view, self.request.user, + document_type + ) return document_type.metadata.filter(required=self.required_metadata) def get(self, *args, **kwargs): - """Returns a list of selected document type's optional metadata types.""" - return super(APIDocumentTypeMetadataTypeOptionalListView, self).get(*args, **kwargs) + """ + Returns a list of selected document type's optional metadata types. + """ + return super( + APIDocumentTypeMetadataTypeOptionalListView, self + ).get(*args, **kwargs) def get_serializer_class(self): if self.request.method == 'GET': @@ -182,18 +245,29 @@ class APIDocumentTypeMetadataTypeOptionalListView(generics.ListCreateAPIView): """ Add an optional metadata type to a document type. """ - document_type = get_object_or_404(DocumentType, pk=self.kwargs['document_type_pk']) + document_type = get_object_or_404( + DocumentType, pk=self.kwargs['document_type_pk'] + ) try: - Permission.check_permissions(self.request.user, [permission_document_type_edit]) + Permission.check_permissions( + self.request.user, [permission_document_type_edit] + ) except PermissionDenied: - AccessControlList.objects.check_access(permission_document_type_edit, self.request.user, document_type) + AccessControlList.objects.check_access( + permission_document_type_edit, self.request.user, + document_type + ) serializer = self.get_serializer(data=self.request.POST) if serializer.is_valid(): - metadata_type = get_object_or_404(MetadataType, pk=serializer.data['metadata_type_pk']) - document_type.metadata_type.add(metadata_type, required=self.required_metadata) + metadata_type = get_object_or_404( + MetadataType, pk=serializer.data['metadata_type_pk'] + ) + document_type.metadata_type.add( + metadata_type, required=self.required_metadata + ) return Response(status=status.HTTP_201_CREATED) else: return Response(status=status.HTTP_400_BAD_REQUEST) @@ -203,14 +277,21 @@ class APIDocumentTypeMetadataTypeRequiredListView(APIDocumentTypeMetadataTypeOpt required_metadata = True def get(self, *args, **kwargs): - """Returns a list of the selected document type's required metadata types.""" - return super(APIDocumentTypeMetadataTypeRequiredListView, self).get(*args, **kwargs) + """ + Returns a list of the selected document type's required metadata + types. + """ + return super( + APIDocumentTypeMetadataTypeRequiredListView, self + ).get(*args, **kwargs) def post(self, request, *args, **kwargs): """ Add a required metadata type to a document type. """ - return super(APIDocumentTypeMetadataTypeRequiredListView, self).get(*args, **kwargs) + return super( + APIDocumentTypeMetadataTypeRequiredListView, self + ).get(*args, **kwargs) class APIDocumentTypeMetadataTypeRequiredView(views.APIView): @@ -219,12 +300,21 @@ class APIDocumentTypeMetadataTypeRequiredView(views.APIView): Remove a metadata type from a document type. """ - document_type = get_object_or_404(DocumentType, pk=self.kwargs['document_type_pk']) + document_type = get_object_or_404( + DocumentType, pk=self.kwargs['document_type_pk'] + ) try: - Permission.check_permissions(self.request.user, [permission_document_type_edit]) + Permission.check_permissions( + self.request.user, [permission_document_type_edit] + ) except PermissionDenied: - AccessControlList.objects.check_access(permission_document_type_edit, self.request.user, document_type) + AccessControlList.objects.check_access( + permission_document_type_edit, self.request.user, + document_type + ) - metadata_type = get_object_or_404(MetadataType, pk=self.kwargs['metadata_type_pk']) + metadata_type = get_object_or_404( + MetadataType, pk=self.kwargs['metadata_type_pk'] + ) document_type.metadata_type.remove(metadata_type) return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/mayan/apps/metadata/apps.py b/mayan/apps/metadata/apps.py index 69a586185e..9ca638c2e7 100644 --- a/mayan/apps/metadata/apps.py +++ b/mayan/apps/metadata/apps.py @@ -31,10 +31,12 @@ from .handlers import ( from .links import ( link_metadata_add, link_metadata_edit, link_metadata_multiple_add, link_metadata_multiple_edit, link_metadata_multiple_remove, - link_metadata_remove, link_metadata_view, link_setup_document_type_metadata, - link_setup_document_type_metadata_required, link_setup_metadata_type_create, - link_setup_metadata_type_delete, link_setup_metadata_type_edit, - link_setup_metadata_type_list, link_documents_missing_required_metadata + link_metadata_remove, link_metadata_view, + link_setup_document_type_metadata, + link_setup_document_type_metadata_required, + link_setup_metadata_type_create, link_setup_metadata_type_delete, + link_setup_metadata_type_edit, link_setup_metadata_type_list, + link_documents_missing_required_metadata ) from .models import DocumentTypeMetadataType, MetadataType from .permissions import ( @@ -54,21 +56,47 @@ class MetadataApp(MayanAppConfig): APIEndPoint('metadata') - Document.add_to_class('metadata_value_of', DocumentMetadataHelper.constructor) + Document.add_to_class( + 'metadata_value_of', DocumentMetadataHelper.constructor + ) - ModelAttribute(Document, 'metadata', type_name='related', description=_('Queryset containing a MetadataType instance reference and a value for that metadata type')) - ModelAttribute(Document, 'metadata__metadata_type__name', label=_('Metadata type name'), type_name='query') - ModelAttribute(Document, 'metadata__value', label=_('Metadata type value'), type_name='query') - ModelAttribute(Document, 'metadata_value_of', label=_('Value of a metadata'), description=_('Return the value of a specific document metadata'), type_name=['property', 'indexing']) + ModelAttribute( + Document, 'metadata', type_name='related', + description=_( + 'Queryset containing a MetadataType instance reference and a value for that metadata type' + ) + ) + ModelAttribute( + Document, 'metadata__metadata_type__name', + label=_('Metadata type name'), type_name='query' + ) + ModelAttribute( + Document, 'metadata__value', label=_('Metadata type value'), + type_name='query' + ) + ModelAttribute( + Document, 'metadata_value_of', label=_('Value of a metadata'), + description=_( + 'Return the value of a specific document metadata' + ), + type_name=['property', 'indexing'] + ) ModelPermission.register( model=Document, permissions=( - permission_metadata_document_add, permission_metadata_document_edit, - permission_metadata_document_remove, permission_metadata_document_view, + permission_metadata_document_add, + permission_metadata_document_edit, + permission_metadata_document_remove, + permission_metadata_document_view, ) ) - SourceColumn(source=Document, label=_('Metadata'), attribute=encapsulate(lambda document: get_metadata_string(document))) + SourceColumn( + source=Document, label=_('Metadata'), + attribute=encapsulate( + lambda document: get_metadata_string(document) + ) + ) app.conf.CELERY_QUEUES.append( Queue('metadata', Exchange('metadata'), routing_key='metadata'), @@ -85,18 +113,66 @@ class MetadataApp(MayanAppConfig): } ) - document_search.add_model_field(field='metadata__metadata_type__name', label=_('Metadata type')) - document_search.add_model_field(field='metadata__value', label=_('Metadata value')) + document_search.add_model_field( + field='metadata__metadata_type__name', label=_('Metadata type') + ) + document_search.add_model_field( + field='metadata__value', label=_('Metadata value') + ) menu_facet.bind_links(links=[link_metadata_view], sources=[Document]) - menu_multi_item.bind_links(links=[link_metadata_multiple_add, link_metadata_multiple_edit, link_metadata_multiple_remove], sources=[Document]) - menu_object.bind_links(links=[link_setup_document_type_metadata, link_setup_document_type_metadata_required], sources=[DocumentType]) - menu_object.bind_links(links=[link_setup_metadata_type_edit, link_setup_metadata_type_delete], sources=[MetadataType]) - menu_secondary.bind_links(links=[link_setup_metadata_type_list, link_setup_metadata_type_create], sources=[MetadataType, 'metadata:setup_metadata_type_list', 'metadata:setup_metadata_type_create']) + menu_multi_item.bind_links( + links=[ + link_metadata_multiple_add, link_metadata_multiple_edit, + link_metadata_multiple_remove + ], sources=[Document] + ) + menu_object.bind_links( + links=[ + link_setup_document_type_metadata, + link_setup_document_type_metadata_required + ], sources=[DocumentType] + ) + menu_object.bind_links( + links=[ + link_setup_metadata_type_edit, + link_setup_metadata_type_delete + ], sources=[MetadataType] + ) + menu_secondary.bind_links( + links=[ + link_setup_metadata_type_list, + link_setup_metadata_type_create + ], sources=[ + MetadataType, 'metadata:setup_metadata_type_list', + 'metadata:setup_metadata_type_create' + ] + ) menu_setup.bind_links(links=[link_setup_metadata_type_list]) - menu_sidebar.bind_links(links=[link_metadata_add, link_metadata_edit, link_metadata_remove], sources=['metadata:metadata_add', 'metadata:metadata_edit', 'metadata:metadata_remove', 'metadata:metadata_view']) - menu_tools.bind_links(links=[link_documents_missing_required_metadata]) + menu_sidebar.bind_links( + links=[ + link_metadata_add, link_metadata_edit, link_metadata_remove + ], sources=[ + 'metadata:metadata_add', 'metadata:metadata_edit', + 'metadata:metadata_remove', 'metadata:metadata_view' + ] + ) + menu_tools.bind_links( + links=[link_documents_missing_required_metadata] + ) - post_delete.connect(post_document_type_metadata_type_delete, dispatch_uid='post_document_type_metadata_type_delete', sender=DocumentTypeMetadataType) - post_document_type_change.connect(post_post_document_type_change_metadata, dispatch_uid='post_post_document_type_change_metadata', sender=Document) - post_save.connect(post_document_type_metadata_type_add, dispatch_uid='post_document_type_metadata_type_add', sender=DocumentTypeMetadataType) + post_delete.connect( + post_document_type_metadata_type_delete, + dispatch_uid='post_document_type_metadata_type_delete', + sender=DocumentTypeMetadataType + ) + post_document_type_change.connect( + post_post_document_type_change_metadata, + dispatch_uid='post_post_document_type_change_metadata', + sender=Document + ) + post_save.connect( + post_document_type_metadata_type_add, + dispatch_uid='post_document_type_metadata_type_add', + sender=DocumentTypeMetadataType + ) diff --git a/mayan/apps/metadata/forms.py b/mayan/apps/metadata/forms.py index 2dce44d130..c107f0790e 100644 --- a/mayan/apps/metadata/forms.py +++ b/mayan/apps/metadata/forms.py @@ -3,11 +3,11 @@ from __future__ import unicode_literals from django import forms from django.core.exceptions import ValidationError from django.forms.formsets import formset_factory +from django.template import Context, Template from django.utils.module_loading import import_string from django.utils.translation import ugettext_lazy as _ from .models import MetadataType -from .settings import setting_available_functions, setting_available_models class MetadataForm(forms.Form): @@ -35,14 +35,19 @@ class MetadataForm(forms.Form): except AttributeError: message = unicode(exception) - raise ValidationError(_('Invalid value: %(message)s'), params={'message': message}, code='invalid') + raise ValidationError( + _('Invalid value: %(message)s'), params={ + 'message': message + }, code='invalid' + ) else: # Return the result if it was a parsing function - # If it was a validation function and passed correctly we return - # the original input value + # If it was a validation function and passed correctly + # we return the original input value return result or self.cleaned_data['value'] else: - # If a validator was never specified we return the original value + # If a validator was never specified we return the original + # value return self.cleaned_data['value'] def __init__(self, *args, **kwargs): @@ -60,12 +65,16 @@ class MetadataForm(forms.Form): else: self.fields['value'].required = False - self.fields['name'].initial = '%s%s' % ((self.metadata_type.label if self.metadata_type.label else self.metadata_type.name), required_string) + self.fields['name'].initial = '%s%s' % ( + (self.metadata_type.label if self.metadata_type.label else self.metadata_type.name), + required_string + ) self.fields['id'].initial = self.metadata_type.pk if self.metadata_type.lookup: try: - choices = eval(self.metadata_type.lookup, setting_available_models.value) + #choices = eval(self.metadata_type.lookup, setting_available_models.value) ##### + choices = [] self.fields['value'] = forms.ChoiceField(label=self.fields['value'].label) choices = zip(choices, choices) if not required: @@ -74,25 +83,39 @@ class MetadataForm(forms.Form): self.fields['value'].required = required except Exception as exception: self.fields['value'].initial = exception - self.fields['value'].widget = forms.TextInput(attrs={'readonly': 'readonly'}) + self.fields['value'].widget = forms.TextInput( + attrs={'readonly': 'readonly'} + ) if self.metadata_type.default: try: - self.fields['value'].initial = eval(self.metadata_type.default, setting_available_functions.value) + template = Template(self.metadata_type.default) + context = Context() + result = template.render(context=context) + self.fields['value'].initial = result except Exception as exception: - self.fields['value'].initial = exception + self.fields['value'].initial = _( + 'Error: %s' + ) % exception id = forms.CharField(label=_('ID'), widget=forms.HiddenInput) - name = forms.CharField(label=_('Name'), required=False, widget=forms.TextInput(attrs={'readonly': 'readonly'})) + name = forms.CharField( + label=_('Name'), required=False, + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) value = forms.CharField(label=_('Value'), required=False) - update = forms.BooleanField(initial=True, label=_('Update'), required=False) + update = forms.BooleanField( + initial=True, label=_('Update'), required=False + ) MetadataFormSet = formset_factory(MetadataForm, extra=0) class AddMetadataForm(forms.Form): - metadata_type = forms.ModelChoiceField(queryset=MetadataType.objects.all(), label=_('Metadata type')) + metadata_type = forms.ModelChoiceField( + queryset=MetadataType.objects.all(), label=_('Metadata type') + ) def __init__(self, *args, **kwargs): document_type = kwargs.pop('document_type') @@ -101,7 +124,9 @@ class AddMetadataForm(forms.Form): class MetadataRemoveForm(MetadataForm): - update = forms.BooleanField(initial=False, label=_('Remove'), required=False) + update = forms.BooleanField( + initial=False, label=_('Remove'), required=False + ) def __init__(self, *args, **kwargs): super(MetadataRemoveForm, self).__init__(*args, **kwargs) diff --git a/mayan/apps/metadata/handlers.py b/mayan/apps/metadata/handlers.py index 480d26c34b..9d559dbca2 100644 --- a/mayan/apps/metadata/handlers.py +++ b/mayan/apps/metadata/handlers.py @@ -12,12 +12,22 @@ def post_document_type_metadata_type_add(sender, instance, created, **kwargs): logger.debug('instance: %s', instance) if created and instance.required: - task_add_required_metadata_type.apply_async(kwargs={'document_type_id': instance.document_type.pk, 'metadata_type_id': instance.metadata_type.pk}) + task_add_required_metadata_type.apply_async( + kwargs={ + 'document_type_id': instance.document_type.pk, + 'metadata_type_id': instance.metadata_type.pk + } + ) def post_document_type_metadata_type_delete(sender, instance, **kwargs): logger.debug('instance: %s', instance) - task_remove_metadata_type.apply_async(kwargs={'document_type_id': instance.document_type.pk, 'metadata_type_id': instance.metadata_type.pk}) + task_remove_metadata_type.apply_async( + kwargs={ + 'document_type_id': instance.document_type.pk, + 'metadata_type_id': instance.metadata_type.pk + } + ) def post_post_document_type_change_metadata(sender, instance, **kwargs): @@ -29,4 +39,8 @@ def post_post_document_type_change_metadata(sender, instance, **kwargs): # Add new document type metadata types to document for document_type_metadata_type in instance.document_type.metadata.filter(required=True): - DocumentMetadata.objects.create(document=instance, metadata_type=document_type_metadata_type.metadata_type, value=None) + DocumentMetadata.objects.create( + document=instance, + metadata_type=document_type_metadata_type.metadata_type, + value=None + ) diff --git a/mayan/apps/metadata/models.py b/mayan/apps/metadata/models.py index c226d80fe6..ba49731c07 100644 --- a/mayan/apps/metadata/models.py +++ b/mayan/apps/metadata/models.py @@ -12,7 +12,10 @@ from .settings import setting_available_validators def validation_choices(): - return zip(setting_available_validators.value, setting_available_validators.value) + return zip( + setting_available_validators.value, + setting_available_validators.value + ) @python_2_unicode_compatible @@ -20,13 +23,28 @@ class MetadataType(models.Model): """ Define a type of metadata """ - name = models.CharField(max_length=48, help_text=_('Do not use python reserved words, or spaces.'), unique=True, verbose_name=_('Name')) + name = models.CharField( + max_length=48, + help_text=_('Name used by other apps to reference this value. Do not use python reserved words, or spaces.'), + unique=True, verbose_name=_('Name') + ) label = models.CharField(max_length=48, verbose_name=_('Label')) - default = models.CharField(blank=True, max_length=128, null=True, help_text=_('Enter a string to be evaluated.'), verbose_name=_('Default')) + default = models.CharField( + blank=True, max_length=128, null=True, + help_text=_('Enter a template to render. Use Django\'s default templating language (https://docs.djangoproject.com/en/1.7/ref/templates/builtins/)'), + verbose_name=_('Default') + ) # TODO: Add enable_lookup boolean to allow users to switch the lookup on and # off without losing the lookup expression - lookup = models.TextField(blank=True, null=True, help_text=_('Enter a string to be evaluated that returns an iterable.'), verbose_name=_('Lookup')) - validation = models.CharField(blank=True, choices=validation_choices(), max_length=64, verbose_name=_('Validation function name')) + lookup = models.TextField( + blank=True, null=True, + help_text=_('Enter a string to be evaluated that returns an iterable.'), + verbose_name=_('Lookup') + ) + validation = models.CharField( + blank=True, choices=validation_choices(), max_length=64, + verbose_name=_('Validation function name') + ) # TODO: Find a different way to let users know what models and functions are # available now that we removed these from the help_text objects = MetadataTypeManager() @@ -49,22 +67,31 @@ class DocumentMetadata(models.Model): Link a document to a specific instance of a metadata type with it's current value """ - document = models.ForeignKey(Document, related_name='metadata', verbose_name=_('Document')) + document = models.ForeignKey( + Document, related_name='metadata', verbose_name=_('Document') + ) metadata_type = models.ForeignKey(MetadataType, verbose_name=_('Type')) - value = models.CharField(blank=True, db_index=True, max_length=255, null=True, verbose_name=_('Value')) + value = models.CharField( + blank=True, db_index=True, max_length=255, null=True, + verbose_name=_('Value') + ) def __str__(self): return unicode(self.metadata_type) def save(self, *args, **kwargs): if self.metadata_type.pk not in self.document.document_type.metadata.values_list('metadata_type', flat=True): - raise ValidationError(_('Metadata type is not valid for this document type.')) + raise ValidationError( + _('Metadata type is not valid for this document type.') + ) return super(DocumentMetadata, self).save(*args, **kwargs) def delete(self, enforce_required=True, *args, **kwargs): if enforce_required and self.metadata_type.pk in self.document.document_type.metadata.filter(required=True).values_list('metadata_type', flat=True): - raise ValidationError(_('Metadata type is required for this document type.')) + raise ValidationError( + _('Metadata type is required for this document type.') + ) return super(DocumentMetadata, self).delete(*args, **kwargs) @@ -76,8 +103,13 @@ class DocumentMetadata(models.Model): @python_2_unicode_compatible class DocumentTypeMetadataType(models.Model): - document_type = models.ForeignKey(DocumentType, related_name='metadata', verbose_name=_('Document type')) - metadata_type = models.ForeignKey(MetadataType, verbose_name=_('Metadata type')) + document_type = models.ForeignKey( + DocumentType, related_name='metadata', + verbose_name=_('Document type') + ) + metadata_type = models.ForeignKey( + MetadataType, verbose_name=_('Metadata type') + ) required = models.BooleanField(default=False, verbose_name=_('Required')) def __str__(self): diff --git a/mayan/apps/metadata/serializers.py b/mayan/apps/metadata/serializers.py index d1988009a9..8fb9900b0a 100644 --- a/mayan/apps/metadata/serializers.py +++ b/mayan/apps/metadata/serializers.py @@ -28,9 +28,16 @@ class DocumentTypeMetadataTypeSerializer(serializers.ModelSerializer): class DocumentNewMetadataSerializer(serializers.Serializer): - metadata_type = serializers.IntegerField(help_text=_('Primary key of the metadata type to be added.')) - value = serializers.CharField(max_length=255, help_text=_('Value of the corresponding metadata type instance.')) + metadata_type = serializers.IntegerField( + help_text=_('Primary key of the metadata type to be added.') + ) + value = serializers.CharField( + max_length=255, + help_text=_('Value of the corresponding metadata type instance.') + ) class DocumentTypeNewMetadataTypeSerializer(serializers.Serializer): - metadata_type = serializers.IntegerField(help_text=_('Primary key of the metadata type to be added.')) + metadata_type = serializers.IntegerField( + help_text=_('Primary key of the metadata type to be added.') + ) diff --git a/mayan/apps/metadata/settings.py b/mayan/apps/metadata/settings.py index c03347a4e2..39710e82b6 100644 --- a/mayan/apps/metadata/settings.py +++ b/mayan/apps/metadata/settings.py @@ -1,22 +1,13 @@ from __future__ import unicode_literals -from django.contrib.auth.models import User -from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from smart_settings import Namespace from .validators import MetadataValidator -default_available_functions = { - 'current_date': now().date, -} - -default_available_models = { - 'User': User -} - namespace = Namespace(name='metadata', label=_('Metadata')) -setting_available_validators = namespace.add_setting(global_name='METADATA_AVAILABLE_VALIDATORS', default=MetadataValidator.get_import_paths()) -setting_available_functions = namespace.add_setting(global_name='METADATA_AVAILABLE_FUNCTIONS', default=default_available_functions) -setting_available_models = namespace.add_setting(global_name='METADATA_AVAILABLE_MODELS', default=default_available_models) +setting_available_validators = namespace.add_setting( + global_name='METADATA_AVAILABLE_VALIDATORS', + default=MetadataValidator.get_import_paths() +) diff --git a/mayan/apps/metadata/tasks.py b/mayan/apps/metadata/tasks.py index fcc1a8cdf5..be2540cc0f 100644 --- a/mayan/apps/metadata/tasks.py +++ b/mayan/apps/metadata/tasks.py @@ -11,7 +11,10 @@ logger = logging.getLogger(__name__) @app.task(ignore_result=True) def task_remove_metadata_type(document_type_id, metadata_type_id): - DocumentMetadata.objects.filter(document__document_type__id=document_type_id, metadata_type__id=metadata_type_id).delete() + DocumentMetadata.objects.filter( + document__document_type__id=document_type_id, + metadata_type__id=metadata_type_id + ).delete() @app.task(ignore_result=True) diff --git a/mayan/apps/metadata/urls.py b/mayan/apps/metadata/urls.py index 7bc6fd6533..1fe36d0e49 100644 --- a/mayan/apps/metadata/urls.py +++ b/mayan/apps/metadata/urls.py @@ -12,37 +12,101 @@ from .api_views import ( from .views import ( MetadataTypeCreateView, MetadataTypeDeleteView, MetadataTypeEditView, MetadataTypeListView, MissingRequiredMetadataDocumentListView, - SetupDocumentTypeMetadataOptionalView, SetupDocumentTypeMetadataRequiredView + SetupDocumentTypeMetadataOptionalView, + SetupDocumentTypeMetadataRequiredView ) urlpatterns = patterns( 'metadata.views', url(r'^(?P\d+)/edit/$', 'metadata_edit', name='metadata_edit'), - url(r'^(?P\d+)/view/$', 'metadata_view', name='metadata_view'), - url(r'^multiple/edit/$', 'metadata_multiple_edit', name='metadata_multiple_edit'), + url( + r'^(?P\d+)/view/$', 'metadata_view', + name='metadata_view' + ), + url( + r'^multiple/edit/$', 'metadata_multiple_edit', + name='metadata_multiple_edit' + ), url(r'^(?P\d+)/add/$', 'metadata_add', name='metadata_add'), - url(r'^multiple/add/$', 'metadata_multiple_add', name='metadata_multiple_add'), - url(r'^(?P\d+)/remove/$', 'metadata_remove', name='metadata_remove'), - url(r'^multiple/remove/$', 'metadata_multiple_remove', name='metadata_multiple_remove'), + url( + r'^multiple/add/$', 'metadata_multiple_add', + name='metadata_multiple_add' + ), + url( + r'^(?P\d+)/remove/$', 'metadata_remove', + name='metadata_remove' + ), + url( + r'^multiple/remove/$', 'metadata_multiple_remove', + name='metadata_multiple_remove' + ), - url(r'^setup/type/list/$', MetadataTypeListView.as_view(), name='setup_metadata_type_list'), - url(r'^setup/type/create/$', MetadataTypeCreateView.as_view(), name='setup_metadata_type_create'), - url(r'^setup/type/(?P\d+)/edit/$', MetadataTypeEditView.as_view(), name='setup_metadata_type_edit'), - url(r'^setup/type/(?P\d+)/delete/$', MetadataTypeDeleteView.as_view(), name='setup_metadata_type_delete'), + url( + r'^setup/type/list/$', MetadataTypeListView.as_view(), + name='setup_metadata_type_list' + ), + url( + r'^setup/type/create/$', MetadataTypeCreateView.as_view(), + name='setup_metadata_type_create' + ), + url( + r'^setup/type/(?P\d+)/edit/$', MetadataTypeEditView.as_view(), + name='setup_metadata_type_edit' + ), + url( + r'^setup/type/(?P\d+)/delete/$', + MetadataTypeDeleteView.as_view(), name='setup_metadata_type_delete' + ), - url(r'^setup/document/type/(?P\d+)/metadata/edit/$', SetupDocumentTypeMetadataOptionalView.as_view(), name='setup_document_type_metadata'), - url(r'^setup/document/type/(?P\d+)/metadata/edit/required/$', SetupDocumentTypeMetadataRequiredView.as_view(), name='setup_document_type_metadata_required'), + url( + r'^setup/document/type/(?P\d+)/metadata/edit/$', + SetupDocumentTypeMetadataOptionalView.as_view(), + name='setup_document_type_metadata' + ), + url( + r'^setup/document/type/(?P\d+)/metadata/edit/required/$', + SetupDocumentTypeMetadataRequiredView.as_view(), + name='setup_document_type_metadata_required' + ), - url(r'^tools/missing_required_metadata/$', MissingRequiredMetadataDocumentListView.as_view(), name='documents_missing_required_metadata'), + url( + r'^tools/missing_required_metadata/$', + MissingRequiredMetadataDocumentListView.as_view(), + name='documents_missing_required_metadata' + ), ) api_urls = patterns( '', - url(r'^metadatatypes/$', APIMetadataTypeListView.as_view(), name='metadatatype-list'), - url(r'^metadatatypes/(?P[0-9]+)/$', APIMetadataTypeView.as_view(), name='metadatatype-detail'), - url(r'^document/metadata/(?P[0-9]+)/$', APIDocumentMetadataView.as_view(), name='documentmetadata-detail'), - url(r'^document/(?P[0-9]+)/metadata/$', APIDocumentMetadataListView.as_view(), name='documentmetadata-list'), - url(r'^document_type/(?P[0-9]+)/metadatatypes/optional/$', APIDocumentTypeMetadataTypeOptionalListView.as_view(), name='documenttypemetadatatype-list'), - url(r'^document_type/(?P[0-9]+)/metadatatypes/required/$', APIDocumentTypeMetadataTypeRequiredListView.as_view(), name='documenttypemetadatatype-list'), - url(r'^document_type/(?P[0-9]+)/metadatatypes/(?P[0-9]+)/$', APIDocumentTypeMetadataTypeRequiredView.as_view(), name='documenttypemetadatatype-detail'), + url( + r'^metadatatypes/$', APIMetadataTypeListView.as_view(), + name='metadatatype-list' + ), + url( + r'^metadatatypes/(?P[0-9]+)/$', APIMetadataTypeView.as_view(), + name='metadatatype-detail' + ), + url( + r'^document/metadata/(?P[0-9]+)/$', + APIDocumentMetadataView.as_view(), name='documentmetadata-detail' + ), + url( + r'^document/(?P[0-9]+)/metadata/$', + APIDocumentMetadataListView.as_view(), name='documentmetadata-list' + ), + url( + r'^document_type/(?P[0-9]+)/metadatatypes/optional/$', + APIDocumentTypeMetadataTypeOptionalListView.as_view(), + name='documenttypemetadatatype-list' + ), + url( + r'^document_type/(?P[0-9]+)/metadatatypes/required/$', + APIDocumentTypeMetadataTypeRequiredListView.as_view(), + name='documenttypemetadatatype-list' + ), + url( + r'^document_type/(?P[0-9]+)/metadatatypes/(?P[0-9]+)/$', + APIDocumentTypeMetadataTypeRequiredView.as_view(), + name='documenttypemetadatatype-detail' + ), ) diff --git a/mayan/apps/metadata/views.py b/mayan/apps/metadata/views.py index 087f885769..773b74eadf 100644 --- a/mayan/apps/metadata/views.py +++ b/mayan/apps/metadata/views.py @@ -41,30 +41,47 @@ class MissingRequiredMetadataDocumentListView(DocumentListView): } def get_document_queryset(self): - return Document.objects.filter(document_type__metadata__required=True, metadata__value__isnull=True) + return Document.objects.filter( + document_type__metadata__required=True, + metadata__value__isnull=True + ) def metadata_edit(request, document_id=None, document_id_list=None): if document_id: document_id_list = unicode(document_id) - documents = Document.objects.select_related('metadata').filter(pk__in=document_id_list.split(',')) + documents = Document.objects.select_related('metadata').filter( + pk__in=document_id_list.split(',') + ) try: - Permission.check_permissions(request.user, [permission_metadata_document_edit]) + Permission.check_permissions( + request.user, [permission_metadata_document_edit] + ) except PermissionDenied: - documents = AccessControlList.objects.filter_by_access(permission_metadata_document_edit, request.user, documents) + documents = AccessControlList.objects.filter_by_access( + permission_metadata_document_edit, request.user, documents + ) if not documents: if document_id: raise Http404 else: messages.error(request, _('Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))) + return HttpResponseRedirect( + request.META.get( + 'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL) + ) + ) if len(set([document.document_type.pk for document in documents])) > 1: messages.error(request, _('Only select documents of the same type.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))) + return HttpResponseRedirect( + request.META.get( + 'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL) + ) + ) if set(documents.values_list('metadata__value', flat=True)) == set([None]): message = ungettext( @@ -73,11 +90,19 @@ def metadata_edit(request, document_id=None, document_id_list=None): len(documents) ) messages.warning(request, message) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))) + return HttpResponseRedirect( + request.META.get( + 'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL) + ) + ) post_action_redirect = reverse('documents:document_list_recent') - next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', post_action_redirect))) + next = request.POST.get( + 'next', request.GET.get( + 'next', request.META.get('HTTP_REFERER', post_action_redirect) + ) + ) metadata = {} initial = [] @@ -97,7 +122,9 @@ def metadata_edit(request, document_id=None, document_id_list=None): initial.append({ 'metadata_type': key, 'value': ', '.join(value) if value else '', - 'required': key in document.document_type.metadata.filter(required=True), + 'required': key in document.document_type.metadata.filter( + required=True + ), }) formset = MetadataFormSet(initial=initial) @@ -119,10 +146,19 @@ def metadata_edit(request, document_id=None, document_id_list=None): if settings.DEBUG: raise else: - messages.error(request, _('Error editing metadata for document %(document)s; %(exception)s.') % { - 'document': document, 'exception': ', '.join(exception.messages)}) + messages.error( + request, _( + 'Error editing metadata for document %(document)s; %(exception)s.' + ) % { + 'document': document, + 'exception': ', '.join(exception.messages) + } + ) else: - messages.success(request, _('Metadata for document %s edited successfully.') % document) + messages.success( + request, + _('Metadata for document %s edited successfully.') % document + ) return HttpResponseRedirect(next) @@ -146,54 +182,102 @@ def metadata_edit(request, document_id=None, document_id_list=None): def metadata_multiple_edit(request): - return metadata_edit(request, document_id_list=request.GET.get('id_list', '')) + return metadata_edit( + request, document_id_list=request.GET.get('id_list', '') + ) def metadata_add(request, document_id=None, document_id_list=None): if document_id: documents = [get_object_or_404(Document, pk=document_id)] elif document_id_list: - documents = [get_object_or_404(Document.objects.select_related('document_type'), pk=document_id) for document_id in document_id_list.split(',')] + documents = [ + get_object_or_404(Document.objects.select_related('document_type'), pk=document_id) for document_id in document_id_list.split(',') + ] if len(set([document.document_type.pk for document in documents])) > 1: - messages.error(request, _('Only select documents of the same type.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))) + messages.error( + request, _('Only select documents of the same type.') + ) + return HttpResponseRedirect( + request.META.get( + 'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL) + ) + ) try: - Permission.check_permissions(request.user, [permission_metadata_document_add]) + Permission.check_permissions( + request.user, [permission_metadata_document_add] + ) except PermissionDenied: - documents = AccessControlList.objects.filter_by_access(permission_metadata_document_add, request.user, documents) + documents = AccessControlList.objects.filter_by_access( + permission_metadata_document_add, request.user, documents + ) if not documents: messages.error(request, _('Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))) + return HttpResponseRedirect( + request.META.get( + 'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL) + ) + ) for document in documents: document.add_as_recent_document_for_user(request.user) post_action_redirect = reverse('documents:document_list_recent') - next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', post_action_redirect))) + next = request.POST.get( + 'next', + request.GET.get( + 'next', request.META.get('HTTP_REFERER', post_action_redirect) + ) + ) if request.method == 'POST': - form = AddMetadataForm(data=request.POST, document_type=document.document_type) + form = AddMetadataForm( + data=request.POST, document_type=document.document_type + ) if form.is_valid(): metadata_type = form.cleaned_data['metadata_type'] for document in documents: try: - document_metadata, created = DocumentMetadata.objects.get_or_create(document=document, metadata_type=metadata_type.metadata_type, defaults={'value': ''}) + document_metadata, created = DocumentMetadata.objects.get_or_create( + document=document, + metadata_type=metadata_type.metadata_type, + defaults={'value': ''} + ) except Exception as exception: if getattr(settings, 'DEBUG', False): raise else: - messages.error(request, _('Error adding metadata type "%(metadata_type)s" to document: %(document)s; %(exception)s') % { - 'metadata_type': metadata_type, 'document': document, 'exception': ', '.join(getattr(exception, 'messages', exception))}) + messages.error( + request, + _( + 'Error adding metadata type "%(metadata_type)s" to document: %(document)s; %(exception)s' + ) % { + 'metadata_type': metadata_type, + 'document': document, + 'exception': ', '.join(getattr(exception, 'messages', exception)) + } + ) else: if created: - messages.success(request, _('Metadata type: %(metadata_type)s successfully added to document %(document)s.') % { - 'metadata_type': metadata_type, 'document': document}) + messages.success( + request, + _( + 'Metadata type: %(metadata_type)s successfully added to document %(document)s.' + ) % { + 'metadata_type': metadata_type, 'document': document + } + ) else: - messages.warning(request, _('Metadata type: %(metadata_type)s already present in document %(document)s.') % { - 'metadata_type': metadata_type, 'document': document}) + messages.warning( + request, _( + 'Metadata type: %(metadata_type)s already present in document %(document)s.' + ) % { + 'metadata_type': metadata_type, 'document': document + } + ) if len(documents) == 1: return HttpResponseRedirect('%s?%s' % ( @@ -228,30 +312,46 @@ def metadata_add(request, document_id=None, document_id_list=None): def metadata_multiple_add(request): - return metadata_add(request, document_id_list=request.GET.get('id_list', [])) + return metadata_add( + request, document_id_list=request.GET.get('id_list', []) + ) def metadata_remove(request, document_id=None, document_id_list=None): if document_id: document_id_list = unicode(document_id) - documents = Document.objects.select_related('metadata').filter(pk__in=document_id_list.split(',')) + documents = Document.objects.select_related('metadata').filter( + pk__in=document_id_list.split(',') + ) try: - Permission.check_permissions(request.user, [permission_metadata_document_remove]) + Permission.check_permissions( + request.user, [permission_metadata_document_remove] + ) except PermissionDenied: - documents = AccessControlList.objects.filter_by_access(permission_metadata_document_remove, request.user, documents) + documents = AccessControlList.objects.filter_by_access( + permission_metadata_document_remove, request.user, documents + ) if not documents: if document_id: raise Http404 else: messages.error(request, _('Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))) + return HttpResponseRedirect( + request.META.get( + 'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL) + ) + ) if len(set([document.document_type.pk for document in documents])) > 1: messages.error(request, _('Only select documents of the same type.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))) + return HttpResponseRedirect( + request.META.get( + 'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL) + ) + ) if set(documents.values_list('metadata__value', flat=True)) == set([None]): message = ungettext( @@ -260,7 +360,11 @@ def metadata_remove(request, document_id=None, document_id_list=None): len(documents) ) messages.warning(request, message) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))) + return HttpResponseRedirect( + request.META.get( + 'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL) + ) + ) post_action_redirect = reverse('documents:document_list_recent') @@ -413,20 +517,36 @@ class SetupDocumentTypeMetadataOptionalView(AssignRemoveView): return get_object_or_404(DocumentType, pk=self.kwargs['pk']) def left_list(self): - return AssignRemoveView.generate_choices(set(MetadataType.objects.all()) - set(MetadataType.objects.filter(id__in=self.get_object().metadata.values_list('metadata_type', flat=True)))) + return AssignRemoveView.generate_choices( + set(MetadataType.objects.all()) - set( + MetadataType.objects.filter( + id__in=self.get_object().metadata.values_list( + 'metadata_type', flat=True + ) + ) + ) + ) def right_list(self): - return AssignRemoveView.generate_choices(self.get_object().metadata.filter(required=False)) + return AssignRemoveView.generate_choices( + self.get_object().metadata.filter(required=False) + ) def remove(self, item): item.delete() def get_context_data(self, **kwargs): - data = super(SetupDocumentTypeMetadataOptionalView, self).get_context_data(**kwargs) - data.update({ - 'object': self.get_object(), - 'title': _('Optional metadata types for document type: %s') % self.get_object(), - }) + data = super( + SetupDocumentTypeMetadataOptionalView, self + ).get_context_data(**kwargs) + data.update( + { + 'object': self.get_object(), + 'title': _( + 'Optional metadata types for document type: %s' + ) % self.get_object(), + } + ) return data @@ -436,13 +556,21 @@ class SetupDocumentTypeMetadataRequiredView(SetupDocumentTypeMetadataOptionalVie self.get_object().metadata.create(metadata_type=item, required=True) def right_list(self): - return AssignRemoveView.generate_choices(self.get_object().metadata.filter(required=True)) + return AssignRemoveView.generate_choices( + self.get_object().metadata.filter(required=True) + ) def get_context_data(self, **kwargs): - data = super(SetupDocumentTypeMetadataRequiredView, self).get_context_data(**kwargs) - data.update({ - 'object': self.get_object(), - 'title': _('Required metadata types for document type: %s') % self.get_object(), - }) + data = super( + SetupDocumentTypeMetadataRequiredView, self + ).get_context_data(**kwargs) + data.update( + { + 'object': self.get_object(), + 'title': _( + 'Required metadata types for document type: %s' + ) % self.get_object(), + } + ) return data