diff --git a/HISTORY.rst b/HISTORY.rst index 13fb1a84fa..b7cc16a8f1 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -38,6 +38,11 @@ - Add new document app events: document type created and document type edited. - Add link to document type events. +- Add new metadata app events: metadata type created, metadata type edited, + metadata type to document type relationship update. +- Add link to metadata type events. +- Add support for subscribing to metadata type events. + 3.0.1 (2018-07-08) ================= diff --git a/mayan/apps/metadata/apps.py b/mayan/apps/metadata/apps.py index a5163f4538..9f2cdb47a6 100644 --- a/mayan/apps/metadata/apps.py +++ b/mayan/apps/metadata/apps.py @@ -1,4 +1,4 @@ -from __future__ import unicode_literals +from __future__ import absolute_import, unicode_literals import logging @@ -17,10 +17,20 @@ from common.classes import ModelAttribute from common.widgets import TwoStateWidget from documents.search import document_page_search, document_search from documents.signals import post_document_type_change +from events import ModelEventType +from events.links import ( + link_events_for_object, link_object_event_types_user_subcriptions_list, + link_object_event_types_user_subcriptions_list_with_icon +) +from events.permissions import permission_events_view from mayan.celery import app from navigation import SourceColumn from .classes import DocumentMetadataHelper +from .events import ( + event_metadata_type_created, event_metadata_type_edited, + event_metadata_type_relationship +) from .handlers import ( handler_index_document, post_document_type_metadata_type_add, post_document_type_metadata_type_delete, @@ -56,6 +66,7 @@ class MetadataApp(MayanAppConfig): def ready(self): super(MetadataApp, self).ready() + from actstream import registry from .wizard_steps import WizardStepMetadata # NOQA @@ -101,6 +112,13 @@ class MetadataApp(MayanAppConfig): type_name=['property', 'indexing'] ) + ModelEventType.register( + model=MetadataType, event_types=( + event_metadata_type_edited, + event_metadata_type_relationship, + ) + ) + ModelPermission.register( model=Document, permissions=( permission_metadata_document_add, @@ -111,6 +129,7 @@ class MetadataApp(MayanAppConfig): ) ModelPermission.register( model=MetadataType, permissions=( + permission_events_view, permission_metadata_type_delete, permission_metadata_type_edit, permission_metadata_type_view @@ -187,7 +206,9 @@ class MetadataApp(MayanAppConfig): links=( link_setup_metadata_type_edit, link_setup_metadata_type_document_types, - link_setup_metadata_type_delete + link_object_event_types_user_subcriptions_list, + link_events_for_object, + link_setup_metadata_type_delete, ), sources=(MetadataType,) ) menu_secondary.bind_links( @@ -237,3 +258,6 @@ class MetadataApp(MayanAppConfig): dispatch_uid='metadata_handler_index_document_save', sender=DocumentMetadata ) + + registry.register(MetadataType) + registry.register(DocumentTypeMetadataType) diff --git a/mayan/apps/metadata/events.py b/mayan/apps/metadata/events.py new file mode 100644 index 0000000000..628324eb4f --- /dev/null +++ b/mayan/apps/metadata/events.py @@ -0,0 +1,19 @@ +from __future__ import absolute_import, unicode_literals + +from django.utils.translation import ugettext_lazy as _ + +from events import EventTypeNamespace + +namespace = EventTypeNamespace(name='metadata', label=_('Metadata')) + +event_metadata_type_created = namespace.add_event_type( + name='metadata_type_created', label=_('Metadata type created') +) +event_metadata_type_edited = namespace.add_event_type( + name='metadata_type_edited', label=_('Metadata type edited') +) +event_metadata_type_relationship = namespace.add_event_type( + name='metadata_type_relationship', label=_( + 'Metadata type relationship updated' + ) +) diff --git a/mayan/apps/metadata/forms.py b/mayan/apps/metadata/forms.py index c09c065bd8..5b75af038a 100644 --- a/mayan/apps/metadata/forms.py +++ b/mayan/apps/metadata/forms.py @@ -6,7 +6,7 @@ from django.forms.formsets import formset_factory from django.utils.translation import string_concat, ugettext_lazy as _ from .classes import MetadataLookup -from .models import MetadataType +from .models import DocumentTypeMetadataType, MetadataType class DocumentMetadataForm(forms.Form): @@ -172,69 +172,107 @@ DocumentMetadataRemoveFormSet = formset_factory( ) + class DocumentTypeMetadataTypeRelationshipForm(forms.Form): + RELATIONSHIP_TYPE_NONE = 'none' + RELATIONSHIP_TYPE_OPTIONAL = 'optional' + RELATIONSHIP_TYPE_REQUIRED = 'required' + RELATIONSHIP_CHOICES = ( + (RELATIONSHIP_TYPE_NONE, _('None')), + (RELATIONSHIP_TYPE_OPTIONAL, _('Optional')), + (RELATIONSHIP_TYPE_REQUIRED, _('Required')), + ) + label = forms.CharField( label=_('Label'), required=False, widget=forms.TextInput(attrs={'readonly': 'readonly'}) ) - relationship = forms.ChoiceField( + relationship_type = forms.ChoiceField( label=_('Relationship'), - widget=forms.RadioSelect(), choices=( - ('none', _('None')), - ('optional', _('Optional')), - ('required', _('Required')), - ) + widget=forms.RadioSelect(), choices=RELATIONSHIP_CHOICES ) def __init__(self, *args, **kwargs): + self._user = kwargs.pop('_user') super(DocumentTypeMetadataTypeRelationshipForm, self).__init__( *args, **kwargs ) + if 'main_model' in self.initial: if self.initial['main_model'] == 'metadata_type': self.fields['label'].initial = self.initial['document_type'].label else: self.fields['label'].initial = self.initial['metadata_type'].label - relationship = self.initial['document_type'].metadata.filter( - metadata_type=self.initial['metadata_type'] - ) - if relationship.exists(): - if relationship.get().required: - self.fields['relationship'].initial = 'required' - else: - self.fields['relationship'].initial = 'optional' - else: - self.fields['relationship'].initial = 'none' + self.initial_relationship_type = self.get_relationship_type() + self.fields['relationship_type'].initial = self.initial_relationship_type - def save(self): - relationship = self.initial['document_type'].metadata.filter( + def get_relationship(self): + return self.initial['document_type'].metadata.filter( metadata_type=self.initial['metadata_type'] ) - if self.cleaned_data['relationship'] == 'none': - relationship.delete() - elif self.cleaned_data['relationship'] == 'optional': - if relationship.exists(): - instance = relationship.get() - instance.required = False - instance.save() + + def get_relationship_choices(self): + return self.initial['document_type'].metadata.filter( + metadata_type=self.initial['metadata_type'] + ) + + def get_relationship_type(self): + relationship = self.get_relationship() + + if relationship.exists(): + if relationship.get().required: + return self.RELATIONSHIP_TYPE_REQUIRED else: - relationship.create( - document_type=self.initial['document_type'], - metadata_type=self.initial['metadata_type'] - ) - elif self.cleaned_data['relationship'] == 'required': - if relationship.exists(): - instance = relationship.get() - instance.required = True - instance.save() - else: - relationship.create( - document_type=self.initial['document_type'], - metadata_type=self.initial['metadata_type'], required=True + return self.RELATIONSHIP_TYPE_OPTIONAL + else: + return self.RELATIONSHIP_TYPE_NONE + + def save(self): + relationship = self.get_relationship() + + if self.cleaned_data['relationship_type'] != self.initial_relationship_type: + getattr( + self, 'save_relationship_{}'.format( + self.cleaned_data['relationship_type'] ) + )(relationship=relationship) + + def save_relationship_none(self, relationship): + relationship.get().delete(_user=self._user) + + def save_relationship_optional(self, relationship): + if relationship.exists(): + instance = relationship.get() + instance.required = False + instance.save(_user=self._user) + else: + relationship = DocumentTypeMetadataType( + document_type=self.initial['document_type'], + metadata_type=self.initial['metadata_type'], + ) + relationship.save(_user=self._user) + + def save_relationship_required(self, relationship): + if relationship.exists(): + instance = relationship.get() + instance.required = True + instance.save(_user=self._user) + else: + relationship = DocumentTypeMetadataType( + document_type=self.initial['document_type'], + metadata_type=self.initial['metadata_type'], + required=True, + ) + relationship.save(_user=self._user) -DocumentTypeMetadataTypeRelationshipFormSet = formset_factory( +DocumentTypeMetadataTypeRelationshipFormSetBase = formset_factory( DocumentTypeMetadataTypeRelationshipForm, extra=0 ) + +class DocumentTypeMetadataTypeRelationshipFormSet(DocumentTypeMetadataTypeRelationshipFormSetBase): + def __init__(self, *args, **kwargs): + _user = kwargs.pop('_user') + super(DocumentTypeMetadataTypeRelationshipFormSet, self).__init__(*args, **kwargs) + self.form_kwargs.update({'_user': _user}) diff --git a/mayan/apps/metadata/models.py b/mayan/apps/metadata/models.py index be67f0093b..1dce6d3dc0 100644 --- a/mayan/apps/metadata/models.py +++ b/mayan/apps/metadata/models.py @@ -12,6 +12,10 @@ from django.utils.translation import ugettext_lazy as _ from documents.models import Document, DocumentType from .classes import MetadataLookup +from .events import ( + event_metadata_type_created, event_metadata_type_edited, + event_metadata_type_relationship +) from .managers import DocumentTypeMetadataTypeManager, MetadataTypeManager from .settings import setting_available_parsers, setting_available_validators @@ -113,6 +117,23 @@ class MetadataType(models.Model): def natural_key(self): return (self.name,) + def save(self, *args, **kwargs): + user = kwargs.pop('_user', None) + created = not self.pk + + result = super(MetadataType, self).save(*args, **kwargs) + + if created: + event_metadata_type_created.commit( + actor=user, target=self + ) + else: + event_metadata_type_edited.commit( + actor=user, target=self + ) + + return result + def validate_value(self, document_type, value): # Check default if not value and self.default: @@ -230,3 +251,25 @@ class DocumentTypeMetadataType(models.Model): def __str__(self): return force_text(self.metadata_type) + + def delete(self, *args, **kwargs): + user = kwargs.pop('_user', None) + + result = super(DocumentTypeMetadataType, self).delete(*args, **kwargs) + + event_metadata_type_relationship.commit( + action_object=self.document_type, actor=user, target=self.metadata_type, + ) + + return result + + def save(self, *args, **kwargs): + user = kwargs.pop('_user', None) + + result = super(DocumentTypeMetadataType, self).save(*args, **kwargs) + + event_metadata_type_relationship.commit( + action_object=self.document_type, actor=user, target=self.metadata_type, + ) + + return result diff --git a/mayan/apps/metadata/views.py b/mayan/apps/metadata/views.py index f410a5adb6..b0b89339d0 100644 --- a/mayan/apps/metadata/views.py +++ b/mayan/apps/metadata/views.py @@ -519,6 +519,11 @@ class MetadataTypeCreateView(SingleObjectCreateView): post_action_redirect = reverse_lazy('metadata:setup_metadata_type_list') view_permission = permission_metadata_type_create + def get_save_extra_data(self): + return { + '_user': self.request.user, + } + class MetadataTypeDeleteView(SingleObjectDeleteView): model = MetadataType @@ -545,6 +550,11 @@ class MetadataTypeEditView(SingleObjectEditView): 'title': _('Edit metadata type: %s') % self.get_object(), } + def get_save_extra_data(self): + return { + '_user': self.request.user, + } + class MetadataTypeListView(SingleObjectListView): view_permission = permission_metadata_type_view @@ -590,6 +600,11 @@ class SetupDocumentTypeMetadataTypes(FormView): SetupDocumentTypeMetadataTypes, self ).form_valid(form=form) + def get_form_extra_kwargs(self): + return { + '_user': self.request.user, + } + def get_object(self): return get_object_or_404(self.model, pk=self.kwargs['pk'])