from __future__ import absolute_import from django.conf import settings from django.contrib import messages from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, render_to_response from django.template import RequestContext from django.utils.http import urlencode from django.utils.translation import ugettext_lazy as _ from acls.models import AccessEntry from documents.models import Document, DocumentType from documents.permissions import PERMISSION_DOCUMENT_TYPE_EDIT from permissions.models import Permission from common.utils import encapsulate, generate_choices_w_labels from common.views import assign_remove from .api import save_metadata_list from .forms import (AddMetadataForm, MetadataFormSet, MetadataRemoveFormSet, MetadataTypeForm) from .models import DocumentMetadata, MetadataType from .permissions import (PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_EDIT, PERMISSION_METADATA_DOCUMENT_REMOVE, PERMISSION_METADATA_DOCUMENT_VIEW, PERMISSION_METADATA_TYPE_CREATE, PERMISSION_METADATA_TYPE_DELETE, PERMISSION_METADATA_TYPE_EDIT, PERMISSION_METADATA_TYPE_VIEW) def metadata_edit(request, document_id=None, document_id_list=None): if document_id: documents = [get_object_or_404(Document, pk=document_id)] if documents[0].metadata.count() == 0: messages.warning(request, _(u'The selected document doesn\'t have any metadata.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('main:home'))) elif document_id_list: documents = [get_object_or_404(Document.objects.select_related('document_type'), pk=document_id) for document_id in document_id_list.split(',')] if len(set([document.document_type.pk for document in documents])) > 1: messages.error(request, _(u'Only select documents of the same type.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('main:home'))) try: Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_EDIT]) except PermissionDenied: documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_METADATA_DOCUMENT_EDIT, request.user, documents) if not documents: messages.error(request, _(u'Must provide at least one document.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('main:home'))) post_action_redirect = reverse('documents:document_list_recent') next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', post_action_redirect))) metadata = {} initial = [] for document in documents: document.add_as_recent_document_for_user(request.user) for item in document.metadata.all(): value = item.value if item.metadata_type in metadata: if value not in metadata[item.metadata_type]: metadata[item.metadata_type].append(value) else: metadata[item.metadata_type] = [value] if value else [] for key, value in metadata.items(): initial.append({ 'metadata_type': key, 'value': u', '.join(value) if value else '', 'required': key in document.document_type.metadata.filter(required=True), }) formset = MetadataFormSet(initial=initial) if request.method == 'POST': formset = MetadataFormSet(data=request.POST, initial=initial) if formset.is_valid(): for document in documents: errors = [] for form in formset.forms: if form.cleaned_data['update']: try: save_metadata_list([form.cleaned_data], document) except Exception as exception: errors.append(exception) if errors: for error in errors: if settings.DEBUG: raise else: messages.error(request, _(u'Error editing metadata for document %(document)s; %(exception)s.') % { 'document': document, 'exception': ', '.join(exception.messages)}) else: messages.success(request, _(u'Metadata for document %s edited successfully.') % document) return HttpResponseRedirect(next) context = { 'form_display_mode_table': True, 'form': formset, 'next': next, } if len(documents) == 1: context['object'] = documents[0] context['title'] = _(u'Edit metadata for document: %s') % ', '.join([unicode(d) for d in documents]) elif len(documents) > 1: context['title'] = _(u'Edit metadata for documents: %s') % ', '.join([unicode(d) for d in documents]) return render_to_response('main/generic_form.html', context, context_instance=RequestContext(request)) def metadata_multiple_edit(request): return metadata_edit(request, document_id_list=request.GET.get('id_list', '')) def metadata_add(request, document_id=None, document_id_list=None): if document_id: documents = [get_object_or_404(Document, pk=document_id)] elif document_id_list: documents = [get_object_or_404(Document.objects.select_related('document_type'), pk=document_id) for document_id in document_id_list.split(',')] if len(set([document.document_type.pk for document in documents])) > 1: messages.error(request, _(u'Only select documents of the same type.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('main:home'))) try: Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_ADD]) except PermissionDenied: documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_METADATA_DOCUMENT_ADD, request.user, documents) if not documents: messages.error(request, _(u'Must provide at least one document.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('main:home'))) for document in documents: document.add_as_recent_document_for_user(request.user) post_action_redirect = reverse('documents:document_list_recent') next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', post_action_redirect))) if request.method == 'POST': form = AddMetadataForm(data=request.POST, document_type=document.document_type) if form.is_valid(): metadata_type = form.cleaned_data['metadata_type'] for document in documents: try: document_metadata, created = DocumentMetadata.objects.get_or_create(document=document, metadata_type=metadata_type, defaults={'value': u''}) except Exception as exception: messages.error(request, _(u'Error adding metadata type "%(metadata_type)s" to document: %(document)s; %(exception)s') % { 'metadata_type': metadata_type, 'document': document, 'exception': ', '.join(exception.messages)}) else: if created: messages.success(request, _(u'Metadata type: %(metadata_type)s successfully added to document %(document)s.') % { 'metadata_type': metadata_type, 'document': document}) else: messages.warning(request, _(u'Metadata type: %(metadata_type)s already present in document %(document)s.') % { 'metadata_type': metadata_type, 'document': document}) if len(documents) == 1: return HttpResponseRedirect(u'%s?%s' % ( reverse('metadata:metadata_edit', args=[document.pk]), urlencode({'next': next})) ) elif len(documents) > 1: return HttpResponseRedirect(u'%s?%s' % ( reverse('metadata:metadata_multiple_edit'), urlencode({'id_list': document_id_list, 'next': next})) ) else: form = AddMetadataForm(document_type=document.document_type) context = { 'form': form, 'next': next, } if len(documents) == 1: context['object'] = documents[0] context['title'] = _(u'Add metadata type to document: %s') % ', '.join([unicode(d) for d in documents]) elif len(documents) > 1: context['title'] = _(u'Add metadata type to documents: %s') % ', '.join([unicode(d) for d in documents]) return render_to_response('main/generic_form.html', context, context_instance=RequestContext(request)) def metadata_multiple_add(request): return metadata_add(request, document_id_list=request.GET.get('id_list', [])) def metadata_remove(request, document_id=None, document_id_list=None): if document_id: documents = [get_object_or_404(Document, pk=document_id)] if documents[0].metadata.count() == 0: messages.warning(request, _(u'The selected document doesn\'t have any metadata.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('main:home'))) elif document_id_list: documents = [get_object_or_404(Document.objects.select_related('document_type'), pk=document_id) for document_id in document_id_list.split(',')] if len(set([document.document_type.pk for document in documents])) > 1: messages.error(request, _(u'Only select documents of the same type.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('main:home'))) try: Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_REMOVE]) except PermissionDenied: documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_METADATA_DOCUMENT_REMOVE, request.user, documents) if not documents: messages.error(request, _(u'Must provide at least one document.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('main:home'))) post_action_redirect = reverse('documents:document_list_recent') next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', post_action_redirect))) metadata = {} for document in documents: document.add_as_recent_document_for_user(request.user) for item in document.metadata.all(): value = item.value if item.metadata_type in metadata: if value not in metadata[item.metadata_type]: metadata[item.metadata_type].append(value) else: metadata[item.metadata_type] = [value] if value else u'' initial = [] for key, value in metadata.items(): initial.append({ 'metadata_type': key, 'value': u', '.join(value) }) formset = MetadataRemoveFormSet(initial=initial) if request.method == 'POST': formset = MetadataRemoveFormSet(request.POST) if formset.is_valid(): for document in documents: for form in formset.forms: if form.cleaned_data['update']: metadata_type = get_object_or_404(MetadataType, pk=form.cleaned_data['id']) try: document_metadata = DocumentMetadata.objects.get(document=document, metadata_type=metadata_type) document_metadata.delete() messages.success(request, _(u'Successfully remove metadata type "%(metadata_type)s" from document: %(document)s.') % { 'metadata_type': metadata_type, 'document': document}) except Exception as exception: messages.error(request, _(u'Error removing metadata type "%(metadata_type)s" from document: %(document)s; %(exception)s') % { 'metadata_type': metadata_type, 'document': document, 'exception': ', '.join(exception.messages)}) return HttpResponseRedirect(next) context = { 'form_display_mode_table': True, 'form': formset, 'next': next, } if len(documents) == 1: context['object'] = documents[0] context['title'] = _(u'Remove metadata types from document: %s') % ', '.join([unicode(d) for d in documents]) elif len(documents) > 1: context['title'] = _(u'Remove metadata types from documents: %s') % ', '.join([unicode(d) for d in documents]) return render_to_response('main/generic_form.html', context, context_instance=RequestContext(request)) def metadata_multiple_remove(request): return metadata_remove(request, document_id_list=request.GET.get('id_list', [])) def metadata_view(request, document_id): document = get_object_or_404(Document, pk=document_id) try: Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_VIEW]) except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_METADATA_DOCUMENT_VIEW, request.user, document) return render_to_response('main/generic_list.html', { 'title': _(u'Metadata for: %s') % document, 'object_list': document.metadata.all(), 'extra_columns': [ {'name': _(u'Value'), 'attribute': 'value'}, {'name': _(u'Required'), 'attribute': encapsulate(lambda x: x.metadata_type in document.document_type.metadata.filter(required=True))} ], 'hide_link': True, 'object': document, }, context_instance=RequestContext(request)) # Setup views def setup_metadata_type_list(request): Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_VIEW]) context = { 'object_list': MetadataType.objects.all(), 'title': _(u'Metadata types'), 'hide_link': True, 'extra_columns': [ { 'name': _(u'Internal name'), 'attribute': 'name', }, ] } return render_to_response('main/generic_list.html', context, context_instance=RequestContext(request)) def setup_metadata_type_edit(request, metadatatype_id): Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_EDIT]) metadata_type = get_object_or_404(MetadataType, pk=metadatatype_id) if request.method == 'POST': form = MetadataTypeForm(instance=metadata_type, data=request.POST) if form.is_valid(): try: form.save() messages.success(request, _(u'Metadata type edited successfully')) return HttpResponseRedirect(reverse('metadata:setup_metadata_type_list')) except Exception as exception: messages.error(request, _(u'Error editing metadata type; %s') % exception) pass else: form = MetadataTypeForm(instance=metadata_type) return render_to_response('main/generic_form.html', { 'title': _(u'Edit metadata type: %s') % metadata_type, 'form': form, 'object': metadata_type, }, context_instance=RequestContext(request)) def setup_metadata_type_create(request): Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_CREATE]) if request.method == 'POST': form = MetadataTypeForm(request.POST) if form.is_valid(): form.save() messages.success(request, _(u'Metadata type created successfully')) return HttpResponseRedirect(reverse('metadata:setup_metadata_type_list')) else: form = MetadataTypeForm() return render_to_response('main/generic_form.html', { 'title': _(u'Create metadata type'), 'form': form, }, context_instance=RequestContext(request)) def setup_metadata_type_delete(request, metadatatype_id): Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_DELETE]) metadata_type = get_object_or_404(MetadataType, pk=metadatatype_id) post_action_redirect = reverse('metadata:setup_metadata_type_list') previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', post_action_redirect))) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', post_action_redirect))) if request.method == 'POST': try: metadata_type.delete() messages.success(request, _(u'Metadata type: %s deleted successfully.') % metadata_type) except Exception as exception: messages.error(request, _(u'Metadata type: %(metadata_type)s delete error: %(error)s') % { 'metadata_type': metadata_type, 'error': exception}) return HttpResponseRedirect(next) context = { 'delete_view': True, 'next': next, 'previous': previous, 'object': metadata_type, 'title': _(u'Are you sure you wish to delete the metadata type: %s?') % metadata_type, } return render_to_response('main/generic_confirm.html', context, context_instance=RequestContext(request)) def setup_document_type_metadata(request, document_type_id): Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_EDIT]) document_type = get_object_or_404(DocumentType, pk=document_type_id) return assign_remove( request, left_list=lambda: generate_choices_w_labels(set(MetadataType.objects.all()) - set(MetadataType.objects.filter(id__in=document_type.metadata.values_list('metadata_type', flat=True))), display_object_type=False), right_list=lambda: generate_choices_w_labels(document_type.metadata.filter(required=False), display_object_type=False), add_method=lambda x: document_type.metadata.create(metadata_type=x, required=False), remove_method=lambda x: x.delete(), extra_context={ 'document_type': document_type, 'navigation_object_name': 'document_type', 'main_title': _(u'Optional metadata types for document type: %s') % document_type, }, decode_content_type=True, ) def setup_document_type_metadata_required(request, document_type_id): Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_EDIT]) document_type = get_object_or_404(DocumentType, pk=document_type_id) return assign_remove( request, left_list=lambda: generate_choices_w_labels(set(MetadataType.objects.all()) - set(MetadataType.objects.filter(id__in=document_type.metadata.values_list('metadata_type', flat=True))), display_object_type=False), right_list=lambda: generate_choices_w_labels(document_type.metadata.filter(required=True), display_object_type=False), add_method=lambda x: document_type.metadata.create(metadata_type=x, required=True), remove_method=lambda x: x.delete(), extra_context={ 'document_type': document_type, 'navigation_object_name': 'document_type', 'main_title': _('Required metadata types for document type: %s') % document_type, }, decode_content_type=True, )