Require view permissions for tag and document

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2019-05-08 16:55:54 -04:00
parent d533e48f46
commit 0b68463ed5
8 changed files with 642 additions and 267 deletions

View File

@@ -247,6 +247,8 @@
* Move the user set password views to the authentication app.
* All views redirect to common's home view instead of the
REDIRECT_URL setting.
* Update tag document list and the document tag list
views to require the view permissions for both objects.
3.1.11 (2019-04-XX)
===================

File diff suppressed because it is too large Load Diff

View File

@@ -68,9 +68,7 @@ class TagsApp(MayanAppConfig):
DocumentTag = self.get_model(model_name='DocumentTag')
Tag = self.get_model(model_name='Tag')
Document.add_to_class(
name='attached_tags', value=method_document_get_tags
)
Document.add_to_class(name='get_tags', value=method_document_get_tags)
ModelEventType.register(
model=Tag, event_types=(

View File

@@ -4,12 +4,19 @@ from django.apps import apps
from django.utils.translation import ugettext_lazy as _
def method_document_get_tags(self):
def method_document_get_tags(self, permission, user):
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
DocumentTag = apps.get_model(app_label='tags', model_name='DocumentTag')
return DocumentTag.objects.filter(documents=self)
return AccessControlList.objects.restrict_queryset(
permission=permission,
queryset=DocumentTag.objects.filter(documents=self), user=user
)
method_document_get_tags.help_text = _(
'Return a the tags attached to the document.'
)
method_document_get_tags.short_description = _('get_tags()')

View File

@@ -64,11 +64,21 @@ class Tag(models.Model):
The count if filtered by access.
"""
queryset = AccessControlList.objects.restrict_queryset(
permission_document_view, user, queryset=self.documents
permission=permission_document_view, queryset=self.documents,
user=user
)
return queryset.count()
def get_documents(self, user):
"""
Return a filtered queryset documents that have this tag attached.
"""
return AccessControlList.objects.restrict_queryset(
permission=permission_document_view, queryset=self.documents.all(),
user=user
)
def get_preview_widget(self):
return widget_single_tag(tag=self)
get_preview_widget.short_description = _('Preview')

View File

@@ -110,8 +110,13 @@ class TagViewTestMixin(object):
}
)
def _request_test_tag_list_view(self):
return self.get(viewname='tags:tag_list')
def _request_test_tag_document_list_view(self):
return self.get(viewname='documents:document_list')
return self.get(
viewname='tags:tag_document_list', kwargs={'pk': self.test_tag.pk}
)
def _request_test_document_tag_attach_view(self):
return self.post(
@@ -146,3 +151,10 @@ class TagViewTestMixin(object):
'tags': self.test_tag.pk,
}
)
def _request_test_document_tag_list_view(self):
return self.get(
viewname='tags:document_tag_list', kwargs={
'pk': self.test_document.pk
}
)

View File

@@ -1,5 +1,7 @@
from __future__ import unicode_literals
from django.utils.encoding import force_text
from mayan.apps.common.tests import GenericViewTestCase
from mayan.apps.documents.permissions import permission_document_view
from mayan.apps.documents.tests import GenericDocumentViewTestCase
@@ -100,8 +102,27 @@ class TagViewTestCase(TagTestMixin, TagViewTestMixin, GenericViewTestCase):
self.test_tag.refresh_from_db()
self.assertNotEqual(self.test_tag.label, tag_label)
def test_tag_list_view_with_no_permission(self):
self._create_test_tag()
response = self._request_test_tag_list_view()
self.assertNotContains(
response=response, text=self.test_tag.label, status_code=200
)
def test_tag_list_view_with_access(self):
self._create_test_tag()
self.grant_access(obj=self.test_tag, permission=permission_tag_view)
response = self._request_test_tag_list_view()
self.assertContains(
response=response, text=self.test_tag.label, status_code=200
)
class TagDocumentViewTestCase(TagTestMixin, TagViewTestMixin, GenericDocumentViewTestCase):
"""
def test_document_tags_widget_no_permissions(self):
self._create_test_tag()
@@ -126,6 +147,58 @@ class TagDocumentViewTestCase(TagTestMixin, TagViewTestMixin, GenericDocumentVie
self.assertContains(
response=response, text=self.test_tag.label, status_code=200
)
"""
def test_document_tags_list_no_permissions(self):
self._create_test_tag()
self.test_tag.documents.add(self.test_document)
response = self._request_test_document_tag_list_view()
self.assertNotContains(
response=response, text=force_text(self.test_tag), status_code=404
)
def test_document_tags_list_with_document_access(self):
self._create_test_tag()
self.test_tag.documents.add(self.test_document)
self.grant_access(
obj=self.test_document, permission=permission_tag_view
)
response = self._request_test_document_tag_list_view()
self.assertNotContains(
response=response, text=force_text(self.test_tag), status_code=200
)
def test_document_tags_list_with_tag_access(self):
self._create_test_tag()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_tag, permission=permission_tag_view)
response = self._request_test_document_tag_list_view()
self.assertNotContains(
response=response, text=force_text(self.test_tag), status_code=404
)
def test_document_tags_list_with_full_access(self):
self._create_test_tag()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_tag, permission=permission_tag_view)
self.grant_access(
obj=self.test_document, permission=permission_tag_view
)
response = self._request_test_document_tag_list_view()
self.assertContains(
response=response, text=force_text(self.test_tag), status_code=200
)
def test_document_attach_tag_view_no_permission(self):
self._create_test_tag()

View File

@@ -13,6 +13,7 @@ from mayan.apps.common.generics import (
MultipleObjectFormActionView, MultipleObjectConfirmActionView,
SingleObjectCreateView, SingleObjectEditView, SingleObjectListView
)
from mayan.apps.common.mixins import ExternalObjectMixin
from mayan.apps.documents.models import Document
from mayan.apps.documents.views import DocumentListView
from mayan.apps.documents.permissions import permission_document_view
@@ -96,7 +97,9 @@ class TagAttachActionView(MultipleObjectFormActionView):
return super(TagAttachActionView, self).get_post_action_redirect()
def object_action(self, form, instance):
attached_tags = instance.attached_tags()
attached_tags = instance.get_tags(
permission=permission_tag_attach, user=self.request.user
)
for tag in form.cleaned_data['tags']:
AccessControlList.objects.check_access(
@@ -227,12 +230,13 @@ class TagListView(SingleObjectListView):
return Tag.objects.all()
class TagDocumentListView(DocumentListView):
def get_tag(self):
return get_object_or_404(klass=Tag, pk=self.kwargs['pk'])
class TagDocumentListView(ExternalObjectMixin, DocumentListView):
external_object_class = Tag
external_object_permission = permission_tag_view
external_object_pk_url_kwarg = 'pk'
def get_document_queryset(self):
return self.get_tag().documents.all()
return self.get_tag().get_documents(user=self.request.user).all()
def get_extra_context(self):
context = super(TagDocumentListView, self).get_extra_context()
@@ -244,39 +248,38 @@ class TagDocumentListView(DocumentListView):
)
return context
def get_tag(self):
return self.get_external_object()
class DocumentTagListView(TagListView):
def dispatch(self, request, *args, **kwargs):
self.document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
AccessControlList.objects.check_access(
obj=self.document, permissions=(permission_document_view,),
user=request.user,
)
return super(DocumentTagListView, self).dispatch(
request, *args, **kwargs
)
class DocumentTagListView(ExternalObjectMixin, TagListView):
external_object_class = Document
external_object_permission = permission_tag_view
external_object_pk_url_kwarg = 'pk'
def get_extra_context(self):
context = super(DocumentTagListView, self).get_extra_context()
context.update(
{
'hide_link': True,
'no_results_title': _('Document has no tags attached'),
'no_results_main_link': link_document_tag_multiple_attach.resolve(
context=RequestContext(
request=self.request, dict_={'object': self.document}
self.request, {'object': self.get_external_object()}
)
),
'object': self.document,
'title': _('Tags for document: %s') % self.document,
'no_results_title': _('Document has no tags attached'),
'object': self.get_external_object(),
'title': _(
'Tags for document: %s'
) % self.get_external_object(),
}
)
return context
def get_tag_queryset(self):
return self.document.attached_tags().all()
def get_source_queryset(self):
return self.get_external_object().get_tags(
permission=permission_tag_view, user=self.request.user
).all()
class TagRemoveActionView(MultipleObjectFormActionView):
@@ -343,7 +346,9 @@ class TagRemoveActionView(MultipleObjectFormActionView):
return super(TagRemoveActionView, self).get_post_action_redirect()
def object_action(self, form, instance):
attached_tags = instance.attached_tags()
attached_tags = instance.get_tags(
permission=permission_tag_remove, user=self.request.user
)
for tag in form.cleaned_data['tags']:
AccessControlList.objects.check_access(