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:
Roberto Rosario
2019-04-28 01:44:23 -04:00
parent 959cdc56e5
commit 395c360784
9 changed files with 206 additions and 77 deletions

View File

@@ -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.

View File

@@ -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
--------

View File

@@ -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)

View 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'
)

View File

@@ -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):
"""

View File

@@ -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
}
)

View 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)

View File

@@ -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
)

View File

@@ -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):