mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Added actions to modify tags and correspondents on multiple documents
This commit is contained in:
		| @@ -1,8 +1,12 @@ | |||||||
| from datetime import datetime | from datetime import datetime | ||||||
|  |  | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.contrib import admin | from django.contrib import admin, messages | ||||||
|  | from django.contrib.admin import helpers | ||||||
|  | from django.contrib.admin.utils import model_ngettext | ||||||
| from django.contrib.auth.models import User, Group | from django.contrib.auth.models import User, Group | ||||||
|  | from django.core.exceptions import PermissionDenied | ||||||
|  | from django.template.response import TemplateResponse | ||||||
| from django.urls import reverse | from django.urls import reverse | ||||||
| from django.templatetags.static import static | from django.templatetags.static import static | ||||||
| from django.utils.safestring import mark_safe | from django.utils.safestring import mark_safe | ||||||
| @@ -132,11 +136,166 @@ class TagAdmin(CommonAdmin): | |||||||
|                 document.tags.add(obj) |                 document.tags.add(obj) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def add_tag_to_selected(modeladmin, request, queryset): | ||||||
|  |     opts = modeladmin.model._meta | ||||||
|  |     app_label = opts.app_label | ||||||
|  |  | ||||||
|  |     if not modeladmin.has_change_permission(request): | ||||||
|  |         raise PermissionDenied | ||||||
|  |  | ||||||
|  |     if request.POST.get('post'): | ||||||
|  |         n = queryset.count() | ||||||
|  |         tag = Tag.objects.get(id=request.POST.get('tag_id')) | ||||||
|  |         if n: | ||||||
|  |             for obj in queryset: | ||||||
|  |                 obj.tags.add(tag) | ||||||
|  |                 obj_display = str(obj) | ||||||
|  |                 modeladmin.log_change(request, obj, obj_display) | ||||||
|  |             modeladmin.message_user(request, "Successfully added tag %(tag)s to %(count)d %(items)s." % { | ||||||
|  |                 "tag": tag.name, "count": n, "items": model_ngettext(modeladmin.opts, n) | ||||||
|  |             }, messages.SUCCESS) | ||||||
|  |  | ||||||
|  |         # Return None to display the change list page again. | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     title = "Add tag to multiple documents" | ||||||
|  |  | ||||||
|  |     context = dict( | ||||||
|  |         modeladmin.admin_site.each_context(request), | ||||||
|  |         title=title, | ||||||
|  |         queryset=queryset, | ||||||
|  |         opts=opts, | ||||||
|  |         action_checkbox_name=helpers.ACTION_CHECKBOX_NAME, | ||||||
|  |         media=modeladmin.media, | ||||||
|  |         action="add_tag_to_selected", | ||||||
|  |         tags=Tag.objects.all() | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     request.current_app = modeladmin.admin_site.name | ||||||
|  |  | ||||||
|  |     return TemplateResponse(request, | ||||||
|  |         "admin/%s/%s/mass_modify_tag.html" % (app_label, opts.model_name) | ||||||
|  |     , context) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | add_tag_to_selected.short_description = "Add tag to selected documents" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def remove_tag_from_selected(modeladmin, request, queryset): | ||||||
|  |     opts = modeladmin.model._meta | ||||||
|  |     app_label = opts.app_label | ||||||
|  |  | ||||||
|  |     if not modeladmin.has_change_permission(request): | ||||||
|  |         raise PermissionDenied | ||||||
|  |  | ||||||
|  |     if request.POST.get('post'): | ||||||
|  |         n = queryset.count() | ||||||
|  |         tag = Tag.objects.get(id=request.POST.get('tag_id')) | ||||||
|  |         if n: | ||||||
|  |             for obj in queryset: | ||||||
|  |                 obj.tags.remove(tag) | ||||||
|  |                 obj_display = str(obj) | ||||||
|  |                 modeladmin.log_change(request, obj, obj_display) | ||||||
|  |             modeladmin.message_user(request, "Successfully removed tag %(tag)s from %(count)d %(items)s." % { | ||||||
|  |                 "tag": tag.name, "count": n, "items": model_ngettext(modeladmin.opts, n) | ||||||
|  |             }, messages.SUCCESS) | ||||||
|  |  | ||||||
|  |         # Return None to display the change list page again. | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     title = "Remove tag from multiple documents" | ||||||
|  |  | ||||||
|  |     context = dict( | ||||||
|  |         modeladmin.admin_site.each_context(request), | ||||||
|  |         title=title, | ||||||
|  |         queryset=queryset, | ||||||
|  |         opts=opts, | ||||||
|  |         action_checkbox_name=helpers.ACTION_CHECKBOX_NAME, | ||||||
|  |         media=modeladmin.media, | ||||||
|  |         action="remove_tag_from_selected", | ||||||
|  |         tags=Tag.objects.all() | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     request.current_app = modeladmin.admin_site.name | ||||||
|  |  | ||||||
|  |     return TemplateResponse(request, | ||||||
|  |         "admin/%s/%s/mass_modify_tag.html" % (app_label, opts.model_name) | ||||||
|  |     , context) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | remove_tag_from_selected.short_description = "Remove tag from selected documents" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def set_correspondent_on_selected(modeladmin, request, queryset): | ||||||
|  |     opts = modeladmin.model._meta | ||||||
|  |     app_label = opts.app_label | ||||||
|  |  | ||||||
|  |     if not modeladmin.has_change_permission(request): | ||||||
|  |         raise PermissionDenied | ||||||
|  |  | ||||||
|  |     if request.POST.get('post'): | ||||||
|  |         n = queryset.count() | ||||||
|  |         correspondent = Correspondent.objects.get(id=request.POST.get('correspondent_id')) | ||||||
|  |         if n: | ||||||
|  |             for obj in queryset: | ||||||
|  |                 obj_display = str(obj) | ||||||
|  |                 modeladmin.log_change(request, obj, obj_display) | ||||||
|  |             queryset.update(correspondent=correspondent) | ||||||
|  |             modeladmin.message_user(request, "Successfully set correspondent %(correspondent)s on %(count)d %(items)s." % { | ||||||
|  |                 "correspondent": correspondent.name, "count": n, "items": model_ngettext(modeladmin.opts, n) | ||||||
|  |             }, messages.SUCCESS) | ||||||
|  |  | ||||||
|  |         # Return None to display the change list page again. | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     title = "Set correspondent on multiple documents" | ||||||
|  |  | ||||||
|  |     context = dict( | ||||||
|  |         modeladmin.admin_site.each_context(request), | ||||||
|  |         title=title, | ||||||
|  |         queryset=queryset, | ||||||
|  |         opts=opts, | ||||||
|  |         action_checkbox_name=helpers.ACTION_CHECKBOX_NAME, | ||||||
|  |         media=modeladmin.media, | ||||||
|  |         correspondents=Correspondent.objects.all() | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     request.current_app = modeladmin.admin_site.name | ||||||
|  |  | ||||||
|  |     return TemplateResponse(request, | ||||||
|  |         "admin/%s/%s/set_correspondent.html" % (app_label, opts.model_name) | ||||||
|  |     , context) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | set_correspondent_on_selected.short_description = "Set correspondent on selected documents" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def remove_correspondent_from_selected(modeladmin, request, queryset): | ||||||
|  |     if not modeladmin.has_change_permission(request): | ||||||
|  |         raise PermissionDenied | ||||||
|  |  | ||||||
|  |     n = queryset.count() | ||||||
|  |     if n: | ||||||
|  |         for obj in queryset: | ||||||
|  |             obj_display = str(obj) | ||||||
|  |             modeladmin.log_change(request, obj, obj_display) | ||||||
|  |         queryset.update(correspondent=None) | ||||||
|  |         modeladmin.message_user(request, "Successfully removed correspondent from %(count)d %(items)s." % { | ||||||
|  |             "count": n, "items": model_ngettext(modeladmin.opts, n) | ||||||
|  |         }, messages.SUCCESS) | ||||||
|  |  | ||||||
|  |     return None | ||||||
|  |  | ||||||
|  |  | ||||||
|  | remove_correspondent_from_selected.short_description = "Remove correspondent from selected documents" | ||||||
|  |  | ||||||
|  |  | ||||||
| class DocumentAdmin(CommonAdmin): | class DocumentAdmin(CommonAdmin): | ||||||
|  |  | ||||||
|     class Media: |     class Media: | ||||||
|         css = { |         css = { | ||||||
|             "all": ("paperless.css",) |             "all": ("paperless.css",) | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     search_fields = ("correspondent__name", "title", "content", "tags__name") |     search_fields = ("correspondent__name", "title", "content", "tags__name") | ||||||
| @@ -148,6 +307,9 @@ class DocumentAdmin(CommonAdmin): | |||||||
|  |  | ||||||
|     ordering = ["-created", "correspondent"] |     ordering = ["-created", "correspondent"] | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     actions = [add_tag_to_selected, remove_tag_from_selected, set_correspondent_on_selected, remove_correspondent_from_selected] | ||||||
|  |  | ||||||
|     def has_add_permission(self, request): |     def has_add_permission(self, request): | ||||||
|         return False |         return False | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								src/documents/templates/admin/documents/document/mass_modify_tag.html
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										46
									
								
								src/documents/templates/admin/documents/document/mass_modify_tag.html
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | {% extends "admin/base_site.html" %} | ||||||
|  | {% load i18n l10n admin_urls static %} | ||||||
|  | {% load staticfiles %} | ||||||
|  |  | ||||||
|  | {% block extrahead %} | ||||||
|  | {{ block.super }} | ||||||
|  | {{ media }} | ||||||
|  | <script type="text/javascript" src="{% static 'admin/js/cancel.js' %}"></script> | ||||||
|  |  | ||||||
|  | {% endblock %} | ||||||
|  |  | ||||||
|  | {% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation delete-selected-confirmation{% endblock %} | ||||||
|  |  | ||||||
|  | {% block breadcrumbs %} | ||||||
|  | <div class="breadcrumbs"> | ||||||
|  |     <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> | ||||||
|  |     › <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a> | ||||||
|  |     › <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a> | ||||||
|  |     › {{title}} | ||||||
|  | </div> | ||||||
|  | {% endblock %} | ||||||
|  |  | ||||||
|  | {% block content %} | ||||||
|  | <p>Please select the tag.</p> | ||||||
|  | <form method="post">{% csrf_token %} | ||||||
|  |     <div> | ||||||
|  |         {% for obj in queryset %} | ||||||
|  |         <input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}"/> | ||||||
|  |         {% endfor %} | ||||||
|  |         <p> | ||||||
|  |             <select name="tag_id"> | ||||||
|  |                 {% for tag in tags %} | ||||||
|  |                 <option value="{{tag.id}}">{{tag.name}}</option> | ||||||
|  |                 {% endfor %} | ||||||
|  |             </select> | ||||||
|  |         </p> | ||||||
|  |  | ||||||
|  |         <input type="hidden" name="action" value="{{action}}"/> | ||||||
|  |         <input type="hidden" name="post" value="yes"/> | ||||||
|  |         <p> | ||||||
|  |             <input type="submit" value="{% trans " Confirm" %}" /> | ||||||
|  |             <a href="#" class="button cancel-link">{% trans "Go back" %}</a> | ||||||
|  |         </p> | ||||||
|  |     </div> | ||||||
|  | </form> | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										46
									
								
								src/documents/templates/admin/documents/document/set_correspondent.html
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										46
									
								
								src/documents/templates/admin/documents/document/set_correspondent.html
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | {% extends "admin/base_site.html" %} | ||||||
|  | {% load i18n l10n admin_urls static %} | ||||||
|  | {% load staticfiles %} | ||||||
|  |  | ||||||
|  | {% block extrahead %} | ||||||
|  | {{ block.super }} | ||||||
|  | {{ media }} | ||||||
|  | <script type="text/javascript" src="{% static 'admin/js/cancel.js' %}"></script> | ||||||
|  |  | ||||||
|  | {% endblock %} | ||||||
|  |  | ||||||
|  | {% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation delete-selected-confirmation{% endblock %} | ||||||
|  |  | ||||||
|  | {% block breadcrumbs %} | ||||||
|  | <div class="breadcrumbs"> | ||||||
|  |     <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> | ||||||
|  |     › <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a> | ||||||
|  |     › <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a> | ||||||
|  |     › {{title}} | ||||||
|  | </div> | ||||||
|  | {% endblock %} | ||||||
|  |  | ||||||
|  | {% block content %} | ||||||
|  | <p>Please select the correspondent.</p> | ||||||
|  | <form method="post">{% csrf_token %} | ||||||
|  |     <div> | ||||||
|  |         {% for obj in queryset %} | ||||||
|  |         <input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}"/> | ||||||
|  |         {% endfor %} | ||||||
|  |         <p> | ||||||
|  |             <select name="correspondent_id"> | ||||||
|  |                 {% for correspondent in correspondents %} | ||||||
|  |                 <option value="{{correspondent.id}}">{{correspondent.name}}</option> | ||||||
|  |                 {% endfor %} | ||||||
|  |             </select> | ||||||
|  |         </p> | ||||||
|  |  | ||||||
|  |         <input type="hidden" name="action" value="set_correspondent_on_selected"/> | ||||||
|  |         <input type="hidden" name="post" value="yes"/> | ||||||
|  |         <p> | ||||||
|  |             <input type="submit" value="{% trans " Confirm" %}" /> | ||||||
|  |             <a href="#" class="button cancel-link">{% trans "Go back" %}</a> | ||||||
|  |         </p> | ||||||
|  |     </div> | ||||||
|  | </form> | ||||||
|  | {% endblock %} | ||||||
		Reference in New Issue
	
	Block a user
	 Jonas Winkler
					Jonas Winkler