Update smart link document type view use AddRemove
Add smart link created and edited events. Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
@@ -194,7 +194,10 @@
|
||||
from the AddRemoveView.
|
||||
* Add view to link document type and indexes from the document
|
||||
type side.
|
||||
|
||||
* Update smart link document type selection view to use
|
||||
AddRemoveView class.
|
||||
* Add smart link created and edited events.
|
||||
|
||||
3.1.11 (2019-04-XX)
|
||||
===================
|
||||
* Fix multiple tag selection wizard step.
|
||||
|
||||
@@ -226,6 +226,9 @@ Other changes
|
||||
from the AddRemoveView.
|
||||
* Add view to link document type and indexes from the document
|
||||
type side.
|
||||
* Update smart link document type selection view to use
|
||||
AddRemoveView class.
|
||||
* Add smart link created and edited events.
|
||||
|
||||
Removals
|
||||
--------
|
||||
|
||||
@@ -11,8 +11,13 @@ from mayan.apps.common.html_widgets import TwoStateWidget
|
||||
from mayan.apps.common.menus import (
|
||||
menu_facet, menu_list_facet, menu_object, menu_secondary, menu_setup
|
||||
)
|
||||
from mayan.apps.events.classes import ModelEventType
|
||||
from mayan.apps.events.links import (
|
||||
link_events_for_object, link_object_event_types_user_subcriptions_list
|
||||
)
|
||||
from mayan.apps.navigation.classes import SourceColumn
|
||||
|
||||
from .events import event_smart_link_created, event_smart_link_edited
|
||||
from .links import (
|
||||
link_smart_link_create, link_smart_link_condition_create,
|
||||
link_smart_link_condition_delete, link_smart_link_condition_edit,
|
||||
@@ -37,6 +42,7 @@ class LinkingApp(MayanAppConfig):
|
||||
|
||||
def ready(self):
|
||||
super(LinkingApp, self).ready()
|
||||
from actstream import registry
|
||||
|
||||
Document = apps.get_model(
|
||||
app_label='documents', model_name='Document'
|
||||
@@ -46,6 +52,12 @@ class LinkingApp(MayanAppConfig):
|
||||
SmartLink = self.get_model(model_name='SmartLink')
|
||||
SmartLinkCondition = self.get_model(model_name='SmartLinkCondition')
|
||||
|
||||
ModelEventType.register(
|
||||
event_types=(
|
||||
event_smart_link_created, event_smart_link_edited
|
||||
), model=SmartLink
|
||||
)
|
||||
|
||||
ModelPermission.register(
|
||||
model=SmartLink, permissions=(
|
||||
permission_acl_edit, permission_acl_view,
|
||||
@@ -79,7 +91,9 @@ class LinkingApp(MayanAppConfig):
|
||||
)
|
||||
menu_list_facet.bind_links(
|
||||
links=(
|
||||
link_acl_list, link_smart_link_document_types,
|
||||
link_acl_list, link_events_for_object,
|
||||
link_smart_link_document_types,
|
||||
link_object_event_types_user_subcriptions_list,
|
||||
link_smart_link_condition_list,
|
||||
), sources=(SmartLink,)
|
||||
)
|
||||
@@ -115,3 +129,5 @@ class LinkingApp(MayanAppConfig):
|
||||
)
|
||||
)
|
||||
menu_setup.bind_links(links=(link_smart_link_setup,))
|
||||
|
||||
registry.register(SmartLink)
|
||||
|
||||
16
mayan/apps/linking/events.py
Normal file
16
mayan/apps/linking/events.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from mayan.apps.events.classes import EventTypeNamespace
|
||||
|
||||
namespace = EventTypeNamespace(
|
||||
label=_('Smart links'), name='linking'
|
||||
)
|
||||
|
||||
event_smart_link_created = namespace.add_event_type(
|
||||
label=_('Smart link created'), name='smart_link_created'
|
||||
)
|
||||
event_smart_link_edited = namespace.add_event_type(
|
||||
label=_('Smart link edited'), name='smart_link_edited'
|
||||
)
|
||||
@@ -1,13 +1,15 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.db.models import Q
|
||||
from django.template import Context, Template
|
||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from mayan.apps.documents.events import event_document_type_edited
|
||||
from mayan.apps.documents.models import Document, DocumentType
|
||||
|
||||
from .events import event_smart_link_created, event_smart_link_edited
|
||||
from .literals import (
|
||||
INCLUSION_AND, INCLUSION_CHOICES, INCLUSION_OR, OPERATOR_CHOICES
|
||||
)
|
||||
@@ -47,6 +49,28 @@ class SmartLink(models.Model):
|
||||
def __str__(self):
|
||||
return self.label
|
||||
|
||||
def document_types_add(self, queryset, _user=None):
|
||||
with transaction.atomic():
|
||||
event_smart_link_edited.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
for obj in queryset:
|
||||
self.document_types.add(obj)
|
||||
event_document_type_edited.commit(
|
||||
actor=_user, action_object=self, target=obj
|
||||
)
|
||||
|
||||
def document_types_remove(self, queryset, _user=None):
|
||||
with transaction.atomic():
|
||||
event_smart_link_edited.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
for obj in queryset:
|
||||
self.document_types.remove(obj)
|
||||
event_document_type_edited.commit(
|
||||
actor=_user, action_object=self, target=obj
|
||||
)
|
||||
|
||||
def get_dynamic_label(self, document):
|
||||
"""
|
||||
If the smart links was created using a template label instead of a
|
||||
@@ -111,6 +135,21 @@ class SmartLink(models.Model):
|
||||
)
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
_user = kwargs.pop('_user', None)
|
||||
|
||||
with transaction.atomic():
|
||||
is_new = not self.pk
|
||||
super(SmartLink, self).save(*args, **kwargs)
|
||||
if is_new:
|
||||
event_smart_link_created.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
else:
|
||||
event_smart_link_edited.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
|
||||
|
||||
class ResolvedSmartLink(SmartLink):
|
||||
"""
|
||||
|
||||
@@ -6,7 +6,7 @@ from .literals import (
|
||||
TEST_SMART_LINK_CONDITION_FOREIGN_DOCUMENT_DATA,
|
||||
TEST_SMART_LINK_CONDITION_EXPRESSION,
|
||||
TEST_SMART_LINK_CONDITION_OPERATOR, TEST_SMART_LINK_DYNAMIC_LABEL,
|
||||
TEST_SMART_LINK_LABEL
|
||||
TEST_SMART_LINK_LABEL, TEST_SMART_LINK_LABEL_EDITED
|
||||
)
|
||||
|
||||
|
||||
@@ -26,3 +26,35 @@ class SmartLinkTestMixin(object):
|
||||
expression=TEST_SMART_LINK_CONDITION_EXPRESSION,
|
||||
operator=TEST_SMART_LINK_CONDITION_OPERATOR
|
||||
)
|
||||
|
||||
|
||||
class SmartLinkViewTestMixin(object):
|
||||
def _request_test_smart_link_create_view(self):
|
||||
# Typecast to list to force queryset evaluation
|
||||
values = list(SmartLink.objects.values_list('pk', flat=True))
|
||||
|
||||
response = self.post(
|
||||
viewname='linking:smart_link_create', data={
|
||||
'label': TEST_SMART_LINK_LABEL
|
||||
}
|
||||
)
|
||||
|
||||
self.test_smart_link = SmartLink.objects.exclude(pk__in=values).first()
|
||||
|
||||
return response
|
||||
|
||||
def _request_test_smart_link_delete_view(self):
|
||||
return self.post(
|
||||
viewname='linking:smart_link_delete', kwargs={
|
||||
'pk': self.test_smart_link.pk
|
||||
}
|
||||
)
|
||||
|
||||
def _request_test_smart_link_edit_view(self):
|
||||
return self.post(
|
||||
viewname='linking:smart_link_edit', kwargs={
|
||||
'pk': self.test_smart_link.pk
|
||||
}, data={
|
||||
'label': TEST_SMART_LINK_LABEL_EDITED
|
||||
}
|
||||
)
|
||||
|
||||
48
mayan/apps/linking/tests/test_events.py
Normal file
48
mayan/apps/linking/tests/test_events.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from actstream.models import Action
|
||||
|
||||
from mayan.apps.common.tests import GenericViewTestCase
|
||||
from mayan.apps.documents.tests import DocumentTestMixin
|
||||
|
||||
from ..permissions import (
|
||||
permission_smart_link_create, permission_smart_link_edit,
|
||||
)
|
||||
|
||||
from ..events import event_smart_link_created, event_smart_link_edited
|
||||
|
||||
from .mixins import SmartLinkTestMixin, SmartLinkViewTestMixin
|
||||
|
||||
|
||||
class SmartLinkTemplateEventsTestCase(DocumentTestMixin, SmartLinkTestMixin, SmartLinkViewTestMixin, GenericViewTestCase):
|
||||
auto_upload_document = False
|
||||
|
||||
def test_smart_link_create_event(self):
|
||||
self.grant_permission(
|
||||
permission=permission_smart_link_create
|
||||
)
|
||||
Action.objects.all().delete()
|
||||
|
||||
response = self._request_test_smart_link_create_view()
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
action = Action.objects.last()
|
||||
|
||||
self.assertEqual(action.actor, self._test_case_user)
|
||||
self.assertEqual(action.target, self.test_smart_link)
|
||||
self.assertEqual(action.verb, event_smart_link_created.id)
|
||||
|
||||
def test_smart_link_edit_event(self):
|
||||
self._create_test_smart_link()
|
||||
|
||||
self.grant_permission(permission=permission_smart_link_edit)
|
||||
Action.objects.all().delete()
|
||||
|
||||
response = self._request_test_smart_link_edit_view()
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
action = Action.objects.last()
|
||||
|
||||
self.assertEqual(action.actor, self._test_case_user)
|
||||
self.assertEqual(action.target, self.test_smart_link)
|
||||
self.assertEqual(action.verb, event_smart_link_edited.id)
|
||||
@@ -14,17 +14,10 @@ from .literals import (
|
||||
TEST_SMART_LINK_DYNAMIC_LABEL, TEST_SMART_LINK_LABEL_EDITED,
|
||||
TEST_SMART_LINK_LABEL
|
||||
)
|
||||
from .mixins import SmartLinkTestMixin
|
||||
from .mixins import SmartLinkTestMixin, SmartLinkViewTestMixin
|
||||
|
||||
|
||||
class SmartLinkViewTestCase(SmartLinkTestMixin, GenericViewTestCase):
|
||||
def _request_test_smart_link_create_view(self):
|
||||
return self.post(
|
||||
viewname='linking:smart_link_create', data={
|
||||
'label': TEST_SMART_LINK_LABEL
|
||||
}
|
||||
)
|
||||
|
||||
class SmartLinkViewTestCase(SmartLinkTestMixin, SmartLinkViewTestMixin, GenericViewTestCase):
|
||||
def test_smart_link_create_view_no_permission(self):
|
||||
response = self._request_test_smart_link_create_view()
|
||||
self.assertEquals(response.status_code, 403)
|
||||
@@ -42,13 +35,6 @@ class SmartLinkViewTestCase(SmartLinkTestMixin, GenericViewTestCase):
|
||||
SmartLink.objects.first().label, TEST_SMART_LINK_LABEL
|
||||
)
|
||||
|
||||
def _request_test_smart_link_delete_view(self):
|
||||
return self.post(
|
||||
viewname='linking:smart_link_delete', kwargs={
|
||||
'pk': self.test_smart_link.pk
|
||||
}
|
||||
)
|
||||
|
||||
def test_smart_link_delete_view_no_permission(self):
|
||||
self._create_test_smart_link()
|
||||
|
||||
@@ -66,15 +52,6 @@ class SmartLinkViewTestCase(SmartLinkTestMixin, GenericViewTestCase):
|
||||
|
||||
self.assertEqual(SmartLink.objects.count(), 0)
|
||||
|
||||
def _request_test_smart_link_edit_view(self):
|
||||
return self.post(
|
||||
viewname='linking:smart_link_edit', kwargs={
|
||||
'pk': self.test_smart_link.pk
|
||||
}, data={
|
||||
'label': TEST_SMART_LINK_LABEL_EDITED
|
||||
}
|
||||
)
|
||||
|
||||
def test_smart_link_edit_view_no_permission(self):
|
||||
self._create_test_smart_link()
|
||||
|
||||
@@ -124,10 +101,11 @@ class SmartLinkDocumentViewTestCase(SmartLinkTestMixin, GenericDocumentViewTestC
|
||||
)
|
||||
|
||||
response = self._request_test_smart_link_document_instances_view()
|
||||
# Text must appear 2 times, only for the windows title and template
|
||||
# Text must appear 3 times, two for the title and one for the template
|
||||
# heading. The two smart links are not shown.
|
||||
self.assertContains(
|
||||
response, text=self.test_document.label, count=2, status_code=200
|
||||
response=response, text=self.test_document.label, count=3,
|
||||
status_code=200
|
||||
)
|
||||
|
||||
def test_document_smart_link_list_view_with_permission(self):
|
||||
@@ -144,8 +122,8 @@ class SmartLinkDocumentViewTestCase(SmartLinkTestMixin, GenericDocumentViewTestC
|
||||
)
|
||||
|
||||
response = self._request_test_smart_link_document_instances_view()
|
||||
# Text must appear 4 times: 2 for the windows title and template
|
||||
# Text must appear 5 times: 3 for the windows title and template
|
||||
# heading, plus 2 for the test.
|
||||
self.assertContains(
|
||||
response, text=self.test_document.label, count=4, status_code=200
|
||||
response, text=self.test_document.label, count=5, status_code=200
|
||||
)
|
||||
|
||||
@@ -11,11 +11,13 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from mayan.apps.acls.models import AccessControlList
|
||||
from mayan.apps.common.generics import (
|
||||
AssignRemoveView, SingleObjectCreateView, SingleObjectDeleteView,
|
||||
AddRemoveView, SingleObjectCreateView, SingleObjectDeleteView,
|
||||
SingleObjectEditView, SingleObjectListView
|
||||
)
|
||||
from mayan.apps.documents.models import Document, DocumentType
|
||||
from mayan.apps.documents.permissions import permission_document_view
|
||||
from mayan.apps.documents.permissions import (
|
||||
permission_document_type_edit, permission_document_view
|
||||
)
|
||||
from mayan.apps.documents.views import DocumentListView
|
||||
|
||||
from .forms import SmartLinkConditionForm, SmartLinkForm
|
||||
@@ -97,43 +99,29 @@ class ResolvedSmartLinkView(DocumentListView):
|
||||
return context
|
||||
|
||||
|
||||
class SetupSmartLinkDocumentTypesView(AssignRemoveView):
|
||||
decode_content_type = True
|
||||
left_list_title = _('Available document types')
|
||||
object_permission = permission_smart_link_edit
|
||||
right_list_title = _('Document types enabled')
|
||||
class SetupSmartLinkDocumentTypesView(AddRemoveView):
|
||||
main_object_method_add = 'document_types_add'
|
||||
main_object_method_remove = 'document_types_remove'
|
||||
main_object_permission = permission_smart_link_edit
|
||||
main_object_model = SmartLink
|
||||
main_object_pk_url_kwarg = 'pk'
|
||||
secondary_object_model = DocumentType
|
||||
secondary_object_permission = permission_document_type_edit
|
||||
list_available_title = _('Available document types')
|
||||
list_added_title = _('Document types enabled')
|
||||
related_field = 'document_types'
|
||||
|
||||
def add(self, item):
|
||||
self.get_object().document_types.add(item)
|
||||
def get_actions_extra_kwargs(self):
|
||||
return {'_user': self.request.user}
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'object': self.get_object(),
|
||||
'object': self.main_object,
|
||||
'title': _(
|
||||
'Document type for which to enable smart link: %s'
|
||||
) % self.get_object()
|
||||
) % self.main_object,
|
||||
}
|
||||
|
||||
def get_object(self):
|
||||
return get_object_or_404(klass=SmartLink, pk=self.kwargs['pk'])
|
||||
|
||||
def left_list(self):
|
||||
# TODO: filter document type list by user ACL
|
||||
return AssignRemoveView.generate_choices(
|
||||
DocumentType.objects.exclude(
|
||||
pk__in=self.get_object().document_types.all()
|
||||
)
|
||||
)
|
||||
|
||||
def remove(self, item):
|
||||
self.get_object().document_types.remove(item)
|
||||
|
||||
def right_list(self):
|
||||
# TODO: filter document type list by user ACL
|
||||
return AssignRemoveView.generate_choices(
|
||||
self.get_object().document_types.all()
|
||||
)
|
||||
|
||||
|
||||
class SmartLinkListView(SingleObjectListView):
|
||||
object_permission = permission_smart_link_view
|
||||
@@ -208,6 +196,23 @@ class SmartLinkCreateView(SingleObjectCreateView):
|
||||
)
|
||||
view_permission = permission_smart_link_create
|
||||
|
||||
def get_save_extra_data(self):
|
||||
return {'_user': self.request.user}
|
||||
|
||||
|
||||
class SmartLinkDeleteView(SingleObjectDeleteView):
|
||||
model = SmartLink
|
||||
post_action_redirect = reverse_lazy(
|
||||
viewname='linking:smart_link_list'
|
||||
)
|
||||
view_permission = permission_smart_link_delete
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'object': self.get_object(),
|
||||
'title': _('Delete smart link: %s') % self.get_object()
|
||||
}
|
||||
|
||||
|
||||
class SmartLinkEditView(SingleObjectEditView):
|
||||
form_class = SmartLinkForm
|
||||
@@ -223,19 +228,8 @@ class SmartLinkEditView(SingleObjectEditView):
|
||||
'title': _('Edit smart link: %s') % self.get_object()
|
||||
}
|
||||
|
||||
|
||||
class SmartLinkDeleteView(SingleObjectDeleteView):
|
||||
model = SmartLink
|
||||
post_action_redirect = reverse_lazy(
|
||||
viewname='linking:smart_link_list'
|
||||
)
|
||||
view_permission = permission_smart_link_delete
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'object': self.get_object(),
|
||||
'title': _('Delete smart link: %s') % self.get_object()
|
||||
}
|
||||
def get_save_extra_data(self):
|
||||
return {'_user': self.request.user}
|
||||
|
||||
|
||||
class SmartLinkConditionListView(SingleObjectListView):
|
||||
|
||||
Reference in New Issue
Block a user