diff --git a/src/documents/actions.py b/src/documents/actions.py index 3db5cd314..cd2698a2c 100644 --- a/src/documents/actions.py +++ b/src/documents/actions.py @@ -4,10 +4,13 @@ from django.contrib.admin.utils import model_ngettext from django.core.exceptions import PermissionDenied from django.template.response import TemplateResponse -from documents.models import Tag, Correspondent +from documents.models import Correspondent, Tag -def select_action(modeladmin, request, queryset, title, action, modelclass, success_message="", document_action=None, queryset_action=None): +def select_action( + modeladmin, request, queryset, title, action, modelclass, + success_message="", document_action=None, queryset_action=None): + opts = modeladmin.model._meta app_label = opts.app_label @@ -27,7 +30,9 @@ def select_action(modeladmin, request, queryset, title, action, modelclass, succ queryset_action(queryset, selected_object) modeladmin.message_user(request, success_message % { - "selected_object": selected_object.name, "count": n, "items": model_ngettext(modeladmin.opts, n) + "selected_object": selected_object.name, + "count": n, + "items": model_ngettext(modeladmin.opts, n) }, messages.SUCCESS) # Return None to display the change list page again. @@ -47,10 +52,17 @@ def select_action(modeladmin, request, queryset, title, action, modelclass, succ request.current_app = modeladmin.admin_site.name - return TemplateResponse(request, "admin/%s/%s/select_object.html" % (app_label, opts.model_name), context) + return TemplateResponse( + request, + "admin/{}/{}/select_object.html".format(app_label, opts.model_name), + context + ) -def simple_action(modeladmin, request, queryset, success_message="", document_action=None, queryset_action=None): +def simple_action( + modeladmin, request, queryset, success_message="", + document_action=None, queryset_action=None): + if not modeladmin.has_change_permission(request): raise PermissionDenied @@ -72,37 +84,63 @@ def simple_action(modeladmin, request, queryset, success_message="", document_ac def add_tag_to_selected(modeladmin, request, queryset): - return select_action(modeladmin=modeladmin, request=request, queryset=queryset, - title="Add tag to multiple documents", - action="add_tag_to_selected", - modelclass=Tag, - success_message="Successfully added tag %(selected_object)s to %(count)d %(items)s.", - document_action=lambda doc, tag: doc.tags.add(tag)) -add_tag_to_selected.short_description = "Add tag to selected documents" + return select_action( + modeladmin=modeladmin, + request=request, + queryset=queryset, + title="Add tag to multiple documents", + action="add_tag_to_selected", + modelclass=Tag, + success_message="Successfully added tag %(selected_object)s to " + "%(count)d %(items)s.", + document_action=lambda doc, tag: doc.tags.add(tag) + ) def remove_tag_from_selected(modeladmin, request, queryset): - return select_action(modeladmin=modeladmin, request=request, queryset=queryset, - title="Remove tag from multiple documents", - action="remove_tag_from_selected", - modelclass=Tag, - success_message="Successfully removed tag %(selected_object)s from %(count)d %(items)s.", - document_action=lambda doc, tag: doc.tags.remove(tag)) -remove_tag_from_selected.short_description = "Remove tag from selected documents" + return select_action( + modeladmin=modeladmin, + request=request, + queryset=queryset, + title="Remove tag from multiple documents", + action="remove_tag_from_selected", + modelclass=Tag, + success_message="Successfully removed tag %(selected_object)s from " + "%(count)d %(items)s.", + document_action=lambda doc, tag: doc.tags.remove(tag) + ) def set_correspondent_on_selected(modeladmin, request, queryset): - return select_action(modeladmin=modeladmin, request=request, queryset=queryset, - title="Set correspondent on multiple documents", - action="set_correspondent_on_selected", - modelclass=Correspondent, - success_message="Successfully set correspondent %(selected_object)s on %(count)d %(items)s.", - queryset_action=lambda qs, correspondent: qs.update(correspondent=correspondent)) -set_correspondent_on_selected.short_description = "Set correspondent on selected documents" + + return select_action( + modeladmin=modeladmin, + request=request, + queryset=queryset, + title="Set correspondent on multiple documents", + action="set_correspondent_on_selected", + modelclass=Correspondent, + success_message="Successfully set correspondent %(selected_object)s " + "on %(count)d %(items)s.", + queryset_action=lambda qs, corr: qs.update(correspondent=corr) + ) def remove_correspondent_from_selected(modeladmin, request, queryset): - return simple_action(modeladmin=modeladmin, request=request, queryset=queryset, - success_message="Successfully removed correspondent from %(count)d %(items)s.", - queryset_action=lambda qs: qs.update(correspondent=None)) -remove_correspondent_from_selected.short_description = "Remove correspondent from selected documents" + return simple_action( + modeladmin=modeladmin, + request=request, + queryset=queryset, + success_message="Successfully removed correspondent from %(count)d " + "%(items)s.", + queryset_action=lambda qs: qs.update(correspondent=None) + ) + + +add_tag_to_selected.short_description = "Add tag to selected documents" +remove_tag_from_selected.short_description = \ + "Remove tag from selected documents" +set_correspondent_on_selected.short_description = \ + "Set correspondent on selected documents" +remove_correspondent_from_selected.short_description = \ + "Remove correspondent from selected documents" diff --git a/src/documents/admin.py b/src/documents/admin.py index d545c1c02..365a99c1a 100644 --- a/src/documents/admin.py +++ b/src/documents/admin.py @@ -3,21 +3,23 @@ from datetime import datetime, timedelta from django.conf import settings from django.contrib import admin, messages from django.contrib.admin.templatetags.admin_urls import add_preserved_filters -from django.contrib.auth.models import User, Group +from django.contrib.auth.models import Group, User +from django.db import models from django.http import HttpResponseRedirect -try: - from django.core.urlresolvers import reverse -except ImportError: - from django.urls import reverse from django.templatetags.static import static +from django.urls import reverse from django.utils.html import format_html, format_html_join from django.utils.http import urlquote from django.utils.safestring import mark_safe -from django.db import models -from documents.actions import add_tag_to_selected, remove_tag_from_selected, set_correspondent_on_selected, \ - remove_correspondent_from_selected -from .models import Correspondent, Tag, Document, Log +from documents.actions import ( + add_tag_to_selected, + remove_correspondent_from_selected, + remove_tag_from_selected, + set_correspondent_on_selected +) + +from .models import Correspondent, Document, Log, Tag class FinancialYearFilter(admin.SimpleListFilter): @@ -92,11 +94,18 @@ class RecentCorrespondentFilter(admin.RelatedFieldListFilter): self.title = "correspondent (recent)" def field_choices(self, field, request, model_admin): + + years = settings.PAPERLESS_RECENT_CORRESPONDENT_YEARS + days = 365 * years + lookups = [] - if settings.PAPERLESS_RECENT_CORRESPONDENT_YEARS and settings.PAPERLESS_RECENT_CORRESPONDENT_YEARS > 0: - date_limit = datetime.now() - timedelta(days=365*settings.PAPERLESS_RECENT_CORRESPONDENT_YEARS) - for c in Correspondent.objects.filter(documents__created__gte=date_limit).distinct(): + if years and years > 0: + correspondents = Correspondent.objects.filter( + documents__created__gte=datetime.now() - timedelta(days=days) + ).distinct() + for c in correspondents: lookups.append((c.id, c.name)) + return lookups @@ -106,13 +115,22 @@ class CommonAdmin(admin.ModelAdmin): class CorrespondentAdmin(CommonAdmin): - list_display = ("name", "match", "matching_algorithm", "document_count", "last_correspondence") + list_display = ( + "name", + "match", + "matching_algorithm", + "document_count", + "last_correspondence" + ) list_filter = ("matching_algorithm",) list_editable = ("match", "matching_algorithm") def get_queryset(self, request): qs = super(CorrespondentAdmin, self).get_queryset(request) - qs = qs.annotate(document_count=models.Count("documents"), last_correspondence=models.Max("documents__created")) + qs = qs.annotate( + document_count=models.Count("documents"), + last_correspondence=models.Max("documents__created") + ) return qs def document_count(self, obj): @@ -152,17 +170,29 @@ class DocumentAdmin(CommonAdmin): readonly_fields = ("added",) list_display = ("title", "created", "added", "thumbnail", "correspondent", "tags_") - list_filter = ("tags", ('correspondent', RecentCorrespondentFilter), "correspondent", FinancialYearFilter) + list_filter = ( + "tags", + ("correspondent", RecentCorrespondentFilter), + "correspondent", + FinancialYearFilter + ) filter_horizontal = ("tags",) ordering = ["-created", "correspondent"] - actions = [add_tag_to_selected, remove_tag_from_selected, set_correspondent_on_selected, remove_correspondent_from_selected] + actions = [ + add_tag_to_selected, + remove_tag_from_selected, + set_correspondent_on_selected, + remove_correspondent_from_selected + ] - date_hierarchy = 'created' + date_hierarchy = "created" - document_queue = None + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.document_queue = [] def has_add_permission(self, request): return False @@ -172,25 +202,38 @@ class DocumentAdmin(CommonAdmin): created_.short_description = "Created" def changelist_view(self, request, extra_context=None): - response = super().changelist_view(request, extra_context) - if request.method == 'GET': + response = super().changelist_view( + request, + extra_context=extra_context + ) + + if request.method == "GET": cl = self.get_changelist_instance(request) self.document_queue = [doc.id for doc in cl.queryset] return response - def change_view(self, request, object_id=None, form_url='', extra_context=None): + def change_view(self, request, object_id=None, form_url='', + extra_context=None): + extra_context = extra_context or {} - doc = Document.objects.get(id=object_id) - if self.document_queue and object_id and int(object_id) in self.document_queue: - # There is a queue of documents - current_index = self.document_queue.index(int(object_id)) - if current_index < len(self.document_queue) - 1: - # ... and there are still documents in the queue - extra_context['next_object'] = self.document_queue[current_index + 1] + + if self.document_queue and object_id: + if int(object_id) in self.document_queue: + # There is a queue of documents + current_index = self.document_queue.index(int(object_id)) + if current_index < len(self.document_queue) - 1: + # ... and there are still documents in the queue + extra_context["next_object"] = self.document_queue[ + current_index + 1 + ] + return super(DocumentAdmin, self).change_view( - request, object_id, form_url, extra_context=extra_context, + request, + object_id, + form_url, + extra_context=extra_context, ) def response_change(self, request, obj): @@ -200,25 +243,35 @@ class DocumentAdmin(CommonAdmin): preserved_filters = self.get_preserved_filters(request) msg_dict = { - 'name': opts.verbose_name, - 'obj': format_html('{}', urlquote(request.path), obj), + "name": opts.verbose_name, + "obj": format_html( + '{}', + urlquote(request.path), + obj + ), } if "_saveandeditnext" in request.POST: msg = format_html( - 'The {name} "{obj}" was changed successfully. Editing next object.', + 'The {name} "{obj}" was changed successfully. ' + 'Editing next object.', **msg_dict ) self.message_user(request, msg, messages.SUCCESS) - redirect_url = reverse('admin:%s_%s_change' % - (opts.app_label, opts.model_name), - args=(request.POST['_next_object'],), - current_app=self.admin_site.name) - redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) - response = HttpResponseRedirect(redirect_url) - else: - response = super().response_change(request, obj) + redirect_url = reverse( + "admin:{}_{}_change".format(opts.app_label, opts.model_name), + args=(request.POST["_next_object"],), + current_app=self.admin_site.name + ) + redirect_url = add_preserved_filters( + { + "preserved_filters": preserved_filters, + "opts": opts + }, + redirect_url + ) + return HttpResponseRedirect(redirect_url) - return response + return super().response_change(request, obj) @mark_safe def thumbnail(self, obj): diff --git a/src/documents/templates/admin/documents/document/select_object.html b/src/documents/templates/admin/documents/document/select_object.html index 1439b5c21..775d57b12 100644 --- a/src/documents/templates/admin/documents/document/select_object.html +++ b/src/documents/templates/admin/documents/document/select_object.html @@ -1,46 +1,50 @@ {% extends "admin/base_site.html" %} + + {% load i18n l10n admin_urls static %} {% load staticfiles %} -{% block extrahead %} -{{ block.super }} -{{ media }} - +{% block extrahead %} + {{ block.super }} + {{ media }} + {% endblock %} + {% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation delete-selected-confirmation{% endblock %} + {% block breadcrumbs %} - + {% endblock %} {% block content %} -

Please select the {{itemname}}.

-
{% csrf_token %} -
- {% for obj in queryset %} - - {% endfor %} -

- -

+

Please select the {{itemname}}.

+ {% csrf_token %} +
+ {% for obj in queryset %} + + {% endfor %} +

+ +

- - -

- - {% trans "Go back" %} -

-
- + + +

+ + {% trans "Go back" %} +

+
+ {% endblock %} diff --git a/src/paperless/settings.py b/src/paperless/settings.py index e6f3da0cb..433eabe88 100644 --- a/src/paperless/settings.py +++ b/src/paperless/settings.py @@ -81,7 +81,7 @@ INSTALLED_APPS = [ "rest_framework", "crispy_forms", - "django_filters" + "django_filters", ]