Refactor the tags app

Remove the widget from the model.

Add keyword arguments.

Separate form widgets from html widgets. HTML widgets now go
in the html_widgets module.

Update the TagMultipleSelectionForm class to be a subclass of
FilteredSelectionForm.

Move Select2 specific JavaScript from the appearence app to the
tags app.

Update tag attachment and removal view names.

Modernize tests.

Add more tests.

Consolidate repeated test code into test mixins.

Update views to comply with MERCs 5 and 6.

Use uniform nomeclature for URLs.

Update URLs parameters to use the '_id' form.

Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2019-01-29 04:20:54 -04:00
parent ef5e0c2d86
commit b5839c0662
30 changed files with 1489 additions and 818 deletions

View File

@@ -8,10 +8,10 @@ class MayanApp {
ajaxMenusOptions: []
}
this.ajaxSpinnerSeletor = '#ajax-spinner';
this.ajaxExecuting = false;
this.ajaxMenusOptions = options.ajaxMenusOptions;
this.ajaxMenuHashes = {};
this.ajaxSpinnerSeletor = '#ajax-spinner';
this.window = $(window);
}
@@ -81,22 +81,6 @@ class MayanApp {
});
}
static tagSelectionTemplate (tag, container) {
var $tag = $(
'<span class="label label-tag" style="background: ' + tag.element.dataset.color + ';"> ' + tag.text + '</span>'
);
container[0].style.background = tag.element.dataset.color;
return $tag;
}
static tagResultTemplate (tag) {
if (!tag.element) { return ''; }
var $tag = $(
'<span class="label label-tag" style="background: ' + tag.element.dataset.color + ';"> ' + tag.text + '</span>'
);
return $tag;
}
static updateNavbarState () {
var uri = new URI(window.location.hash);
var uriFragment = uri.fragment();
@@ -445,12 +429,6 @@ class MayanApp {
dropdownAutoWidth: true,
width: '100%'
});
$('.select2-tags').select2({
templateSelection: MayanApp.tagSelectionTemplate,
templateResult: MayanApp.tagResultTemplate,
width: '100%'
});
}
resizeFullHeight () {

View File

@@ -8,4 +8,4 @@ from .models import Tag
@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
filter_horizontal = ('documents',)
list_display = ('label', 'color', 'get_preview_widget')
list_display = ('label', 'color')

View File

@@ -1,14 +1,20 @@
from __future__ import absolute_import, unicode_literals
from rest_framework import generics
from rest_framework import generics, status
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response
from mayan.apps.common.mixins import ExternalObjectViewMixin
from mayan.apps.common.mixins import ExternalObjectMixin
from mayan.apps.documents.api_views import DocumentViewSet
from mayan.apps.documents.models import Document
from mayan.apps.documents.permissions import permission_document_view
from mayan.apps.documents.serializers import DocumentSerializer
from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter
from mayan.apps.rest_api.generics import (
ListAPIView, ListCreateAPIView, RetrieveDestroyAPIView,
RetrieveUpdateDestroyAPIView
)
from mayan.apps.rest_api.permissions import MayanPermission
from .models import Tag
@@ -17,116 +23,295 @@ from .permissions import (
permission_tag_edit, permission_tag_remove, permission_tag_view
)
from .serializers import (
DocumentTagSerializer, TagSerializer, WritableTagSerializer
DocumentTagAttachSerializer, DocumentTagSerializer, TagAttachSerializer,
TagRemoveSerializer, TagSerializer,
)
class APITagListView(generics.ListCreateAPIView):
from django.conf.urls import url, include
from django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets
from rest_framework.decorators import detail_route
from rest_framework.response import Response
from drf_yasg.utils import swagger_auto_schema
class TagViewSet(viewsets.ModelViewSet):
filter_backends = (MayanObjectPermissionsFilter,)
lookup_field = 'pk'
lookup_url_kwarg='tag_id'
permission_classes = (MayanPermission,)
queryset = Tag.objects.all()
serializer_class = TagSerializer
#@swagger_auto_schema(operation_description='GET /articles/today/')
@swagger_auto_schema(
operation_description="partial_update description override", responses={200: TagAttachSerializer}
)
@action(
detail=True, lookup_field='pk', lookup_url_kwarg='tag_id',
methods=('post',), serializer_class=TagAttachSerializer,
url_name='document-attach', url_path='attach'
)
def attach(self, request, *args, **kwargs):
#print '!!! attach', args, kwargs#, self.context
#return Response({})
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
#print '((((((((', serializer.validated_data
#self.perform_attach(serializer=serializer)
serializer.attach(instance=self.get_object())
headers = self.get_success_headers(data=serializer.data)
return Response(
serializer.data, status=status.HTTP_200_OK, headers=headers
)
#def perform_attach(self, serializer):
# #print '!!!!', serializer
# serializer.attach(instance=self.get_object())
#def get_success_headers(self, data):
# try:
# return {'Location': str(data[api_settings.URL_FIELD_NAME])}
# except (TypeError, KeyError):
# return {}
@action(
detail=True, lookup_field='pk', lookup_url_kwarg='tag_id',
url_name='document-list', url_path='documents'
)
def document_list(self, request, *args, **kwargs):
queryset = self.get_object().documents.all()
#TODO:Filter queryset
#queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
#serializer = self.get_serializer(page, many=True)
serializer = DocumentSerializer(page, many=True, context={'request': request})
return self.get_paginated_response(serializer.data)
#serializer = self.get_serializer(queryset, many=True)
serializer = DocumentSerializer(queryset, many=True, context={'request': request})
return Response(serializer.data)
#serializer = DocumentSerializer(
# instance=, many=True,
# context={'request': request}
#)
#return Response(serializer.data)
@action(
detail=True, lookup_field='pk', lookup_url_kwarg='tag_id',
methods=('post',), serializer_class=TagRemoveSerializer,
url_name='document-remove', url_path='remove'
)
def remove(self, request, *args, **kwargs):
#print '!!! attach', args, kwargs#, self.context
#return Response({})
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
#print '((((((((', serializer.validated_data
#self.perform_attach(serializer=serializer)
serializer.remove(instance=self.get_object())
headers = self.get_success_headers(data=serializer.data)
return Response(
serializer.data, status=status.HTTP_200_OK, headers=headers
)
#def get_serializer_class(self, *args, **kwargs):
# #if self.action == 'attach':
# print '!!!!get_serializer_class', args, kwargs
# return TagAttachSerializer
class DocumentTagViewSet(ExternalObjectMixin, viewsets.ReadOnlyModelViewSet):
external_object_class = Document
external_object_pk_url_kwarg = 'document_id'
external_object_permission = permission_tag_view
lookup_field = 'pk'
object_permission = {
'list': permission_document_view,
'retrieve': permission_document_view
}
serializer_class = DocumentTagSerializer
@action(
detail=True, lookup_field='pk', lookup_url_kwarg='document_id',
methods=('post',), serializer_class=DocumentTagAttachSerializer,
url_name='tag-attach', url_path='attach'
)
def attach(self, request, *args, **kwargs):
return Response({})
'''
serializer = DocumentSerializer(
instance=self.get_object().documents.all(), many=True,
context={'request': request}
)
return Response(serializer.data)
'''
def get_document(self):
return self.get_external_object()
def get_queryset(self):
#return self.get_document().get_tags(user=self.request.user).all()
return self.get_document().tags.all()
#@detail_route(lookup_url_kwarg='tag_id')
#def document_list(self, request, *args, **kwargs):
# serializer = DocumentSerializer(
## instance=self.get_object().documents.all(), many=True,
# context={'request': request}
# )
# return Response(serializer.data)
'''
class APITagListView(ListCreateAPIView):
"""
get: Returns a list of all the tags.
post: Create a new tag.
"""
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {'GET': (permission_tag_view,)}
mayan_view_permissions = {'POST': (permission_tag_create,)}
permission_classes = (MayanPermission,)
object_permission = {'GET': permission_tag_view}
queryset = Tag.objects.all()
def get_serializer(self, *args, **kwargs):
if not self.request:
return None
return super(APITagListView, self).get_serializer(*args, **kwargs)
def get_serializer_class(self):
if self.request.method == 'GET':
return TagSerializer
elif self.request.method == 'POST':
return WritableTagSerializer
serializer_class = TagSerializer
view_permission = {'POST': permission_tag_create}
class APITagView(generics.RetrieveUpdateDestroyAPIView):
class APITagView(RetrieveUpdateDestroyAPIView):
"""
delete: Delete the selected tag.
get: Return the details of the selected tag.
patch: Edit the selected tag.
put: Edit the selected tag.
"""
filter_backends = (MayanObjectPermissionsFilter,)
lookup_url_kwarg = 'tag_pk'
mayan_object_permissions = {
'DELETE': (permission_tag_delete,),
'GET': (permission_tag_view,),
'PATCH': (permission_tag_edit,),
'PUT': (permission_tag_edit,)
object_permission = {
'DELETE': permission_tag_delete,
'GET': permission_tag_view,
'PATCH': permission_tag_edit,
'PUT': permission_tag_edit
}
queryset = Tag.objects.all()
serializer_class = TagSerializer
def get_serializer(self, *args, **kwargs):
if not self.request:
return None
##
return super(APITagView, self).get_serializer(*args, **kwargs)
def get_serializer_class(self):
if self.request.method == 'GET':
return TagSerializer
else:
return WritableTagSerializer
class APITagDocumentListView(ExternalObjectViewMixin, generics.ListAPIView):
class APITagDocumentListView(ExternalObjectMixin, ListCreateAPIView):
"""
get: Returns a list of all the documents tagged by a particular tag.
"""
external_object_class = Tag
external_object_pk_url_kwarg = 'tag_pk'
external_object_permission = permission_tag_view
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {'GET': (permission_document_view,)}
serializer_class = DocumentSerializer
object_permission = {'GET': permission_document_view}
serializer_class = TagDocumentSerializer
def get_queryset(self):
return self.get_tag().documents.all()
return self.get_tag().get_documents(user=self.request.user).all()
def get_tag(self):
return self.get_external_object()
##
'''
class APIDocumentTagListView(ExternalObjectViewMixin, generics.ListCreateAPIView):
'''
class APITagView(RetrieveDestroyAPIView):
"""
get: Returns a list of all the tags attached to a document.
post: Attach a tag to a document.
delete: Delete the selected tag document.
get: Return the details of the selected tag document.
"""
lookup_url_kwarg = 'tag_pk'
object_permission = {
'DELETE': permission_tag_delete,
'GET': permission_tag_view,
'PATCH': permission_tag_edit,
'PUT': permission_tag_edit
}
queryset = Tag.objects.all()
serializer_class = TagSerializer
'''
##
'''
class DocumentSourceMixin(ExternalObjectMixin):
external_object_class = Document
external_object_pk_url_kwarg = 'document_pk'
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {
'GET': (permission_tag_view,),
'POST': (permission_tag_attach,)
}
serializer_class = DocumentTagSerializer
def get_document(self):
return self.get_external_object()
def get_external_object_permission(self):
if self.request.method == 'POST':
return permission_tag_attach
else:
return permission_tag_view
permission_dictionary = {
'DELETE': permission_tag_remove,
'GET': permission_tag_view,
'POST': permission_tag_attach
}
return permission_dictionary.get(self.request.method)
def get_queryset(self):
return self.get_document().get_tags().all()
return self.get_document().tags.all()
def get_serializer(self, *args, **kwargs):
if not self.request:
return None
def get_serializer_context(self):
context = super(DocumentSourceMixin, self).get_serializer_context()
if self.kwargs:
context.update(
{
'document': self.get_document(),
}
)
return super(APIDocumentTagListView, self).get_serializer(*args, **kwargs)
return context
def get_serializer_class(self):
return DocumentTagSerializer
class APIDocumentTagListView(DocumentSourceMixin, ListCreateAPIView):
"""
get: Returns a list of all the tags attached to a document.
post: Attach a tag to a document.
"""
#external_object_class = Document
#external_object_pk_url_kwarg = 'document_pk'
object_permission = {
'GET': permission_tag_view,
#'POST': permission_tag_attach
}
#serializer_class = DocumentTagSerializer
#def get_document(self):
# return self.get_external_object()
#def get_external_object_permission(self):
# if self.request.method == 'POST':
# return permission_tag_attach
# else:
# return permission_tag_view
#def get_queryset(self):
# #if self.request.method == 'POST':
# # permission = permission_tag_attach
# #else:
# # permission = permission_tag_view
#
# return self.get_document().tags().all()
# #return self.get_document().get_tags(
## # permission=permission, user=self.request.user
# #).all()
"""
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
@@ -140,41 +325,44 @@ class APIDocumentTagListView(ExternalObjectViewMixin, generics.ListCreateAPIView
)
return context
"""
class APIDocumentTagView(ExternalObjectViewMixin, generics.RetrieveDestroyAPIView):
class APIDocumentTagView(DocumentSourceMixin, RetrieveDestroyAPIView):
"""
delete: Remove a tag from the selected document.
get: Returns the details of the selected document tag.
"""
external_object_class = Document
external_object_pk_url_kwarg = 'document_pk'
filter_backends = (MayanObjectPermissionsFilter,)
#external_object_class = Document
#external_object_pk_url_kwarg = 'document_pk'
lookup_url_kwarg = 'tag_pk'
mayan_object_permissions = {
'GET': (permission_tag_view,),
'DELETE': (permission_tag_remove,)
mayan_object_permission = {
'GET': permission_tag_view,
'DELETE': permission_tag_remove
}
serializer_class = DocumentTagSerializer
#serializer_class = DocumentTagSerializer
def get_document(self):
return self.get_external_object()
#def get_document(self):
# return self.get_external_object()
def get_external_object_permission(self):
if self.request.method == 'DELETE':
return permission_tag_remove
else:
return permission_tag_view
#def get_external_object_permission(self):
# if self.request.method == 'DELETE':
# return permission_tag_remove
# else:
# return permission_tag_view
"""
def get_queryset(self):
return self.get_document().get_tags().all()
if self.request.method == 'DELETE':
permission = permission_tag_remove
else:
permission = permission_tag_view
def get_serializer(self, *args, **kwargs):
if not self.request:
return None
return super(APIDocumentTagView, self).get_serializer(*args, **kwargs)
return self.get_document().get_tags(
permission=permission, user=self.request.user
).all()
"""
"""
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
@@ -188,15 +376,33 @@ class APIDocumentTagView(ExternalObjectViewMixin, generics.RetrieveDestroyAPIVie
)
return context
"""
def perform_destroy(self, instance):
try:
instance.documents.remove(self.get_document())
except Exception as exception:
raise ValidationError(exception)
# try:
from mayan.apps.acls.models import AccessControlList
from rest_framework.generics import get_object_or_404
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_tag_remove, queryset=Tag.objects.all(),
user=self.request.user
)
instance = get_object_or_404(queryset=queryset, pk=instance.pk)
#instance.attach_to(
# document=self.context['document'],
# user=self.context['request'].user
#)
serializer = self.get_serializer(instance)
return Response(serializer.data)
instance.remove_from(
document=self.get_document(), user=self.request.user
)
#instance.documents.remove(self.get_document())
# except Exception as exception:
# raise ValidationError(exception)
#def retrieve(self, request, *args, **kwargs):
# instance = self.get_object()
# serializer = self.get_serializer(instance)
# return Response(serializer.data)
'''

View File

@@ -24,12 +24,13 @@ from .events import (
event_tag_attach, event_tag_created, event_tag_edited, event_tag_remove
)
from .handlers import handler_index_document, handler_tag_pre_delete
from .html_widgets import DocumentTagsWidget, TagWidget
from .links import (
link_document_tag_list, link_multiple_documents_attach_tag,
link_multiple_documents_tag_remove,
link_single_document_multiple_tag_remove, link_tag_attach,
link_tag_create, link_tag_delete, link_tag_edit, link_tag_list,
link_tag_multiple_delete, link_tag_tagged_item_list
link_document_tag_list, link_document_multiple_tag_multiple_attach,
link_document_multiple_tag_multiple_remove,
link_document_tag_multiple_remove, link_document_tag_multiple_attach,
link_tag_create, link_tag_delete, link_tag_document_list, link_tag_edit,
link_tag_list, link_tag_multiple_delete
)
from .menus import menu_tags
from .methods import method_get_tags
@@ -38,7 +39,6 @@ from .permissions import (
permission_tag_remove, permission_tag_view
)
from .search import tag_search # NOQA
from .widgets import widget_document_tags
class TagsApp(MayanAppConfig):
@@ -63,13 +63,11 @@ class TagsApp(MayanAppConfig):
app_label='documents', model_name='DocumentPageSearchResult'
)
DocumentTag = self.get_model('DocumentTag')
Tag = self.get_model('Tag')
DocumentTag = self.get_model(model_name='DocumentTag')
Tag = self.get_model(model_name='Tag')
Document.add_to_class(name='get_tags', value=method_get_tags)
ModelAttribute(model=Document, name='get_tags')
ModelEventType.register(
model=Tag, event_types=(
event_tag_attach, event_tag_created, event_tag_edited,
@@ -78,10 +76,10 @@ class TagsApp(MayanAppConfig):
)
ModelField(
Document, name='tags__label'
model=Document, name='tags__label'
)
ModelField(
Document, name='tags__color'
model=Document, name='tags__color'
)
ModelPermission.register(
@@ -96,29 +94,31 @@ class TagsApp(MayanAppConfig):
permission_acl_edit, permission_acl_view,
permission_events_view, permission_tag_attach,
permission_tag_delete, permission_tag_edit,
permission_tag_remove, permission_tag_view,
permission_tag_remove, permission_tag_view
)
)
SourceColumn(
attribute='label', is_identifier=True, is_sortable=True,
source=DocumentTag,
source=DocumentTag
)
SourceColumn(
attribute='get_preview_widget', source=DocumentTag
label=_('Preview'), source=DocumentTag, widget=TagWidget
)
SourceColumn(
func=lambda context: widget_document_tags(
document=context['object'], user=context['request'].user
), label=_('Tags'), source=Document
)
SourceColumn(
func=lambda context: widget_document_tags(
document=context['object'].document,
func=lambda context: context['object'].get_tags(
permission=permission_tag_view,
user=context['request'].user
), label=_('Tags'), source=DocumentPageSearchResult
), label=_('Tags'), source=Document, widget=DocumentTagsWidget
)
SourceColumn(
func=lambda context: context['object'].document.get_tag(
permission=permission_tag_view,
user=context['request'].user
), label=_('Tags'), source=DocumentPageSearchResult,
widget=DocumentTagsWidget
)
SourceColumn(
@@ -126,12 +126,12 @@ class TagsApp(MayanAppConfig):
source=Tag
)
SourceColumn(
attribute='get_preview_widget', source=Tag
label=_('Preview'), source=Tag, widget=TagWidget
)
SourceColumn(
func=lambda context: context['object'].get_document_count(
user=context['request'].user
), label=_('Documents'), source=Tag
), include_label=True, label=_('Documents'), source=Tag
)
document_page_search.add_model_field(
@@ -147,19 +147,17 @@ class TagsApp(MayanAppConfig):
links=(
link_acl_list, link_events_for_object,
link_object_event_types_user_subcriptions_list,
link_tag_tagged_item_list,
),
sources=(Tag,)
link_tag_document_list,
), sources=(Tag,)
)
menu_main.bind_links(links=(menu_tags,), position=98)
menu_multi_item.bind_links(
links=(
link_multiple_documents_attach_tag,
link_multiple_documents_tag_remove
),
sources=(Document,)
link_document_multiple_tag_multiple_attach,
link_document_multiple_tag_multiple_remove
), sources=(Document,)
)
menu_multi_item.bind_links(
links=(link_tag_multiple_delete,), sources=(Tag,)
@@ -167,14 +165,14 @@ class TagsApp(MayanAppConfig):
menu_object.bind_links(
links=(
link_tag_edit, link_tag_delete
),
sources=(Tag,)
), sources=(Tag,)
)
menu_sidebar.bind_links(
links=(link_tag_attach, link_single_document_multiple_tag_remove),
sources=(
'tags:tag_attach', 'tags:document_tags',
'tags:single_document_multiple_tag_remove'
links=(
link_document_tag_multiple_attach, link_document_tag_multiple_remove
), sources=(
'tags:document_tag_multiple_attach', 'tags:document_tag_list',
'tags:document_tag_multiple_remove'
)
)
menu_tags.bind_links(
@@ -188,13 +186,11 @@ class TagsApp(MayanAppConfig):
# Index update
m2m_changed.connect(
handler_index_document,
dispatch_uid='tags_handler_index_document',
sender=Tag.documents.through
receiver=handler_index_document, sender=Tag.documents.through
)
pre_delete.connect(
handler_tag_pre_delete,
dispatch_uid='tags_handler_tag_pre_delete',
sender=Tag
receiver=handler_tag_pre_delete, sender=Tag
)

View File

@@ -4,7 +4,7 @@ from django.utils.translation import ugettext_lazy as _
from mayan.apps.events import EventTypeNamespace
namespace = EventTypeNamespace(name='tags', label=_('Tags'))
namespace = EventTypeNamespace(label=_('Tags'), name='tags')
event_tag_attach = namespace.add_event_type(
label=_('Tag attached to document'), name='attach'

View File

@@ -1,37 +1,22 @@
from __future__ import absolute_import, unicode_literals
import logging
from django import forms
from django.utils.translation import ugettext_lazy as _
from mayan.apps.acls.models import AccessControlList
from mayan.apps.common.forms import FilteredSelectionForm
from .models import Tag
from .permissions import permission_tag_view
from .widgets import TagFormWidget
logger = logging.getLogger(__name__)
class TagMultipleSelectionForm(FilteredSelectionForm):
class Media:
js = ('tags/js/tags_form.js',)
class TagMultipleSelectionForm(forms.Form):
def __init__(self, *args, **kwargs):
help_text = kwargs.pop('help_text', None)
permission = kwargs.pop('permission', permission_tag_view)
queryset = kwargs.pop('queryset', Tag.objects.all())
user = kwargs.pop('user', None)
logger.debug('user: %s', user)
super(TagMultipleSelectionForm, self).__init__(*args, **kwargs)
queryset = AccessControlList.objects.filter_by_access(
permission=permission, queryset=queryset, user=user
)
self.fields['tags'] = forms.ModelMultipleChoiceField(
label=_('Tags'), help_text=help_text,
queryset=queryset, required=False,
widget=TagFormWidget(
attrs={'class': 'select2-tags'}, queryset=queryset
)
)
class Meta:
allow_multiple = True
field_name = 'tags'
label = _('Tags')
widget_attributes = {'class': 'select2-tags'}

View File

@@ -0,0 +1,26 @@
from __future__ import absolute_import, unicode_literals
from django.template.loader import render_to_string
class DocumentTagsWidget(object):
"""
A tag widget that displays the tags for the given document
"""
def render(self, name, value):
return render_to_string(
template_name='tags/document_tags_widget.html',
context={
'tags': value,
}
)
class TagWidget(object):
def render(self, name, value):
return render_to_string(
template_name='tags/tag_widget.html',
context={
'tag': value,
}
)

View File

@@ -2,19 +2,22 @@ from __future__ import absolute_import, unicode_literals
from mayan.apps.appearance.classes import Icon
icon_menu_tags = Icon(driver_name='fontawesome', symbol='tags')
icon_multiple_documents_tag_attach = Icon(
driver_name='fontawesome-dual', primary_symbol='tag',
secondary_symbol='arrow-right'
)
icon_multiple_documents_tag_remove = Icon(
icon_document_multiple_tag_multiple_remove = Icon(
driver_name='fontawesome-dual', primary_symbol='tag',
secondary_symbol='minus'
)
icon_tag_attach = Icon(
icon_document_tag_multiple_attach = Icon(
driver_name='fontawesome-dual', primary_symbol='tag',
secondary_symbol='arrow-right'
)
icon_document_tag_multiple_remove = Icon(
driver_name='fontawesome-dual', primary_symbol='tag',
secondary_symbol='minus'
)
icon_document_tag_multiple_remove_submit = Icon(
driver_name='fontawesome', symbol='minus'
)
icon_menu_tags = Icon(driver_name='fontawesome', symbol='tags')
icon_tag_create = Icon(
driver_name='fontawesome-dual', primary_symbol='tag',
secondary_symbol='plus'
@@ -25,8 +28,3 @@ icon_tag_delete_submit = Icon(driver_name='fontawesome', symbol='times')
icon_tag_document_list = Icon(driver_name='fontawesome', symbol='tags')
icon_tag_list = Icon(driver_name='fontawesome', symbol='tags')
icon_tag_multiple_delete = Icon(driver_name='fontawesome', symbol='times')
icon_tag_remove = Icon(
driver_name='fontawesome-dual', primary_symbol='tag',
secondary_symbol='minus'
)
icon_tag_remove_submit = Icon(driver_name='fontawesome', symbol='minus')

View File

@@ -6,10 +6,10 @@ from mayan.apps.documents.icons import icon_document_list
from mayan.apps.navigation import Link, get_cascade_condition
from .icons import (
icon_document_multiple_tag_multiple_remove, icon_document_multiple_tag_multiple_remove,
icon_document_tag_multiple_attach, icon_tag_create, icon_tag_delete, icon_tag_edit,
icon_tag_document_list, icon_tag_list, icon_tag_multiple_delete,
icon_document_tag_multiple_remove
icon_document_multiple_tag_multiple_remove,
icon_document_tag_multiple_attach, icon_tag_create, icon_tag_delete,
icon_tag_edit, icon_tag_document_list, icon_tag_list,
icon_tag_multiple_delete, icon_document_tag_multiple_remove
)
from .permissions import (
permission_tag_attach, permission_tag_create, permission_tag_delete,
@@ -17,10 +17,6 @@ from .permissions import (
)
link_document_tag_list = Link(
args='resolved_object.pk', icon_class=icon_tag_document_list,
permission=permission_tag_view, text=_('Tags'), view='tags:document_tags'
)
link_document_multiple_tag_multiple_attach = Link(
icon_class=icon_document_multiple_tag_multiple_remove, text=_('Attach tags'),
view='tags:document_multiple_tag_multiple_attach'
@@ -29,27 +25,37 @@ link_document_multiple_tag_multiple_remove = Link(
icon_class=icon_document_multiple_tag_multiple_remove, text=_('Remove tag'),
view='tags:document_multiple_tag_multiple_remove'
)
link_document_tag_list = Link(
icon_class=icon_tag_document_list,
kwargs={'document_id': 'resolved_object.pk'},
permission=permission_tag_view, text=_('Tags'),
view='tags:document_tag_list'
)
link_document_tag_multiple_attach = Link(
args='object.pk', icon_class=icon_document_tag_multiple_attach,
permission=permission_tag_attach, text=_('Attach tags'),
view='tags:document_tag_multiple_attach'
icon_class=icon_document_tag_multiple_attach,
kwargs={'document_id': 'object.pk'}, permission=permission_tag_attach,
text=_('Attach tags'), view='tags:document_tag_multiple_attach'
)
link_document_tag_multiple_remove = Link(
args='object.id', icon_class=icon_document_tag_multiple_remove,
permission=permission_tag_remove, text=_('Remove tags'),
view='tags:document_tag_multiple_remove'
icon_class=icon_document_tag_multiple_remove,
kwargs={'document_id': 'object.pk'}, permission=permission_tag_remove,
text=_('Remove tags'), view='tags:document_tag_multiple_remove'
)
link_tag_create = Link(
icon_class=icon_tag_create, permission=permission_tag_create,
text=_('Create new tag'), view='tags:tag_create'
)
link_tag_delete = Link(
args='object.id', icon_class=icon_tag_delete,
icon_class=icon_tag_delete, kwargs={'tag_id': 'object.pk'},
permission=permission_tag_delete, tags='dangerous', text=_('Delete'),
view='tags:tag_delete'
)
link_tag_document_list = Link(
icon_class=icon_document_list, kwargs={'tag_id': 'object.pk'},
text=('Documents'), view='tags:tag_document_list'
)
link_tag_edit = Link(
args='object.id', icon_class=icon_tag_edit,
icon_class=icon_tag_edit, kwargs={'tag_id': 'object.pk'},
permission=permission_tag_edit, text=_('Edit'), view='tags:tag_edit'
)
link_tag_list = Link(
@@ -62,7 +68,3 @@ link_tag_multiple_delete = Link(
icon_class=icon_tag_multiple_delete, permission=permission_tag_delete,
text=_('Delete'), view='tags:tag_multiple_delete'
)
link_tag_tagged_item_list = Link(
args='object.id', icon_class=icon_document_list, text=('Documents'),
view='tags:tag_tagged_item_list'
)

View File

@@ -3,10 +3,18 @@ from __future__ import unicode_literals
from django.apps import apps
from django.utils.translation import ugettext_lazy as _
from .permissions import permission_tag_view
def method_get_tags(self):
def method_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_get_tags.help_text = _('Return a the tags attached to the document.')

View File

@@ -15,7 +15,6 @@ from .events import (
event_tag_attach, event_tag_created, event_tag_edited, event_tag_remove
)
from .managers import DocumentTagManager
from .widgets import widget_single_tag
@python_2_unicode_compatible
@@ -56,23 +55,22 @@ class Tag(models.Model):
def get_absolute_url(self):
return reverse(
viewname='tags:tag_tagged_item_list', kwargs={'tag_pk': str(self.pk)}
viewname='tags:tag_tagged_item_list', kwargs={
'tag_id': self.pk
}
)
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,
user=user
)
def get_document_count(self, user):
"""
Return the numeric count of documents that have this tag attached.
The count if filtered by access.
"""
queryset = AccessControlList.objects.filter_by_access(
permission_document_view, user, queryset=self.documents
)
return queryset.count()
def get_preview_widget(self):
return widget_single_tag(tag=self)
get_preview_widget.short_description = _('Preview')
return self.get_documents(user=user).count()
def remove_from(self, document, user=None):
"""

View File

@@ -0,0 +1,20 @@
from __future__ import unicode_literals
#from rest_framework import routers
#router = routers.SimpleRouter()
#router.register(r'users', UserViewSet)
#router.register(r'accounts', AccountViewSet)
#urlpatterns = router.urls
#router = routers.DefaultRouter()
#from mayan.apps.rest_api.api_views import router
#from mayan.apps.rest_api.urls import router
from .api_views import TagViewSet
router_entries = (
{'prefix': r'tags', 'viewset': TagViewSet, 'base_name': 'tag'},
)
#router.register(prefix=r'tags', viewset=TagViewSet, basename='tag')

View File

@@ -7,9 +7,8 @@ from mayan.apps.dynamic_search.classes import SearchModel
from .permissions import permission_tag_view
tag_search = SearchModel(
app_label='tags', model_name='Tag',
permission=permission_tag_view,
serializer_string='mayan.apps.tags.serializers.TagSerializer'
app_label='tags', model_name='Tag', permission=permission_tag_view,
serializer_path='mayan.apps.tags.serializers.TagSerializer'
)
tag_search.add_model_field(

View File

@@ -8,34 +8,42 @@ from rest_framework.reverse import reverse
from mayan.apps.acls.models import AccessControlList
from mayan.apps.documents.models import Document
from mayan.apps.documents.serializers import DocumentSerializer
from mayan.apps.rest_api.relations import MultiKwargHyperlinkedIdentityField
from .models import Tag
from .permissions import permission_tag_attach
class TagSerializer(serializers.HyperlinkedModelSerializer):
documents_url = serializers.HyperlinkedIdentityField(
lookup_field='pk', lookup_url_kwarg='tag_pk',
view_name='rest_api:tag-document-list'
attach_url = serializers.HyperlinkedIdentityField(
lookup_url_kwarg='tag_id', view_name='rest_api:tag-document-attach'
)
documents_url = serializers.HyperlinkedIdentityField(
lookup_url_kwarg='tag_id', view_name='rest_api:tag-document-list'
)
remove_url = serializers.HyperlinkedIdentityField(
lookup_url_kwarg='tag_id', view_name='rest_api:tag-document-remove'
)
documents_count = serializers.SerializerMethodField()
class Meta:
extra_kwargs = {
'url': {
'lookup_field': 'pk', 'lookup_url_kwarg': 'tag_pk',
'lookup_url_kwarg': 'tag_id',
'view_name': 'rest_api:tag-detail'
}
},
}
fields = (
'color', 'documents_count', 'documents_url', 'id', 'label', 'url'
'attach_url', 'color', 'documents_url', 'label', 'id',
'remove_url', 'url'
)
model = Tag
def get_documents_count(self, instance):
return instance.documents.count()
"""
class WritableTagSerializer(serializers.ModelSerializer):
documents_pk_list = serializers.CharField(
help_text=_(
@@ -81,37 +89,303 @@ class WritableTagSerializer(serializers.ModelSerializer):
)
return instance
"""
class DocumentTagSerializer(TagSerializer):
document_tag_url = serializers.SerializerMethodField(
help_text=_(
'API URL pointing to a tag in relation to the document '
'attached to it. This URL is different than the canonical '
'tag URL.'
)
)
tag_pk = serializers.IntegerField(
help_text=_('Primary key of the tag to be added.'), write_only=True
)
#document_attach_url = serializers.HyperlinkedIdentityField(
# lookup_url_kwarg='document_id', view_name='rest_api:document-tag-attach'
#)
class Meta(TagSerializer.Meta):
fields = TagSerializer.Meta.fields + ('document_tag_url', 'tag_pk')
read_only_fields = TagSerializer.Meta.fields + ('document_tag_url',)
#fields = TagSerializer.Meta.fields + ('document_attach_url',)
fields = TagSerializer.Meta.fields
#fields = TagSerializer.Meta.fields + ('document_tag_url', 'tag_pk')
#fields = TagSerializer.Meta.fields + ('tag_pk',)
#read_only_fields = TagSerializer.Meta.fields + ('document_attach_url',)
read_only_fields = TagSerializer.Meta.fields
#read_only_fields = TagSerializer.Meta.fields
def get_document_tag_url(self, instance):
return reverse(
viewname='rest_api:document-tag-detail', kwargs={
'document_pk': self.context['document'].pk,
'tag_pk': instance.pk
}, request=self.context['request'], format=self.context['format']
#related_models = ('tags',)
#related_models_kwargs = {
# 'documents': {
## #'pk_list': 'tags_pk_list', 'model': Tag,
# #'model': Tag,
# 'object_permission': {'create': permission_tag_attach},
# #'add_method': 'add', 'add_method_kwargs': 'document'
# }
#}
'''
def create(self, validated_data):
"""
queryset = Tag.objects.filter(pk__in=validated_data['tags_pk_list'].split(','))
#permission = self.object_permission.get('create')
#if permission:
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_tag_attach, queryset=queryset,
user=self.context['request'].user
)
def create(self, validated_data):
queryset = AccessControlList.objects.filter_by_access(
for tag in queryset.all():
tag.attach_to(
document=self.context['document'],
user=self.context['request'].user
)
"""
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_tag_attach, queryset=Tag.objects.all(),
user=self.context['request'].user
)
tag = get_object_or_404(queryset=queryset, pk=validated_data['tag_pk'])
tag.documents.add(self.context['document'])
tag.attach_to(
document=self.context['document'],
user=self.context['request'].user
)
return tag
#return None
'''
def get_document_tag_url(self, instance):
return reverse(
viewname='rest_api:document-tag-detail', kwargs={
'document_id': self.context['document'].pk,
'tag_id': instance.pk
}, request=self.context['request'], format=self.context['format']
)
class DocumentTagAttachSerializer(serializers.Serializer):
tags_pk_list = serializers.CharField(
help_text=_(
'Comma separated list of tag primary keys that will be attached '
'to this document.'
), write_only=True
)
class TagAttachSerializer(serializers.Serializer):
#class TagAttachSerializer(TagSerializer):
documents_pk_list = serializers.CharField(
help_text=_(
'Comma separated list of document primary keys to which this '
'tag will be attached.'
), write_only=True
)
#class Meta(TagSerializer.Meta):
# fields = TagSerializer.Meta.fields + ('documents_pk_list',)
# read_only_fields = TagSerializer.Meta.fields
def attach(self, instance):
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_tag_attach, queryset=Document.objects.all(),
user=self.context['request'].user
)
for document in queryset.filter(pk__in=self.validated_data['documents_pk_list'].split(',')):
instance.attach_to(document=document, user=self.context['request'].user)
#print '@@@@@@@', self.validated_data['document_pk_list']
#print '@@@@@@@', instance
#print '22222', validated_data
#print '!!!', self.data['document_pk_list']
class TagRemoveSerializer(serializers.Serializer):
documents_pk_list = serializers.CharField(
help_text=_(
'Comma separated list of document primary keys from which this '
'tag will be removed.'
), write_only=True
)
def remove(self, instance):
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_tag_attach, queryset=Document.objects.all(),
user=self.context['request'].user
)
for document in queryset.filter(pk__in=self.validated_data['documents_pk_list'].split(',')):
instance.remove_from(document=document, user=self.context['request'].user)
class RelatedModel(object):
@classmethod
def generate(cls, serializer, validated_data):
result = []
kwargs = getattr(serializer.Meta, 'related_model_kwargs', {})
kwargs.update({'serializer': serializer})
for field_name in getattr(serializer.Meta, 'related_models', []):
kwargs.update({'field_name': field_name})
related_field = cls(**kwargs)
related_field.pop_pk_list(validated_data=validated_data)
result.append(related_field)
return result
def __init__(self, field_name, serializer, pk_list_field=None, model=None, object_permission=None):
self.field_name = field_name
self._pk_list_field = pk_list_field
self.model = model
self.object_permission = object_permission
self.serializer = serializer
def create(self, instance):
field = self.get_field(instance=instance)
field.clear()
#model = self.get_model()
queryset = self.get_model().objects.filter(pk__in=self.pk_list.split(','))
permission = self.object_permission.get('create')
if permission:
queryset = AccessControlList.objects.restrict_queryset(
permission=permission,
queryset=queryset,
user=self.serializer.context['request'].user
)
self.related_add()
field.add(*queryset)
#fieldqueryset=queryset)
#def related_add(self, queryset):
# self.get_field().add(*queryset)
#def _get_m2m_field(self, instance):
# getattr(instance, m2m_field_name).all()
"""
def _add_m2m(self, instance, m2m_pk_list, permission):
m2m_field = self._get_m2m_field()
m2m_field.clear()
queryset = AccessControlList.objects.restrict_queryset(
permission=permission,
queryset=m2m_model.objects.filter(pk__in=m2m_pk_list.split(',')),
user=self.context['request'].user
)
#m2m_field.add(*queryset)
self._m2m_add(m2m_field=m2m_field, queryset=queryset)
"""
def get_model(self):
return self.model or self.get_field.model
def get_field(self, instance):
return getattr(instance, self.field_name)
def get_pk_list_field_name(self):
return self._pk_list_field or '{}_pk_list'.format(self.field_name)
def pop_pk_list(self, validated_data):
self.pk_list = validated_data.pop(self.get_pk_list_field_name(), '')
class RelatedModelSerializerMixin(object):
#m2m_pk_list_name = 'documents_pk_list'
#m2m_field_name = 'documents'
#m2m_model = Document
"""
class Meta:
extra_kwargs = {
'url': {
'lookup_field': 'pk', 'lookup_url_kwarg': 'tag_pk',
'view_name': 'rest_api:tag-detail'
}
}
fields = (
'color', 'documents_count', 'documents_pk_list', 'documents_url',
'id', 'label', 'url'
)
model = Tag
related_models = ('documents',)
related_models_kwargs = {
'documents': {
'pk_list_field': 'documents_pk_list', 'model': Document,
'permissions': {'create': permission_tag_attach}
}
}
"""
def _get_m2m_field(self, instance):
getattr(instance, m2m_field_name).all()
def _add_m2m(self, instance, m2m_pk_list, permission):
m2m_field = self._get_m2m_field()
m2m_field.clear()
queryset = AccessControlList.objects.restrict_queryset(
permission=permission,
queryset=m2m_model.objects.filter(pk__in=m2m_pk_list.split(',')),
user=self.context['request'].user
)
#m2m_field.add(*queryset)
self._m2m_add(m2m_field=m2m_field, queryset=queryset)
#def _m2m_add(self, m2m_field, queryset):
# m2m_field.add(*queryset)
def _m2m_add(self, m2m_field, queryset):
for document in queryset.all():
m2m_field.add(document=document, user=self.context['request'].user)
def create(self, validated_data):
related_objects = RelatedModel.generate(
serializer=self, validated_data=validated_data
)
instance = super(RelatedModelSerializerMixin, self).create(
validated_data=validated_data
)
#TODO: return a container class
#TODO:related_objects.create(instance=instance)
for related_object in related_objects:
related_object.create(instance=instance)
#if m2m_pk_list:
## self._add_m2m(
# instance=instance, m2m_pk_list=m2m_pk_list,
# permission=permission_tag_add
# )
return instance
'''
# Extract the related field data before calling the superclass
# .create() and avoid an error due to unknown field data.
#related_models = self.Meta.related_models
#self.Meta.related_models
related_models_dictionary = {}
for related_model in self.Meta.related_models:
#if self.m2m_pk_list_name:
m2m_pk_list = validated_data.pop(self.get_related_model_pk_list(), '')
instance = super(RelatedObjectSerializerMixin, self).create(
validated_data=validated_data
)
if m2m_pk_list:
self._add_m2m(
instance=instance, m2m_pk_list=m2m_pk_list,
permission=permission_tag_add
)
return instance
'''

View File

@@ -0,0 +1,26 @@
'use strict';
var tagSelectionTemplate = function (tag, container) {
var $tag = $(
'<span class="label label-tag" style="background: ' + tag.element.dataset.color + ';"> ' + escape(tag.text) + '</span>'
);
container[0].style.background = tag.element.dataset.color;
return $tag;
}
var tagResultTemplate = function (tag) {
if (!tag.element) { return ''; }
var $tag = $(
'<span class="label label-tag" style="background: ' + tag.element.dataset.color + ';"> ' + escape(tag.text) + '</span>'
);
return $tag;
}
jQuery(document).ready(function() {
$('.select2-tags').select2({
templateSelection: tagSelectionTemplate,
templateResult: tagResultTemplate,
width: '100%'
});
});

View File

@@ -0,0 +1,5 @@
<div class="tag-container">
{% for tag in tags %}
{% include 'tags/tag_widget.html' with tag=tag %}
{% endfor %}
</div>

View File

@@ -1,2 +1 @@
{% include 'django/forms/widgets/select_option.html' %}

View File

@@ -9,15 +9,15 @@ TEST_TAG_INDEX_HAS_TAG = 'HAS_TAG'
TEST_TAG_INDEX_NO_TAG = 'NO_TAG'
TEST_TAG_INDEX_NODE_TEMPLATE = '''
{{% for tag in document.get_tags().all() %}}
{{% if tag.label == "{}" %}}
{}
{{% if tag.label == "{label}" %}}
{has_tag}
{{% else %}}
{not_tagged}
{{% endif %}}
{{% else %}}
NO_TAG
{{% endif %}}
{{% else %}}
NO_TAG
{not_tagged}
{{% endfor %}}
'''.format(
TEST_TAG_LABEL, TEST_TAG_INDEX_HAS_TAG, TEST_TAG_INDEX_NO_TAG,
TEST_TAG_INDEX_NO_TAG
label=TEST_TAG_LABEL, has_tag=TEST_TAG_INDEX_HAS_TAG,
not_tagged=TEST_TAG_INDEX_NO_TAG
).replace('\n', '')

View File

@@ -9,39 +9,100 @@ from .literals import (
class TagTestMixin(object):
def _create_tag(self):
self.tag = Tag.objects.create(
def _create_test_tag(self):
self.test_tag = Tag.objects.create(
color=TEST_TAG_COLOR, label=TEST_TAG_LABEL
)
class TagAPITestMixin(object):
def _request_api_tag_create_view(self):
return self.post(
viewname='rest_api:tag-list', data={
'label': TEST_TAG_LABEL, 'color': TEST_TAG_COLOR
'color': TEST_TAG_COLOR, 'label': TEST_TAG_LABEL
}
)
def _request_api_tag_create_and_attach_view(self):
return self.post(
viewname='rest_api:tag-list', data={
'color': TEST_TAG_COLOR, 'label': TEST_TAG_LABEL,
'document_id_list': self.document.pk
}
)
def _request_api_tag_delete_view(self):
return self.delete(
viewname='rest_api:tag-detail', kwargs={'tag_pk': self.tag.pk}
viewname='rest_api:tag-detail', kwargs={'tag_id': self.test_tag.pk}
)
def _request_api_tag_edit_via_patch_view(self):
def _request_api_tag_edit_patch_view(self):
return self.patch(
viewname='rest_api:tag-detail', kwargs={'tag_pk': self.tag.pk}, data={
viewname='rest_api:tag-detail', kwargs={
'tag_id': self.test_tag.pk
}, data={
'label': TEST_TAG_LABEL_EDITED,
'color': TEST_TAG_COLOR_EDITED
}
)
def _request_api_tag_edit_via_put_view(self):
def _request_api_tag_edit_put_view(self):
return self.put(
viewname='rest_api:tag-detail', kwargs={'tag_pk': self.tag.pk}, data={
viewname='rest_api:tag-detail', kwargs={
'tag_id': self.test_tag.pk
}, data={
'label': TEST_TAG_LABEL_EDITED,
'color': TEST_TAG_COLOR_EDITED
}
)
def _request_api_tag_list_view(self):
return self.get(viewname='rest_api:tag-list')
class TagViewTestMixin(object):
def _request_document_tag_multiple_attach_view(self):
return self.post(
viewname='tags:document_tag_multiple_attach',
kwargs={'document_id': self.document.pk}, data={
'tags': self.test_tag.pk,
}
)
def _request_document_multiple_tag_multiple_attach_view(self):
return self.post(
viewname='tags:document_multiple_tag_multiple_attach', data={
'id_list': self.document.pk, 'tags': self.test_tag.pk,
}
)
def _request_document_tag_multiple_remove_view(self):
return self.post(
viewname='tags:document_tag_multiple_remove',
kwargs={'document_id': self.document.pk}, data={
'tags': self.test_tag.pk,
}
)
def _request_document_multiple_tag_multiple_remove_view(self):
return self.post(
viewname='tags:document_multiple_tag_multiple_remove',
data={
'id_list': self.document.pk,
'tags': self.test_tag.pk,
}
)
def _request_document_tag_list_view(self):
return self.get(
viewname='tags:document_tag_list',
kwargs={
'document_id': self.document.pk,
}
)
# Normal tag view
def _request_tag_create_view(self):
return self.post(
viewname='tags:tag_create', data={
@@ -52,68 +113,19 @@ class TagTestMixin(object):
def _request_tag_delete_view(self):
return self.post(
viewname='tags:tag_delete', kwargs={'tag_pk': self.tag.pk}
viewname='tags:tag_delete', kwargs={'tag_id': self.test_tag.pk},
)
def _request_tag_edit_view(self):
return self.post(
viewname='tags:tag_edit', kwargs={'tag_pk': self.tag.pk}, data={
viewname='tags:tag_edit', kwargs={'tag_id': self.test_tag.pk},
data={
'label': TEST_TAG_LABEL_EDITED, 'color': TEST_TAG_COLOR_EDITED
}
)
def _request_multiple_delete_view(self):
def _request_tag_multiple_delete_view(self):
return self.post(
viewname='tags:tag_multiple_delete',
data={'id_list': self.tag.pk},
)
def _request_edit_tag_view(self):
return self.post(
viewname='tags:tag_edit', kwargs={'tag_pk': self.tag.pk}, data={
'label': TEST_TAG_LABEL_EDITED, 'color': TEST_TAG_COLOR_EDITED
}
)
def _request_create_tag_view(self):
return self.post(
viewname='tags:tag_create', data={
'label': TEST_TAG_LABEL,
'color': TEST_TAG_COLOR
}
)
def _request_attach_tag_view(self):
return self.post(
viewname='tags:tag_attach',
kwargs={'document_pk': self.document.pk}, data={
'tags': self.tag.pk,
'user': self.user.pk
}
)
def _request_multiple_attach_tag_view(self):
return self.post(
viewname='tags:multiple_documents_tag_attach', data={
'id_list': self.document.pk, 'tags': self.tag.pk,
'user': self.user.pk
}
)
def _request_single_document_multiple_tag_remove_view(self):
return self.post(
viewname='tags:single_document_multiple_tag_remove',
kwargs={'document_pk': self.document.pk}, data={
'id_list': self.document.pk,
'tags': self.tag.pk,
}
)
def _request_multiple_documents_selection_tag_remove_view(self):
return self.post(
viewname='tags:multiple_documents_selection_tag_remove',
data={
'id_list': self.document.pk,
'tags': self.tag.pk,
}
data={'id_list': self.test_tag.pk}
)

View File

@@ -21,11 +21,7 @@ from .literals import (
from .mixins import TagTestMixin
class TagAPITestCase(TagTestMixin, DocumentTestMixin, BaseAPITestCase):
def setUp(self):
super(TagAPITestCase, self).setUp()
self.login_user()
class TagAPITestCase(TagTestMixin, BaseAPITestCase):
def test_tag_create_view_no_permission(self):
response = self._request_api_tag_create_view()
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
@@ -46,284 +42,301 @@ class TagAPITestCase(TagTestMixin, DocumentTestMixin, BaseAPITestCase):
self.assertEqual(tag.color, TEST_TAG_COLOR)
def test_tag_delete_view_no_access(self):
self._create_tag()
self._create_test_tag()
response = self._request_api_tag_delete_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertTrue(self.tag in Tag.objects.all())
self.assertTrue(self.test_tag in Tag.objects.all())
self.assertEqual(Tag.objects.all().count(), 1)
def test_tag_delete_view_with_access(self):
self._create_tag()
self.grant_access(obj=self.tag, permission=permission_tag_delete)
self._create_test_tag()
self.grant_access(obj=self.test_tag, permission=permission_tag_delete)
response = self._request_api_tag_delete_view()
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertEqual(Tag.objects.all().count(), 0)
def test_tag_edit_via_patch_no_access(self):
self._create_tag()
response = self._request_api_tag_edit_via_patch_view()
def test_tag_edit_patch_view_no_access(self):
self._create_test_tag()
response = self._request_api_tag_edit_patch_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.tag.refresh_from_db()
self.assertEqual(self.tag.label, TEST_TAG_LABEL)
self.assertEqual(self.tag.color, TEST_TAG_COLOR)
self.test_tag.refresh_from_db()
self.assertEqual(self.test_tag.label, TEST_TAG_LABEL)
self.assertEqual(self.test_tag.color, TEST_TAG_COLOR)
self.assertEqual(Tag.objects.all().count(), 1)
def test_tag_edit_via_patch_with_access(self):
self._create_tag()
self.grant_access(obj=self.tag, permission=permission_tag_edit)
response = self._request_api_tag_edit_via_patch_view()
def test_tag_edit_patch_view_with_access(self):
self._create_test_tag()
self.grant_access(obj=self.test_tag, permission=permission_tag_edit)
response = self._request_api_tag_edit_patch_view()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.tag.refresh_from_db()
self.assertEqual(self.tag.label, TEST_TAG_LABEL_EDITED)
self.assertEqual(self.tag.color, TEST_TAG_COLOR_EDITED)
self.test_tag.refresh_from_db()
self.assertEqual(self.test_tag.label, TEST_TAG_LABEL_EDITED)
self.assertEqual(self.test_tag.color, TEST_TAG_COLOR_EDITED)
self.assertEqual(Tag.objects.all().count(), 1)
def test_tag_edit_via_put_no_access(self):
self._create_tag()
response = self._request_api_tag_edit_via_put_view()
def test_tag_edit_put_view_no_access(self):
self._create_test_tag()
response = self._request_api_tag_edit_put_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.tag.refresh_from_db()
self.assertEqual(self.tag.label, TEST_TAG_LABEL)
self.assertEqual(self.tag.color, TEST_TAG_COLOR)
self.test_tag.refresh_from_db()
self.assertEqual(self.test_tag.label, TEST_TAG_LABEL)
self.assertEqual(self.test_tag.color, TEST_TAG_COLOR)
self.assertEqual(Tag.objects.all().count(), 1)
def test_tag_edit_via_put_with_access(self):
self._create_tag()
self.grant_access(obj=self.tag, permission=permission_tag_edit)
response = self._request_api_tag_edit_via_put_view()
def test_tag_edit_put_view_with_access(self):
self._create_test_tag()
self.grant_access(obj=self.test_tag, permission=permission_tag_edit)
response = self._request_api_tag_edit_put_view()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.tag.refresh_from_db()
self.assertEqual(self.tag.label, TEST_TAG_LABEL_EDITED)
self.assertEqual(self.tag.color, TEST_TAG_COLOR_EDITED)
self.test_tag.refresh_from_db()
self.assertEqual(self.test_tag.label, TEST_TAG_LABEL_EDITED)
self.assertEqual(self.test_tag.color, TEST_TAG_COLOR_EDITED)
self.assertEqual(Tag.objects.all().count(), 1)
class DocumentAPITestCase(TagTestMixin, DocumentTestMixin, BaseAPITestCase):
auto_upload_document = False
def setUp(self):
super(DocumentAPITestCase, self).setUp()
self.login_user()
def _request_api_tag_document_list_view(self):
return self.get(
viewname='rest_api:tag-document-list',
kwargs={'tag_pk': self.tag.pk}
)
def test_tag_document_list_view_no_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
response = self._request_api_tag_document_list_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_tag_document_list_view_with_tag_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(obj=self.tag, permission=permission_tag_view)
response = self._request_api_tag_document_list_view()
def test_tag_list_view_no_access(self):
self._create_test_tag()
response = self._request_api_tag_list_view()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 0)
def test_tag_document_list_view_with_document_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(
obj=self.document, permission=permission_document_view
)
response = self._request_api_tag_document_list_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_tag_document_list_view_with_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(obj=self.tag, permission=permission_tag_view)
self.grant_access(
obj=self.document, permission=permission_document_view
)
response = self._request_api_tag_document_list_view()
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_api_tag_list_view()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data['results'][0]['uuid'],
force_text(self.document.uuid)
)
self.assertEqual(response.data['count'], 1)
def _request_api_document_attach_tag_view(self):
class DocumentTagAPITestCase(TagTestMixin, DocumentTestMixin, BaseAPITestCase):
auto_upload_document = False
def _request_api_document_tag_attach_view(self):
return self.post(
viewname='rest_api:document-tag-list',
kwargs={'document_pk': self.document.pk},
data={'tag_pk': self.tag.pk}
kwargs={'document_id': self.test_document.pk},
data={'tag_id': self.test_tag.pk}
)
def test_document_attach_tag_view_no_access(self):
self._create_tag()
self.document = self.upload_document()
response = self._request_api_document_attach_tag_view()
def test_document_tag_attach_view_no_access(self):
self._create_test_tag()
self.test_document = self.upload_document()
response = self._request_api_document_tag_attach_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertTrue(self.tag not in self.document.tags.all())
self.assertTrue(self.test_tag not in self.test_document.tags.all())
self.assertEqual(Tag.objects.all().count(), 1)
def test_document_attach_tag_view_with_document_access(self):
self._create_tag()
self.document = self.upload_document()
self.grant_access(obj=self.document, permission=permission_tag_attach)
response = self._request_api_document_attach_tag_view()
def test_document_tag_attach_view_with_document_access(self):
self._create_test_tag()
self.test_document = self.upload_document()
self.grant_access(obj=self.test_document, permission=permission_tag_attach)
response = self._request_api_document_tag_attach_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertTrue(self.tag not in self.document.tags.all())
self.assertTrue(self.test_tag not in self.test_document.tags.all())
self.assertEqual(Tag.objects.all().count(), 1)
def test_document_attach_tag_view_with_tag_access(self):
self._create_tag()
self.document = self.upload_document()
self.grant_access(obj=self.tag, permission=permission_tag_attach)
response = self._request_api_document_attach_tag_view()
def test_document_tag_attach_view_with_tag_access(self):
self._create_test_tag()
self.test_document = self.upload_document()
self.grant_access(obj=self.test_tag, permission=permission_tag_attach)
response = self._request_api_document_tag_attach_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertTrue(self.tag not in self.document.tags.all())
self.assertTrue(self.test_tag not in self.test_document.tags.all())
self.assertEqual(Tag.objects.all().count(), 1)
def test_document_attach_tag_view_with_full_access(self):
self._create_tag()
self.document = self.upload_document()
self.grant_access(obj=self.document, permission=permission_tag_attach)
self.grant_access(obj=self.tag, permission=permission_tag_attach)
response = self._request_api_document_attach_tag_view()
def test_document_tag_attach_view_with_full_access(self):
self._create_test_tag()
self.test_document = self.upload_document()
self.grant_access(
obj=self.test_document, permission=permission_tag_attach
)
self.grant_access(obj=self.test_tag, permission=permission_tag_attach)
response = self._request_api_document_tag_attach_view()
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(self.tag in self.document.tags.all())
self.assertTrue(self.test_tag in self.test_document.tags.all())
self.assertEqual(Tag.objects.all().count(), 1)
def _request_api_document_tag_detail_view(self):
return self.get(
viewname='rest_api:document-tag-detail', kwargs={
'document_pk': self.document.pk, 'tag_pk': self.tag.pk
'document_id': self.test_document.pk, 'tag_id': self.test_tag.pk
}
)
def test_document_tag_detail_view_no_permission(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
response = self._request_api_document_tag_detail_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_document_tag_detail_view_with_document_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(
obj=self.document, permission=permission_document_view
obj=self.test_document, permission=permission_document_view
)
response = self._request_api_document_tag_detail_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_document_tag_detail_view_with_tag_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(obj=self.tag, permission=permission_tag_view)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_tag, permission=permission_tag_view)
response = self._request_api_document_tag_detail_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_document_tag_detail_view_with_full_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(obj=self.tag, permission=permission_tag_view)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_tag, permission=permission_tag_view)
self.grant_access(
obj=self.document, permission=permission_tag_view
obj=self.test_document, permission=permission_tag_view
)
response = self._request_api_document_tag_detail_view()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['label'], self.tag.label)
self.assertEqual(response.data['label'], self.test_tag.label)
def _request_api_document_tag_list_view(self):
return self.get(
viewname='rest_api:document-tag-list',
kwargs={'document_pk': self.document.pk}
kwargs={'document_id': self.test_document.pk}
)
def test_document_tag_list_view_no_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
response = self._request_api_document_tag_list_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_document_tag_list_view_with_document_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(obj=self.document, permission=permission_tag_view)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_document, permission=permission_tag_view)
response = self._request_api_document_tag_list_view()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 0)
def test_document_tag_list_view_with_tag_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(obj=self.tag, permission=permission_tag_view)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_tag, permission=permission_tag_view)
response = self._request_api_document_tag_list_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_document_tag_list_view_with_full_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(obj=self.document, permission=permission_tag_view)
self.grant_access(obj=self.tag, permission=permission_tag_view)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_document, permission=permission_tag_view)
self.grant_access(obj=self.test_tag, permission=permission_tag_view)
response = self._request_api_document_tag_list_view()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['results'][0]['label'], self.tag.label)
self.assertEqual(
response.data['results'][0]['label'], self.test_tag.label
)
def _request_api_document_tag_remove_view(self):
return self.delete(
viewname='rest_api:document-tag-detail', kwargs={
'document_pk': self.document.pk, 'tag_pk': self.tag.pk
'document_id': self.test_document.pk, 'tag_id': self.test_tag.pk
}
)
def test_document_tag_remove_view_no_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
response = self._request_api_document_tag_remove_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertTrue(self.tag in self.document.tags.all())
self.assertTrue(self.test_tag in self.test_document.tags.all())
self.assertEqual(Tag.objects.all().count(), 1)
def test_document_tag_remove_view_with_document_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(obj=self.document, permission=permission_tag_remove)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_document, permission=permission_tag_remove)
response = self._request_api_document_tag_remove_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertTrue(self.tag in self.document.tags.all())
self.assertTrue(self.test_tag in self.test_document.tags.all())
self.assertEqual(Tag.objects.all().count(), 1)
def test_document_tag_remove_view_with_tag_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self.grant_access(obj=self.tag, permission=permission_tag_remove)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_tag, permission=permission_tag_remove)
response = self._request_api_document_tag_remove_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertTrue(self.tag in self.document.tags.all())
self.assertTrue(self.test_tag in self.test_document.tags.all())
self.assertEqual(Tag.objects.all().count(), 1)
def test_document_tag_remove_view_with_full_access(self):
self._create_tag()
self.document = self.upload_document()
self.tag.documents.add(self.document)
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(
obj=self.document, permission=permission_tag_remove
obj=self.test_document, permission=permission_tag_remove
)
self.grant_access(obj=self.tag, permission=permission_tag_remove)
self.grant_access(obj=self.test_tag, permission=permission_tag_remove)
response = self._request_api_document_tag_remove_view()
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertFalse(self.tag in self.document.tags.all())
self.assertFalse(self.test_tag in self.test_document.tags.all())
self.assertEqual(Tag.objects.all().count(), 1)
class TagDocumentAPITestCase(TagTestMixin, DocumentTestMixin, BaseAPITestCase):
auto_upload_document = False
def _request_api_tag_document_list_view(self):
return self.get(
viewname='rest_api:tag-document-list',
kwargs={'tag_id': self.test_tag.pk}
)
def test_tag_document_list_view_no_access(self):
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
response = self._request_api_tag_document_list_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_tag_document_list_view_with_tag_access(self):
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(obj=self.test_tag, permission=permission_tag_view)
response = self._request_api_tag_document_list_view()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 0)
def test_tag_document_list_view_with_document_access(self):
self._create_test_tag()
self.test_document = self.upload_document()
self.test_tag.documents.add(self.test_document)
self.grant_access(
obj=self.test_document, permission=permission_document_view
)
response = self._request_api_tag_document_list_view()
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_tag_document_list_view_with_access(self):
self._create_test_tag()
self.test_document = self.upload_document()
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_document_view
)
response = self._request_api_tag_document_list_view()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data['results'][0]['uuid'],
force_text(self.test_document.uuid)
)

View File

@@ -10,7 +10,7 @@ from ..permissions import permission_tag_create, permission_tag_edit
from .mixins import TagTestMixin
#TODO: Add tests for event_tag_remove and event_tag_attach
class TagEventsTestCase(TagTestMixin, GenericDocumentViewTestCase):
def setUp(self):
super(TagEventsTestCase, self).setUp()
@@ -38,10 +38,10 @@ class TagEventsTestCase(TagTestMixin, GenericDocumentViewTestCase):
self.assertEqual(event.verb, event_tag_created.id)
self.assertEqual(event.target, tag)
self.assertEqual(event.actor, self.user)
self.assertEqual(event.actor, self._test_case_user)
def test_tag_edit_event_no_permissions(self):
self._create_tag()
self._create_test_tag()
Action.objects.all().delete()
response = self._request_tag_edit_view()
@@ -49,11 +49,11 @@ class TagEventsTestCase(TagTestMixin, GenericDocumentViewTestCase):
self.assertEqual(Action.objects.count(), 0)
def test_tag_edit_event_with_access(self):
self._create_tag()
self._create_test_tag()
Action.objects.all().delete()
self.grant_access(
permission=permission_tag_edit, obj=self.tag
permission=permission_tag_edit, obj=self.test_tag
)
response = self._request_tag_edit_view()
@@ -63,5 +63,5 @@ class TagEventsTestCase(TagTestMixin, GenericDocumentViewTestCase):
event = Action.objects.first()
self.assertEqual(event.verb, event_tag_edited.id)
self.assertEqual(event.target, self.tag)
self.assertEqual(event.actor, self.user)
self.assertEqual(event.target, self.test_tag)
self.assertEqual(event.actor, self._test_case_user)

View File

@@ -11,9 +11,10 @@ from .literals import (
TEST_TAG_COLOR, TEST_TAG_LABEL, TEST_TAG_INDEX_HAS_TAG,
TEST_TAG_INDEX_NO_TAG, TEST_TAG_INDEX_NODE_TEMPLATE
)
from .mixins import TagTestMixin
class TagSignalIndexingTestCase(DocumentTestMixin, BaseTestCase):
class TagSignalIndexingTestCase(TagTestMixin, DocumentTestMixin, BaseTestCase):
auto_upload_document = False
def test_tag_indexing(self):
@@ -27,7 +28,8 @@ class TagSignalIndexingTestCase(DocumentTestMixin, BaseTestCase):
link_documents=True
)
tag = Tag.objects.create(color=TEST_TAG_COLOR, label=TEST_TAG_LABEL)
self._create_test_tag()
self.document = self.upload_document()
self.assertTrue(
@@ -36,7 +38,7 @@ class TagSignalIndexingTestCase(DocumentTestMixin, BaseTestCase):
).documents.all()
)
tag.documents.add(self.document)
self.test_tag.documents.add(self.document)
self.assertTrue(
self.document in IndexInstanceNode.objects.get(
@@ -44,7 +46,7 @@ class TagSignalIndexingTestCase(DocumentTestMixin, BaseTestCase):
).documents.all()
)
tag.delete()
self.test_tag.delete()
self.assertTrue(
self.document in IndexInstanceNode.objects.get(

View File

@@ -0,0 +1,41 @@
from __future__ import unicode_literals
from django.urls import reverse
from mayan.apps.documents.tests import GenericDocumentViewTestCase
from ..links import link_document_tag_list
from ..permissions import permission_tag_view
from .mixins import TagTestMixin
class DocumentLinksTestCase(TagTestMixin, GenericDocumentViewTestCase):
def _request_document_tag_list_link(self):
self.add_test_view(test_object=self.document)
context = self.get_test_view()
return link_document_tag_list.resolve(context=context)
def test_document_tag_list_no_permission(self):
self._create_test_tag()
resolved_link = self._request_document_tag_list_link()
self.assertEqual(resolved_link, None)
def test_document_tag_list_with_full_access(self):
self._create_test_tag()
self.grant_access(
obj=self.document, permission=permission_tag_view
)
self.grant_access(
obj=self.test_tag, permission=permission_tag_view
)
resolved_link = self._request_document_tag_list_link()
self.assertNotEqual(resolved_link, None)
self.assertEqual(
resolved_link.url,
reverse(
viewname='tags:document_tag_list',
kwargs={'document_id': self.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
@@ -14,21 +16,17 @@ from .literals import (
TEST_TAG_COLOR, TEST_TAG_COLOR_EDITED, TEST_TAG_LABEL,
TEST_TAG_LABEL_EDITED
)
from .mixins import TagTestMixin
from .mixins import TagTestMixin, TagViewTestMixin
class TagViewTestCase(TagTestMixin, GenericViewTestCase):
class TagViewTestCase(TagViewTestMixin, TagTestMixin, GenericViewTestCase):
def test_tag_create_view_no_permissions(self):
self.login_user()
response = self._request_tag_create_view()
self.assertEqual(response.status_code, 403)
self.assertEqual(Tag.objects.count(), 0)
def test_tag_create_view_with_permissions(self):
self.login_user()
self.grant_permission(permission=permission_tag_create)
response = self._request_tag_create_view()
self.assertEqual(response.status_code, 302)
@@ -39,18 +37,16 @@ class TagViewTestCase(TagTestMixin, GenericViewTestCase):
self.assertEqual(tag.color, TEST_TAG_COLOR)
def test_tag_delete_view_no_permissions(self):
self.login_user()
self._create_tag()
self._create_test_tag()
response = self._request_tag_delete_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(response.status_code, 404)
self.assertEqual(Tag.objects.count(), 1)
def test_tag_delete_view_with_access(self):
self.login_user()
self._create_tag()
self._create_test_tag()
self.grant_access(obj=self.tag, permission=permission_tag_delete)
self.grant_access(obj=self.test_tag, permission=permission_tag_delete)
response = self._request_tag_delete_view()
self.assertEqual(response.status_code, 302)
@@ -58,190 +54,295 @@ class TagViewTestCase(TagTestMixin, GenericViewTestCase):
self.assertEqual(Tag.objects.count(), 0)
def test_tag_multiple_delete_view_no_permissions(self):
self.login_user()
self._create_tag()
self._create_test_tag()
response = self._request_multiple_delete_view()
self.assertEqual(response.status_code, 302)
response = self._request_tag_multiple_delete_view()
self.assertEqual(response.status_code, 404)
self.assertEqual(Tag.objects.count(), 1)
def test_tag_multiple_delete_view_with_access(self):
self.login_user()
self._create_tag()
self._create_test_tag()
self.grant_access(obj=self.tag, permission=permission_tag_delete)
self.grant_access(obj=self.test_tag, permission=permission_tag_delete)
response = self._request_multiple_delete_view()
response = self._request_tag_multiple_delete_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(Tag.objects.count(), 0)
def test_tag_edit_view_no_permissions(self):
self.login_user()
self._create_tag()
self._create_test_tag()
response = self._request_edit_tag_view()
response = self._request_tag_edit_view()
self.assertEqual(response.status_code, 404)
tag = Tag.objects.get(pk=self.tag.pk)
tag = Tag.objects.get(pk=self.test_tag.pk)
self.assertEqual(tag.label, TEST_TAG_LABEL)
self.assertEqual(tag.color, TEST_TAG_COLOR)
def test_tag_edit_view_with_access(self):
self.login_user()
self._create_tag()
self._create_test_tag()
self.grant_access(obj=self.tag, permission=permission_tag_edit)
self.grant_access(obj=self.test_tag, permission=permission_tag_edit)
response = self._request_edit_tag_view()
response = self._request_tag_edit_view()
self.assertEqual(response.status_code, 302)
tag = Tag.objects.get(pk=self.tag.pk)
tag = Tag.objects.get(pk=self.test_tag.pk)
self.assertEqual(tag.label, TEST_TAG_LABEL_EDITED)
self.assertEqual(tag.color, TEST_TAG_COLOR_EDITED)
class TagDocumentsViewTestCase(TagTestMixin, GenericDocumentViewTestCase):
def _request_document_list_view(self):
return self.get(viewname='documents:document_list')
class TagDocumentsViewTestCase(TagViewTestMixin, TagTestMixin, GenericDocumentViewTestCase):
def test_document_tag_attach_view_no_permission(self):
self._create_test_tag()
def test_document_tags_widget_no_permissions(self):
self.login_user()
self._create_tag()
response = self._request_document_tag_multiple_attach_view()
self.assertEqual(response.status_code, 404)
self.assertEqual(self.test_document.tags.count(), 0)
self.tag.documents.add(self.document)
response = self._request_document_list_view()
self.assertNotContains(
response=response, text=TEST_TAG_LABEL, status_code=200
)
def test_document_tag_attach_view_with_document_access(self):
self._create_test_tag()
def test_document_tags_widget_with_access(self):
self.login_user()
self._create_tag()
self.tag.documents.add(self.document)
self.grant_access(obj=self.tag, permission=permission_tag_view)
self.grant_access(
obj=self.document, permission=permission_document_view
obj=self.test_document, permission=permission_tag_attach
)
response = self._request_document_list_view()
response = self._request_document_tag_multiple_attach_view()
self.assertContains(
response=response, text=TEST_TAG_LABEL, status_code=200
response=response, text=force_text(self.test_document),
status_code=200
)
self.assertNotContains(
response=response, text=force_text(self.test_tag), status_code=200
)
def test_document_attach_tag_view_no_permission(self):
self.login_user()
self._create_tag()
self.assertEqual(self.test_document.tags.count(), 0)
self.assertEqual(self.document.tags.count(), 0)
def test_document_tag_attach_view_with_tag_access(self):
self._create_test_tag()
self.grant_access(obj=self.tag, permission=permission_tag_attach)
self.grant_access(obj=self.test_tag, permission=permission_tag_attach)
response = self._request_document_tag_multiple_attach_view()
self.assertEqual(response.status_code, 404)
response = self._request_attach_tag_view()
# Redirect to previous URL and show warning message about having to
# select at least one object.
self.assertEqual(response.status_code, 302)
self.assertEqual(self.document.tags.count(), 0)
self.assertEqual(self.test_document.tags.count(), 0)
def test_document_attach_tag_view_with_access(self):
self.login_user()
self._create_tag()
def test_document_tag_attach_view_with_full_access(self):
self._create_test_tag()
self.assertEqual(self.document.tags.count(), 0)
self.grant_access(obj=self.document, permission=permission_tag_attach)
self.grant_access(obj=self.tag, permission=permission_tag_attach)
# permission_tag_view is needed because the form filters the
# choices
self.grant_access(obj=self.tag, permission=permission_tag_view)
response = self._request_attach_tag_view()
self.grant_access(
obj=self.test_document, permission=permission_tag_attach
)
self.grant_access(obj=self.test_tag, permission=permission_tag_attach)
response = self._request_document_tag_multiple_attach_view()
self.assertEqual(response.status_code, 302)
self.assertQuerysetEqual(
self.document.tags.all(), (repr(self.tag),)
self.test_document.tags.all(), (repr(self.test_tag),)
)
def test_document_multiple_attach_tag_view_no_permission(self):
self.login_user()
self._create_tag()
self.grant_permission(permission=permission_tag_view)
def test_document_single_tag_attach_view_with_full_access(self):
"""
Test to make sure only the tag is attached to the selected document
"""
self._create_test_tag()
self.test_document_2 = self.upload_document()
response = self._request_multiple_attach_tag_view()
self.assertEqual(response.status_code, 200)
self.assertEqual(self.document.tags.count(), 0)
def test_document_multiple_attach_tag_view_with_access(self):
self.login_user()
self._create_tag()
self.grant_access(obj=self.document, permission=permission_tag_attach)
self.grant_access(obj=self.tag, permission=permission_tag_attach)
# permission_tag_view is needed because the form filters the
# choices
self.grant_access(obj=self.tag, permission=permission_tag_view)
response = self._request_multiple_attach_tag_view()
self.grant_access(
obj=self.test_document, permission=permission_tag_attach
)
self.grant_access(
obj=self.test_document_2, permission=permission_tag_attach
)
self.grant_access(obj=self.test_tag, permission=permission_tag_attach)
response = self._request_document_tag_multiple_attach_view()
self.assertEqual(response.status_code, 302)
self.assertQuerysetEqual(
self.document.tags.all(), (repr(self.tag),)
self.test_document.tags.all(), (repr(self.test_tag),)
)
def test_single_document_multiple_tag_remove_view_no_permissions(self):
self.login_user()
self._create_tag()
self.assertEqual(self.test_document_2.tags.count(), 0)
self.document.tags.add(self.tag)
def test_document_multiple_tag_attach_view_no_permission(self):
self._create_test_tag()
self.grant_access(obj=self.tag, permission=permission_tag_view)
response = self._request_document_multiple_tag_multiple_attach_view()
self.assertEqual(response.status_code, 404)
self.assertEqual(self.test_document.tags.count(), 0)
response = self._request_single_document_multiple_tag_remove_view()
self.assertEqual(response.status_code, 200)
def test_document_multiple_tag_attach_view_with_document_access(self):
self._create_test_tag()
self.assertQuerysetEqual(self.document.tags.all(), (repr(self.tag),))
self.grant_access(
obj=self.test_document, permission=permission_tag_attach
)
def test_single_document_multiple_tag_remove_view_with_access(self):
self.login_user()
self._create_tag()
response = self._request_document_multiple_tag_multiple_attach_view()
self.document.tags.add(self.tag)
self.assertContains(
response=response, text=force_text(self.test_document),
status_code=200
)
self.assertNotContains(
response=response, text=force_text(self.test_tag), status_code=200
)
self.grant_access(obj=self.document, permission=permission_tag_remove)
self.grant_access(obj=self.tag, permission=permission_tag_remove)
self.grant_access(obj=self.tag, permission=permission_tag_view)
self.assertEqual(self.test_document.tags.count(), 0)
response = self._request_single_document_multiple_tag_remove_view()
def test_document_multiple_tag_attach_view_with_tag_access(self):
self._create_test_tag()
self.grant_access(obj=self.test_tag, permission=permission_tag_attach)
response = self._request_document_multiple_tag_multiple_attach_view()
self.assertEqual(response.status_code, 404)
self.assertEqual(self.test_document.tags.count(), 0)
def test_document_multiple_tag_attach_view_with_full_access(self):
self._create_test_tag()
self.grant_access(
obj=self.test_document, permission=permission_tag_attach
)
self.grant_access(obj=self.test_tag, permission=permission_tag_attach)
response = self._request_document_multiple_tag_multiple_attach_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(self.document.tags.count(), 0)
self.assertQuerysetEqual(
self.test_document.tags.all(), (repr(self.test_tag),)
)
def test_multiple_documents_selection_tag_remove_view_no_permissions(self):
self.login_user()
self._create_tag()
def test_document_tag_multiple_remove_view_no_permissions(self):
self._create_test_tag()
self.document.tags.add(self.tag)
self.test_document.tags.add(self.test_tag)
self.grant_access(obj=self.tag, permission=permission_tag_view)
response = self._request_document_tag_multiple_remove_view()
self.assertEqual(response.status_code, 404)
response = self._request_multiple_documents_selection_tag_remove_view()
self.assertEqual(response.status_code, 200)
self.assertQuerysetEqual(
self.test_document.tags.all(), (repr(self.test_tag),)
)
self.assertQuerysetEqual(self.document.tags.all(), (repr(self.tag),))
def test_document_tag_multiple_remove_view_with_document_access(self):
self._create_test_tag()
def test_multiple_documents_selection_tag_remove_view_with_access(self):
self.login_user()
self._create_tag()
self.test_document.tags.add(self.test_tag)
self.document.tags.add(self.tag)
self.grant_access(
obj=self.test_document, permission=permission_tag_remove
)
response = self._request_document_tag_multiple_remove_view()
self.assertNotContains(
response=response, text=self.test_tag, status_code=200
)
self.assertContains(
response=response, text=self.test_document, status_code=200
)
self.grant_access(obj=self.document, permission=permission_tag_remove)
self.grant_access(obj=self.tag, permission=permission_tag_remove)
self.grant_access(obj=self.tag, permission=permission_tag_view)
self.assertEqual(self.test_document.tags.count(), 1)
response = self._request_multiple_documents_selection_tag_remove_view()
def test_document_tag_multiple_remove_view_with_tag_access(self):
self._create_test_tag()
self.test_document.tags.add(self.test_tag)
self.grant_access(obj=self.test_tag, permission=permission_tag_remove)
response = self._request_document_tag_multiple_remove_view()
self.assertEqual(response.status_code, 404)
self.assertEqual(self.test_document.tags.count(), 1)
def test_document_tag_multiple_remove_view_with_full_access(self):
self._create_test_tag()
self.test_document.tags.add(self.test_tag)
self.grant_access(
obj=self.test_document, permission=permission_tag_remove
)
self.grant_access(obj=self.test_tag, permission=permission_tag_remove)
response = self._request_document_tag_multiple_remove_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(self.document.tags.count(), 0)
self.assertEqual(self.test_document.tags.count(), 0)
def test_document_tags_list_no_permissions(self):
self._create_test_tag()
self.test_tag.documents.add(self.test_document)
response = self._request_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_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_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_document_tag_list_view()
self.assertContains(
response=response, text=force_text(self.test_tag), status_code=200
)
def test_document_multiple_tag_remove_view_no_permissions(self):
self._create_test_tag()
self.test_document.tags.add(self.test_tag)
response = self._request_document_multiple_tag_multiple_remove_view()
self.assertEqual(response.status_code, 404)
self.assertQuerysetEqual(
self.test_document.tags.all(), (repr(self.test_tag),)
)
def test_document_multiple_tag_remove_view_with_full_access(self):
self._create_test_tag()
self.test_document.tags.add(self.test_tag)
self.grant_access(
obj=self.test_document, permission=permission_tag_remove
)
self.grant_access(obj=self.test_tag, permission=permission_tag_remove)
response = self._request_document_multiple_tag_multiple_remove_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(self.test_document.tags.count(), 0)

View File

@@ -13,12 +13,12 @@ from mayan.apps.sources.tests.literals import (
from ..models import Tag
from .literals import TEST_TAG_COLOR, TEST_TAG_LABEL
from .mixins import TagTestMixin
class TaggedDocumentUploadTestCase(GenericDocumentViewTestCase):
class TaggedDocumentUploadTestCase(TagTestMixin, GenericDocumentViewTestCase):
def setUp(self):
super(TaggedDocumentUploadTestCase, self).setUp()
self.login_user()
self.source = WebFormSource.objects.create(
enabled=True, label=TEST_SOURCE_LABEL,
uncompress=TEST_SOURCE_UNCOMPRESS_N
@@ -34,20 +34,15 @@ class TaggedDocumentUploadTestCase(GenericDocumentViewTestCase):
data={
'document_type_id': self.document_type.pk,
'source-file': file_object,
'tags': self.tag.pk
'tags': self.test_tag.pk
}
)
def _create_tag(self):
self.tag = Tag.objects.create(
color=TEST_TAG_COLOR, label=TEST_TAG_LABEL
)
def test_upload_interactive_view_with_access(self):
self._create_tag()
self._create_test_tag()
self.grant_access(
permission=permission_document_create, obj=self.document_type
)
response = self._request_upload_interactive_document_create_view()
self.assertEqual(response.status_code, 302)
self.assertTrue(self.tag in Document.objects.first().tags.all())
self.assertTrue(self.test_tag in Document.objects.first().tags.all())

View File

@@ -2,66 +2,75 @@ from __future__ import unicode_literals
from django.conf.urls import url
from .api_views import (
APIDocumentTagView, APIDocumentTagListView, APITagDocumentListView,
APITagListView, APITagView
)
#from .api_views import (
# APIDocumentTagView, APIDocumentTagListView, APITagDocumentListView,
# APITagListView, APITagView
#)
from .api_views import DocumentTagViewSet, TagViewSet
from .views import (
DocumentTagListView, TagAttachActionView, TagCreateView,
TagDeleteActionView, TagEditView, TagListView, TagRemoveActionView,
TagTaggedItemListView
TagDeleteActionView, TagDocumentListView, TagEditView, TagListView,
TagRemoveActionView
)
urlpatterns = [
url(regex=r'^tags/list/$', name='tag_list', view=TagListView.as_view()),
url(
regex=r'^documents/(?P<document_id>\d+)/tags/$',
name='document_tag_list', view=DocumentTagListView.as_view()
),
url(
regex=r'^documents/(?P<document_id>\d+)/tags/multiple/attach/$',
name='document_tag_multiple_attach', view=TagAttachActionView.as_view()
),
url(
regex=r'^documents/(?P<document_id>\d+)/tags/multiple/remove/$',
name='document_tag_multiple_remove',
view=TagRemoveActionView.as_view()
),
url(
regex=r'^documents/multiple/attach/$',
name='document_multiple_tag_multiple_attach',
view=TagAttachActionView.as_view()
),
url(
regex=r'^documents/multiple/tags/remove/$',
name='document_multiple_tag_multiple_remove',
view=TagRemoveActionView.as_view()
),
url(regex=r'^tags/$', name='tag_list', view=TagListView.as_view()),
url(
regex=r'^tags/create/$', name='tag_create',
view=TagCreateView.as_view()
),
url(
regex=r'^tags/(?P<tag_pk>\d+)/delete/$', name='tag_delete',
regex=r'^tags/(?P<tag_id>\d+)/delete/$', name='tag_delete',
view=TagDeleteActionView.as_view()
),
url(
regex=r'^tags/(?P<tag_pk>\d+)/edit/$', name='tag_edit',
regex=r'^tags/(?P<tag_id>\d+)/edit/$', name='tag_edit',
view=TagEditView.as_view()
),
url(
regex=r'^tags/(?P<tag_pk>\d+)/documents/$',
name='tag_tagged_item_list', view=TagTaggedItemListView.as_view()
regex=r'^tags/(?P<tag_id>\d+)/documents/$',
name='tag_document_list', view=TagDocumentListView.as_view()
),
url(
regex=r'^tags/multiple/delete/$', name='tag_multiple_delete',
view=TagDeleteActionView.as_view()
),
url(
regex=r'^tags/multiple/remove/document/(?P<document_pk>\d+)/$',
name='single_document_multiple_tag_remove',
view=TagRemoveActionView.as_view()
),
url(
regex=r'^tags/multiple/remove/document/multiple/$',
name='multiple_documents_selection_tag_remove',
view=TagRemoveActionView.as_view()
),
url(
regex=r'^documents/(?P<document_pk>\d+)/attach/$',
name='tag_attach', view=TagAttachActionView.as_view()
),
url(
regex=r'^documents/multiple/attach//$',
name='multiple_documents_tag_attach',
view=TagAttachActionView.as_view()
),
url(
regex=r'^documents/(?P<document_pk>\d+)/tags/$', name='document_tags',
view=DocumentTagListView.as_view(),
),
)
]
api_urls = [
api_router_entries = (
{'prefix': r'tags', 'viewset': TagViewSet, 'basename': 'tag'},
{
'prefix': r'documents/(?P<document_id>\d+)/tags',
'viewset': DocumentTagViewSet, 'basename': 'document_tag'
},
)
"""
url(
regex=r'^tags/(?P<tag_pk>\d+)/documents/$',
name='tag-document-list', view=APITagDocumentListView.as_view(),
@@ -79,4 +88,4 @@ api_urls = [
regex=r'^documents/(?P<document_pk>\d+)/tags/(?P<tag_pk>[0-9]+)/$',
name='document-tag-detail', view=APIDocumentTagView.as_view()
),
]
"""

View File

@@ -9,19 +9,20 @@ from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _, ungettext
from mayan.apps.acls.models import AccessControlList
from mayan.apps.common.views import (
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
from .forms import TagMultipleSelectionForm
from .icons import (
icon_menu_tags, icon_tag_delete_submit, icon_tag_remove_submit
icon_menu_tags, icon_tag_delete_submit, icon_document_tag_multiple_remove_submit
)
from .links import link_tag_attach, link_tag_create
from .links import link_document_tag_multiple_attach, link_tag_create
from .models import Tag
from .permissions import (
permission_tag_attach, permission_tag_create, permission_tag_delete,
@@ -34,7 +35,7 @@ logger = logging.getLogger(__name__)
class TagAttachActionView(MultipleObjectFormActionView):
form_class = TagMultipleSelectionForm
model = Document
pk_url_kwarg = 'document_pk'
pk_url_kwarg = 'document_id'
object_permission = permission_tag_attach
success_message = _('Tag attach request performed on %(count)d document')
success_message_plural = _(
@@ -42,7 +43,7 @@ class TagAttachActionView(MultipleObjectFormActionView):
)
def get_extra_context(self):
queryset = self.get_queryset()
queryset = self.get_object_list()
result = {
'submit_label': _('Attach'),
@@ -66,7 +67,7 @@ class TagAttachActionView(MultipleObjectFormActionView):
return result
def get_form_extra_kwargs(self):
queryset = self.get_queryset()
queryset = self.get_object_list()
result = {
'help_text': _('Tags to be attached.'),
'permission': permission_tag_attach,
@@ -85,44 +86,45 @@ class TagAttachActionView(MultipleObjectFormActionView):
return result
def get_post_action_redirect(self):
queryset = self.get_queryset()
queryset = self.get_object_list()
if queryset.count() == 1:
return reverse(
viewname='tags:document_tags', kwargs={
'document_pk': queryset.first().pk
viewname='tags:document_tag_list', kwargs={
'document_id': queryset.first().pk
}
)
else:
return super(TagAttachActionView, self).get_post_action_redirect()
def object_action(self, form, instance):
attached_tags = instance.get_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(
obj=tag, permissions=permission_tag_attach,
user=self.request.user
)
tag_list = AccessControlList.objects.restrict_queryset(
permission=permission_tag_attach, queryset=form.cleaned_data['tags'],
user=self.request.user
)
for tag in tag_list:
if tag in attached_tags:
messages.warning(
self.request, _(
message=_(
'Document "%(document)s" is already tagged as '
'"%(tag)s"'
) % {
'document': instance, 'tag': tag
}
}, request=self.request
)
else:
tag.attach_to(document=instance, user=self.request.user)
messages.success(
self.request,
_(
message=_(
'Tag "%(tag)s" attached successfully to document '
'"%(document)s".'
) % {
'document': instance, 'tag': tag
}
}, request=self.request
)
@@ -130,7 +132,7 @@ class TagCreateView(SingleObjectCreateView):
extra_context = {'title': _('Create tag')}
fields = ('label', 'color')
model = Tag
post_action_redirect = reverse_lazy('tags:tag_list')
post_action_redirect = reverse_lazy(viewname='tags:tag_list')
view_permission = permission_tag_create
def get_save_extra_data(self):
@@ -139,8 +141,8 @@ class TagCreateView(SingleObjectCreateView):
class TagDeleteActionView(MultipleObjectConfirmActionView):
model = Tag
pk_url_kwarg = 'tag_pk'
post_action_redirect = reverse_lazy('tags:tag_list')
pk_url_kwarg = 'tag_id'
post_action_redirect = reverse_lazy(viewname='tags:tag_list')
object_permission = permission_tag_delete
success_message = _('Tag delete request performed on %(count)d tag')
success_message_plural = _(
@@ -155,9 +157,9 @@ class TagDeleteActionView(MultipleObjectConfirmActionView):
'submit_icon_class': icon_tag_delete_submit,
'submit_label': _('Delete'),
'title': ungettext(
'Delete the selected tag?',
'Delete the selected tags?',
queryset.count()
singular='Delete the selected tag?',
plural='Delete the selected tags?',
number=queryset.count()
)
}
@@ -175,13 +177,14 @@ class TagDeleteActionView(MultipleObjectConfirmActionView):
try:
instance.delete()
messages.success(
self.request, _('Tag "%s" deleted successfully.') % instance
message=_('Tag "%s" deleted successfully.') % instance,
request=self.request
)
except Exception as exception:
messages.error(
self.request, _('Error deleting tag "%(tag)s": %(error)s') % {
message=_('Error deleting tag "%(tag)s": %(error)s') % {
'tag': instance, 'error': exception
}
}, request=self.request
)
@@ -189,9 +192,8 @@ class TagEditView(SingleObjectEditView):
fields = ('label', 'color')
model = Tag
object_permission = permission_tag_edit
object_permission_raise_404 = True
pk_url_kwarg = 'tag_pk'
post_action_redirect = reverse_lazy('tags:tag_list')
pk_url_kwarg = 'tag_id'
post_action_redirect = reverse_lazy(viewname='tags:tag_list')
def get_extra_context(self):
return {
@@ -222,22 +224,24 @@ class TagListView(SingleObjectListView):
'title': _('Tags'),
}
def get_object_list(self):
return self.get_tag_queryset()
def get_tag_queryset(self):
def get_source_queryset(self):
#return self.get_tag_queryset()
return Tag.objects.all()
#def get_tag_queryset(self):
# return Tag.objects.all()
class TagTaggedItemListView(DocumentListView):
def get_tag(self):
return get_object_or_404(klass=Tag, pk=self.kwargs['tag_pk'])
class TagDocumentListView(ExternalObjectMixin, DocumentListView):
external_object_class = Tag
external_object_permission = permission_tag_view
external_object_pk_url_kwarg = 'tag_id'
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(TagTaggedItemListView, self).get_extra_context()
context = super(TagDocumentListView, self).get_extra_context()
context.update(
{
'column_class': 'col-xs-12 col-sm-6 col-md-4 col-lg-3',
@@ -247,57 +251,56 @@ class TagTaggedItemListView(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['document_pk']
)
AccessControlList.objects.check_access(
permissions=permission_document_view, user=request.user,
obj=self.document
)
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 = 'document_id'
def get_extra_context(self):
context = super(DocumentTagListView, self).get_extra_context()
context.update(
{
'hide_link': True,
'no_results_main_link': link_tag_attach.resolve(
'no_results_main_link': link_document_tag_multiple_attach.resolve(
context=RequestContext(
self.request, {'object': self.document}
self.request, {'object': self.get_external_object()}
)
),
'no_results_title': _('Document has no tags attached'),
'object': self.document,
'title': _('Tags for document: %s') % self.document,
'object': self.get_external_object(),
'title': _(
'Tags for document: %s'
) % self.get_external_object(),
}
)
return context
def get_tag_queryset(self):
return self.document.get_tags().all()
#def get_tag_queryset(self):
def get_source_queryset(self):
return self.get_external_object().get_tags(
permission=permission_tag_view, user=self.request.user
).all()
class TagRemoveActionView(MultipleObjectFormActionView):
form_class = TagMultipleSelectionForm
model = Document
object_permission = permission_tag_remove
pk_url_kwarg = 'document_id'
success_message = _('Tag remove request performed on %(count)d document')
success_message_plural = _(
'Tag remove request performed on %(count)d documents'
)
def get_extra_context(self):
queryset = self.get_queryset()
queryset = self.get_object_list()
result = {
'submit_icon_class': icon_tag_remove_submit,
'submit_icon_class': icon_document_tag_multiple_remove_submit,
'submit_label': _('Remove'),
'title': ungettext(
singular='Remove tags to %(count)d document',
@@ -321,7 +324,7 @@ class TagRemoveActionView(MultipleObjectFormActionView):
return result
def get_form_extra_kwargs(self):
queryset = self.get_queryset()
queryset = self.get_object_list()
result = {
'help_text': _('Tags to be removed.'),
'permission': permission_tag_remove,
@@ -338,41 +341,43 @@ class TagRemoveActionView(MultipleObjectFormActionView):
return result
def get_post_action_redirect(self):
queryset = self.get_queryset()
queryset = self.get_object_list()
if queryset.count() == 1:
return reverse(
viewname='tags:document_tags', kwargs={
'document_pk': queryset.first().pk
viewname='tags:document_tag_list', kwargs={
'document_id': queryset.first().pk
}
)
else:
return super(TagRemoveActionView, self).get_post_action_redirect()
def object_action(self, form, instance):
attached_tags = instance.get_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(
obj=tag, permissions=permission_tag_remove,
user=self.request.user
)
tag_list = AccessControlList.objects.restrict_queryset(
permission=permission_tag_remove,
queryset=form.cleaned_data['tags'],
user=self.request.user
)
for tag in tag_list:
if tag not in attached_tags:
messages.warning(
self.request, _(
message=_(
'Document "%(document)s" wasn\'t tagged as "%(tag)s'
) % {
'document': instance, 'tag': tag
}
}, request=self.request
)
else:
tag.remove_from(document=instance, user=self.request.user)
messages.success(
self.request,
_(
message=_(
'Tag "%(tag)s" removed successfully from document '
'"%(document)s".'
) % {
'document': instance, 'tag': tag
}
}, request=self.request
)

View File

@@ -18,39 +18,11 @@ class TagFormWidget(forms.SelectMultiple):
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
result = super(TagFormWidget, self).create_option(
name=name, value=value, label='{}'.format(conditional_escape(label)),
selected=selected, index=index, subindex=subindex, attrs=attrs
attrs=attrs, index=index,
label='{}'.format(conditional_escape(label)), name=name,
selected=selected, subindex=subindex, value=value
)
result['attrs']['data-color'] = self.queryset.get(pk=value).color
return result
def widget_document_tags(document, user):
"""
A tag widget that displays the tags for the given document
"""
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
result = ['<div class="tag-container">']
tags = AccessControlList.objects.filter_by_access(
permission_tag_view, user, queryset=document.get_tags().all()
)
for tag in tags:
result.append(widget_single_tag(tag))
result.append('</div>')
if tags:
return mark_safe(''.join(result))
else:
return ''
def widget_single_tag(tag):
return render_to_string('tags/tag_widget.html', {'tag': tag})

View File

@@ -22,17 +22,10 @@ class WizardStepTags(WizardStep):
Tag = apps.get_model(app_label='tags', model_name='Tag')
return Tag.objects.exists()
@classmethod
def get_form_kwargs(self, wizard):
return {
'help_text': _('Tags to be attached.'),
'user': wizard.request.user
}
@classmethod
def done(cls, wizard):
result = {}
cleaned_data = wizard.get_cleaned_data_for_step(cls.name)
cleaned_data = wizard.get_cleaned_data_for_step(step=cls.name)
if cleaned_data:
result['tags'] = [
force_text(tag.pk) for tag in cleaned_data['tags']
@@ -40,13 +33,20 @@ class WizardStepTags(WizardStep):
return result
@classmethod
def get_form_kwargs(self, wizard):
return {
'help_text': _('Tags to be attached.'),
'user': wizard.request.user
}
@classmethod
def step_post_upload_process(cls, document, querystring=None):
furl_instance = furl(querystring)
furl_instance = furl(args=querystring)
Tag = apps.get_model(app_label='tags', model_name='Tag')
for tag in Tag.objects.filter(pk__in=furl_instance.args.getlist('tags')):
tag.documents.add(document)
WizardStep.register(WizardStepTags)
WizardStep.register(step=WizardStepTags)

View File

@@ -38,8 +38,9 @@ class AttachTagAction(WorkflowAction):
user = request.user
logger.debug('user: %s', user)
queryset = AccessControlList.objects.filter_by_access(
self.permission, user, queryset=Tag.objects.all()
queryset = AccessControlList.objects.restrict_queryset(
permission=self.permission, queryset=Tag.objects.all(),
user=user
)
self.fields['tags']['kwargs']['queryset'] = queryset