Refactor the workflow for removing tags from single or multiple documents.
This commit is contained in:
@@ -25,6 +25,7 @@ the user links
|
|||||||
- Tags are alphabetically ordered by label
|
- Tags are alphabetically ordered by label
|
||||||
- Stop loading theme fonts from the web
|
- Stop loading theme fonts from the web
|
||||||
- Add support for attaching multiple tags to single or multiple documents.
|
- Add support for attaching multiple tags to single or multiple documents.
|
||||||
|
- Refactor the workflow for removing tags from single and multiple documents.
|
||||||
|
|
||||||
Removals
|
Removals
|
||||||
--------
|
--------
|
||||||
|
|||||||
@@ -91,7 +91,10 @@ class DocumentCreateWizard(ViewPermissionCheckMixin, SessionWizardView):
|
|||||||
return {'user': self.request.user}
|
return {'user': self.request.user}
|
||||||
|
|
||||||
if step == STEP_TAGS:
|
if step == STEP_TAGS:
|
||||||
return {'user': self.request.user}
|
return {
|
||||||
|
'help_text': _('Tags to be attached.'),
|
||||||
|
'user': self.request.user
|
||||||
|
}
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|||||||
@@ -127,10 +127,6 @@ class TagsApp(MayanAppConfig):
|
|||||||
menu_multi_item.bind_links(
|
menu_multi_item.bind_links(
|
||||||
links=(link_tag_multiple_delete,), sources=(Tag,)
|
links=(link_tag_multiple_delete,), sources=(Tag,)
|
||||||
)
|
)
|
||||||
menu_multi_item.bind_links(
|
|
||||||
links=(link_single_document_multiple_tag_remove,),
|
|
||||||
sources=(DocumentTag,)
|
|
||||||
)
|
|
||||||
menu_object.bind_links(
|
menu_object.bind_links(
|
||||||
links=(
|
links=(
|
||||||
link_tag_tagged_item_list, link_tag_edit, link_acl_list,
|
link_tag_tagged_item_list, link_tag_edit, link_acl_list,
|
||||||
@@ -139,7 +135,7 @@ class TagsApp(MayanAppConfig):
|
|||||||
sources=(Tag,)
|
sources=(Tag,)
|
||||||
)
|
)
|
||||||
menu_sidebar.bind_links(
|
menu_sidebar.bind_links(
|
||||||
links=(link_tag_attach,),
|
links=(link_tag_attach, link_single_document_multiple_tag_remove),
|
||||||
sources=(
|
sources=(
|
||||||
'tags:document_tags', 'tags:tag_remove',
|
'tags:document_tags', 'tags:tag_remove',
|
||||||
'tags:tag_multiple_remove', 'tags:tag_attach'
|
'tags:tag_multiple_remove', 'tags:tag_attach'
|
||||||
|
|||||||
@@ -14,33 +14,21 @@ from .widgets import TagFormWidget
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TagListForm(forms.Form):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
user = kwargs.pop('user', None)
|
|
||||||
logger.debug('user: %s', user)
|
|
||||||
super(TagListForm, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
queryset = AccessControlList.objects.filter_by_access(
|
|
||||||
permission_tag_view, user, queryset=Tag.objects.all()
|
|
||||||
)
|
|
||||||
|
|
||||||
self.fields['tag'] = forms.ModelChoiceField(
|
|
||||||
queryset=queryset, label=_('Tags')
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TagMultipleSelectionForm(forms.Form):
|
class TagMultipleSelectionForm(forms.Form):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
help_text = kwargs.pop('help_text', None)
|
||||||
|
queryset = kwargs.pop('queryset', Tag.objects.all())
|
||||||
user = kwargs.pop('user', None)
|
user = kwargs.pop('user', None)
|
||||||
|
|
||||||
logger.debug('user: %s', user)
|
logger.debug('user: %s', user)
|
||||||
super(TagMultipleSelectionForm, self).__init__(*args, **kwargs)
|
super(TagMultipleSelectionForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
queryset = AccessControlList.objects.filter_by_access(
|
queryset = AccessControlList.objects.filter_by_access(
|
||||||
permission_tag_view, user, queryset=Tag.objects.all()
|
permission_tag_view, user, queryset=queryset
|
||||||
)
|
)
|
||||||
|
|
||||||
self.fields['tags'] = forms.ModelMultipleChoiceField(
|
self.fields['tags'] = forms.ModelMultipleChoiceField(
|
||||||
label=_('Tags'), help_text=_('Tags to attach to the document.'),
|
label=_('Tags'), help_text=help_text,
|
||||||
queryset=queryset, required=False,
|
queryset=queryset, required=False,
|
||||||
widget=TagFormWidget(attrs={'class': 'select2'}, queryset=queryset)
|
widget=TagFormWidget(attrs={'class': 'select2'}, queryset=queryset)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ from .api_views import (
|
|||||||
)
|
)
|
||||||
from .views import (
|
from .views import (
|
||||||
DocumentTagListView, TagAttachActionView, TagCreateView,
|
DocumentTagListView, TagAttachActionView, TagCreateView,
|
||||||
TagDeleteActionView, TagEditView, TagListView, TagTaggedItemListView,
|
TagDeleteActionView, TagEditView, TagListView, TagRemoveActionView,
|
||||||
multiple_documents_selection_tag_remove,
|
TagTaggedItemListView
|
||||||
single_document_multiple_tag_remove
|
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -31,13 +30,13 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
|
|
||||||
url(
|
url(
|
||||||
r'^multiple/remove/document/(?P<document_id>\d+)/$',
|
r'^multiple/remove/document/(?P<pk>\d+)/$',
|
||||||
single_document_multiple_tag_remove,
|
TagRemoveActionView.as_view(),
|
||||||
name='single_document_multiple_tag_remove'
|
name='single_document_multiple_tag_remove'
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^multiple/remove/document/multiple/$',
|
r'^multiple/remove/document/multiple/$',
|
||||||
multiple_documents_selection_tag_remove,
|
TagRemoveActionView.as_view(),
|
||||||
name='multiple_documents_selection_tag_remove'
|
name='multiple_documents_selection_tag_remove'
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,8 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.urlresolvers import reverse, reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.conf import settings
|
from django.shortcuts import get_object_or_404
|
||||||
from django.http import HttpResponseRedirect
|
|
||||||
from django.shortcuts import get_object_or_404, render_to_response
|
|
||||||
from django.template import RequestContext
|
|
||||||
from django.utils.translation import ugettext_lazy as _, ungettext
|
from django.utils.translation import ugettext_lazy as _, ungettext
|
||||||
|
|
||||||
from acls.models import AccessControlList
|
from acls.models import AccessControlList
|
||||||
@@ -19,7 +16,7 @@ from documents.models import Document
|
|||||||
from documents.views import DocumentListView
|
from documents.views import DocumentListView
|
||||||
from documents.permissions import permission_document_view
|
from documents.permissions import permission_document_view
|
||||||
|
|
||||||
from .forms import TagMultipleSelectionForm, TagListForm
|
from .forms import TagMultipleSelectionForm
|
||||||
from .models import Tag
|
from .models import Tag
|
||||||
from .permissions import (
|
from .permissions import (
|
||||||
permission_tag_attach, permission_tag_create, permission_tag_delete,
|
permission_tag_attach, permission_tag_create, permission_tag_delete,
|
||||||
@@ -44,8 +41,8 @@ class TagAttachActionView(MultipleObjectFormActionView):
|
|||||||
result = {
|
result = {
|
||||||
'submit_label': _('Attach'),
|
'submit_label': _('Attach'),
|
||||||
'title': ungettext(
|
'title': ungettext(
|
||||||
'Attach tag to document',
|
'Attach tags to document',
|
||||||
'Attach tag to documents',
|
'Attach tags to documents',
|
||||||
queryset.count()
|
queryset.count()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -54,14 +51,27 @@ class TagAttachActionView(MultipleObjectFormActionView):
|
|||||||
result.update(
|
result.update(
|
||||||
{
|
{
|
||||||
'object': queryset.first(),
|
'object': queryset.first(),
|
||||||
'title': _('Attach tag to document: %s') % queryset.first()
|
'title': _('Attach tags to document: %s') % queryset.first()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_form_extra_kwargs(self):
|
def get_form_extra_kwargs(self):
|
||||||
return {'user': self.request.user}
|
queryset = self.get_queryset()
|
||||||
|
result = {
|
||||||
|
'help_text': _('Tags to be attached.'),
|
||||||
|
'user': self.request.user
|
||||||
|
}
|
||||||
|
|
||||||
|
if queryset.count() == 1:
|
||||||
|
result.update(
|
||||||
|
{
|
||||||
|
'queryset': Tag.objects.exclude(pk__in=queryset.first().tags.all())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def object_action(self, form, instance):
|
def object_action(self, form, instance):
|
||||||
attached_tags = instance.attached_tags()
|
attached_tags = instance.attached_tags()
|
||||||
@@ -218,138 +228,78 @@ class DocumentTagListView(TagListView):
|
|||||||
return self.document.attached_tags().all()
|
return self.document.attached_tags().all()
|
||||||
|
|
||||||
|
|
||||||
def tag_remove(request, document_id=None, document_id_list=None, tag_id=None, tag_id_list=None):
|
class TagRemoveActionView(MultipleObjectFormActionView):
|
||||||
if document_id:
|
form_class = TagMultipleSelectionForm
|
||||||
documents = Document.objects.filter(pk=document_id)
|
model = Document
|
||||||
elif document_id_list:
|
object_permission = permission_tag_remove
|
||||||
documents = Document.objects.filter(pk__in=document_id_list)
|
success_message = _('Tag remove request performed on %(count)d document')
|
||||||
|
success_message_plural = _(
|
||||||
|
'Tag remove request performed on %(count)d documents'
|
||||||
|
)
|
||||||
|
|
||||||
if not documents:
|
def get_extra_context(self):
|
||||||
messages.error(
|
queryset = self.get_queryset()
|
||||||
request, _('Must provide at least one tagged document.')
|
|
||||||
)
|
result = {
|
||||||
return HttpResponseRedirect(
|
'submit_label': _('Remove'),
|
||||||
request.META.get(
|
'title': ungettext(
|
||||||
'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)
|
'Remove tags from document',
|
||||||
|
'Remove tags from documents',
|
||||||
|
queryset.count()
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
documents = AccessControlList.objects.filter_by_access(
|
if queryset.count() == 1:
|
||||||
permission_tag_remove, request.user, documents
|
result.update(
|
||||||
)
|
{
|
||||||
|
'object': queryset.first(),
|
||||||
post_action_redirect = None
|
'title': _('Remove tags from document: %s') % queryset.first()
|
||||||
|
|
||||||
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
|
||||||
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'previous': previous,
|
|
||||||
'next': next,
|
|
||||||
}
|
|
||||||
|
|
||||||
template = 'appearance/generic_confirm.html'
|
|
||||||
if tag_id:
|
|
||||||
tags = Tag.objects.filter(pk=tag_id)
|
|
||||||
elif tag_id_list:
|
|
||||||
tags = Tag.objects.filter(pk__in=tag_id_list)
|
|
||||||
else:
|
|
||||||
template = 'appearance/generic_form.html'
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
form = TagListForm(request.POST, user=request.user)
|
|
||||||
if form.is_valid():
|
|
||||||
tags = Tag.objects.filter(pk=form.cleaned_data['tag'].pk)
|
|
||||||
else:
|
|
||||||
if not tag_id and not tag_id_list:
|
|
||||||
form = TagListForm(user=request.user)
|
|
||||||
tags = Tag.objects.none()
|
|
||||||
|
|
||||||
context['form'] = form
|
|
||||||
if len(documents) == 1:
|
|
||||||
context['object'] = documents.first()
|
|
||||||
context['title'] = _(
|
|
||||||
'Remove tag from document: %s.'
|
|
||||||
) % ', '.join([unicode(d) for d in documents])
|
|
||||||
elif len(documents) > 1:
|
|
||||||
context['title'] = _(
|
|
||||||
'Remove tag from documents: %s.'
|
|
||||||
) % ', '.join([unicode(d) for d in documents])
|
|
||||||
|
|
||||||
if tags:
|
|
||||||
if tags.count() == 1:
|
|
||||||
if documents.count() == 1:
|
|
||||||
context['object'] = documents.first()
|
|
||||||
context['title'] = _(
|
|
||||||
'Remove the tag "%(tag)s" from the document: %(document)s?'
|
|
||||||
) % {
|
|
||||||
'tag': ', '.join([unicode(d) for d in tags]),
|
|
||||||
'document': ', '.join([unicode(d) for d in documents])
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_form_extra_kwargs(self):
|
||||||
|
queryset = self.get_queryset()
|
||||||
|
result = {
|
||||||
|
'help_text': _('Tags to be removed.'),
|
||||||
|
'user': self.request.user
|
||||||
|
}
|
||||||
|
|
||||||
|
if queryset.count() == 1:
|
||||||
|
result.update(
|
||||||
|
{
|
||||||
|
'queryset': queryset.first().tags.all()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def object_action(self, form, instance):
|
||||||
|
attached_tags = instance.attached_tags()
|
||||||
|
|
||||||
|
for tag in form.cleaned_data['tags']:
|
||||||
|
AccessControlList.objects.check_access(
|
||||||
|
obj=tag, permissions=permission_tag_view,
|
||||||
|
user=self.request.user
|
||||||
|
)
|
||||||
|
|
||||||
|
if tag not in attached_tags:
|
||||||
|
messages.warning(
|
||||||
|
self.request, _(
|
||||||
|
'Document "%(document)s" wasn\'t tagged as "%(tag)s'
|
||||||
|
) % {
|
||||||
|
'document': instance, 'tag': tag
|
||||||
|
}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
context['title'] = _(
|
tag.documents.remove(instance)
|
||||||
'Remove the tag "%(tag)s" from the documents: %(documents)s?'
|
messages.success(
|
||||||
) % {
|
self.request,
|
||||||
'tag': ', '.join([unicode(d) for d in tags]),
|
_(
|
||||||
'documents': ', '.join([unicode(d) for d in documents])
|
'Tag "%(tag)s" removed successfully from document '
|
||||||
}
|
'"%(document)s".'
|
||||||
elif tags.count() > 1:
|
) % {
|
||||||
if documents.count() == 1:
|
'document': instance, 'tag': tag
|
||||||
context['object'] = documents.first()
|
}
|
||||||
context['title'] = _(
|
)
|
||||||
'Remove the tags: %(tags)s from the document: %(document)s?'
|
|
||||||
) % {
|
|
||||||
'tags': ', '.join([unicode(d) for d in tags]),
|
|
||||||
'document': ', '.join([unicode(d) for d in documents])
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
context['title'] = _(
|
|
||||||
'Remove the tags %(tags)s from the documents: %(documents)s?'
|
|
||||||
) % {
|
|
||||||
'tags': ', '.join([unicode(d) for d in tags]),
|
|
||||||
'documents': ', '.join([unicode(d) for d in documents])
|
|
||||||
}
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
for document in documents:
|
|
||||||
for tag in tags:
|
|
||||||
if tag not in document.attached_tags().all():
|
|
||||||
messages.warning(
|
|
||||||
request, _(
|
|
||||||
'Document "%(document)s" wasn\'t tagged as "%(tag)s"'
|
|
||||||
) % {
|
|
||||||
'document': document, 'tag': tag
|
|
||||||
}
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
tag.documents.remove(document)
|
|
||||||
messages.success(
|
|
||||||
request, _(
|
|
||||||
'Tag "%(tag)s" removed successfully from document "%(document)s".'
|
|
||||||
) % {
|
|
||||||
'document': document, 'tag': tag
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return HttpResponseRedirect(next)
|
|
||||||
else:
|
|
||||||
return render_to_response(
|
|
||||||
template, context, context_instance=RequestContext(request)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def single_document_multiple_tag_remove(request, document_id):
|
|
||||||
return tag_remove(
|
|
||||||
request, document_id=document_id,
|
|
||||||
tag_id_list=request.GET.get(
|
|
||||||
'id_list', request.POST.get('id_list', '')
|
|
||||||
).split(',')
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def multiple_documents_selection_tag_remove(request):
|
|
||||||
return tag_remove(
|
|
||||||
request, document_id_list=request.GET.get(
|
|
||||||
'id_list', request.POST.get('id_list', '')
|
|
||||||
).split(',')
|
|
||||||
)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user