Initial commit

This commit is contained in:
2024-08-27 20:33:44 +02:00
commit 1f1832267d
14794 changed files with 1599592 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
from .base_bulk_action import BulkAction
from .dispatcher import index
__all__ = ["BulkAction", "index"]

View File

@@ -0,0 +1,163 @@
from abc import ABC, abstractmethod
from django import forms
from django.db import transaction
from django.shortcuts import get_list_or_404, redirect
from django.utils.functional import classproperty
from django.views.generic import FormView
from wagtail import hooks
from wagtail.admin import messages
from wagtail.admin.utils import get_valid_next_url_from_request
class BulkAction(ABC, FormView):
@property
@abstractmethod
def display_name(self):
pass
@property
@abstractmethod
def action_type(self):
pass
@property
@abstractmethod
def aria_label(self):
pass
extras = {}
action_priority = 100
classes = set()
form_class = forms.Form
cleaned_form = None
def __init__(self, request, model):
self.request = request
next_url = get_valid_next_url_from_request(request)
if not next_url:
next_url = request.path
self.next_url = next_url
self.num_parent_objects = self.num_child_objects = 0
if model in self.models:
self.model = model
else:
raise Exception(
"model {} is not among the specified list of models".format(
model.__class__.__name__
)
)
@classproperty
def models(cls):
return []
@classmethod
def get_queryset(cls, model, object_ids):
return get_list_or_404(model, pk__in=object_ids)
def check_perm(self, obj):
return True
@classmethod
def execute_action(cls, objects, **kwargs):
raise NotImplementedError("execute_action needs to be implemented")
def get_success_message(self, num_parent_objects, num_child_objects):
pass
def object_context(self, obj):
return {"item": obj}
@classmethod
def get_default_model(cls):
models = cls.models
if len(models) == 1:
return models[0]
raise Exception(
"Cannot get default model if number of models is greater than 1"
)
def __run_before_hooks(self, action_type, request, objects):
for hook in hooks.get_hooks("before_bulk_action"):
result = hook(request, action_type, objects, self)
if hasattr(result, "status_code"):
return result
def __run_after_hooks(self, action_type, request, objects):
for hook in hooks.get_hooks("after_bulk_action"):
result = hook(request, action_type, objects, self)
if hasattr(result, "status_code"):
return result
def get_all_objects_in_listing_query(self, parent_id):
return self.model.objects.all().values_list("pk", flat=True)
def get_actionable_objects(self):
objects = []
items_with_no_access = []
object_ids = self.request.GET.getlist("id")
if "all" in object_ids:
object_ids = self.get_all_objects_in_listing_query(
self.request.GET.get("childOf")
)
for obj in self.get_queryset(self.model, object_ids):
if not self.check_perm(obj):
items_with_no_access.append(obj)
else:
objects.append(obj)
return objects, {"items_with_no_access": items_with_no_access}
def get_context_data(self, **kwargs):
items, items_with_no_access = self.get_actionable_objects()
_items = []
for item in items:
_items.append(self.object_context(item))
return {
**super().get_context_data(**kwargs),
"items": _items,
**items_with_no_access,
"next": self.next_url,
"submit_url": self.request.path + "?" + self.request.META["QUERY_STRING"],
}
def prepare_action(self, objects, objects_without_access):
return
def get_execution_context(self):
return {}
def form_valid(self, form):
request = self.request
self.cleaned_form = form
objects, objects_without_access = self.get_actionable_objects()
self.actionable_objects = objects
resp = self.prepare_action(objects, objects_without_access)
if hasattr(resp, "status_code"):
return resp
with transaction.atomic():
before_hook_result = self.__run_before_hooks(
self.action_type, request, objects
)
if before_hook_result is not None:
return before_hook_result
num_parent_objects, num_child_objects = self.execute_action(
objects, **self.get_execution_context()
)
after_hook_result = self.__run_after_hooks(
self.action_type, request, objects
)
if after_hook_result is not None:
return after_hook_result
success_message = self.get_success_message(
num_parent_objects, num_child_objects
)
if success_message is not None:
messages.success(request, success_message)
return redirect(self.next_url)
def form_invalid(self, form):
return super().form_invalid(form)

View File

@@ -0,0 +1,15 @@
from django.apps import apps
from django.http import Http404
from wagtail.admin.views.bulk_action.registry import bulk_action_registry as registry
def index(request, app_label, model_name, action):
try:
model = apps.get_model(app_label, model_name)
except LookupError:
raise Http404
action_class = registry.get_bulk_action_class(app_label, model_name, action)
if action_class is not None:
return action_class(request, model).dispatch(request)
raise Http404

View File

@@ -0,0 +1,40 @@
from wagtail import hooks
from wagtail.admin.views.bulk_action import BulkAction
class BulkActionRegistry:
def __init__(self):
self.actions = {} # {app_name: {model_name: {action_name: action_class]}}
self.has_scanned_for_bulk_actions = False
def _scan_for_bulk_actions(self):
if not self.has_scanned_for_bulk_actions:
for action_class in hooks.get_hooks("register_bulk_action"):
if not issubclass(action_class, BulkAction):
raise Exception(
"{} is not a subclass of {}".format(
action_class.__name__, BulkAction.__name__
)
)
for model in action_class.models:
self.actions.setdefault(model._meta.app_label, {})
self.actions[model._meta.app_label].setdefault(
model._meta.model_name, {}
)
self.actions[model._meta.app_label][model._meta.model_name][
action_class.action_type
] = action_class
self.has_scanned_for_bulk_actions = True
def get_bulk_actions_for_model(self, app_label, model_name):
self._scan_for_bulk_actions()
return self.actions.get(app_label, {}).get(model_name, {}).values()
def get_bulk_action_class(self, app_label, model_name, action_type):
self._scan_for_bulk_actions()
return (
self.actions.get(app_label, {}).get(model_name, {}).get(action_type, None)
)
bulk_action_registry = BulkActionRegistry()