Skip to content

Commit

Permalink
feat: actions detail and submit line permissions accepts object_id (#552
Browse files Browse the repository at this point in the history
)
  • Loading branch information
lukasvinclav committed Jul 9, 2024
1 parent d3ddca2 commit 7532d0a
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 14 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ class UserAdmin(ModelAdmin):
actions_detail = ["change_detail_action_block"]
actions_submit_line = ["submit_line_action_activate"]

@action(description=_("Save & Activate"))
@action(description=_("Save & Activate"), permissions=["submit_line_action_activate"])
def submit_line_action_activate(self, request: HttpRequest, obj: User):
"""
If instance is modified in any way, it also needs to be saved,
Expand All @@ -431,6 +431,9 @@ class UserAdmin(ModelAdmin):
obj.is_active = True
obj.save()

def has_submit_line_action_activate_permission(self, request: HttpRequest, object_id: Union[str, int]):
pass

@action(description=_("Import"), url_path="import")
def changelist_global_action_import(self, request: HttpRequest):
"""
Expand All @@ -455,7 +458,7 @@ class UserAdmin(ModelAdmin):
"""
return redirect(f"https://example.com/{object_id}")

@action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"})
@action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"}, permissions=["change_detail_action_block"])
def change_detail_action_block(self, request: HttpRequest, object_id: int):
"""
Handler for detail action.
Expand All @@ -470,6 +473,10 @@ class UserAdmin(ModelAdmin):
return redirect(
reverse_lazy("admin:users_user_change", args=(object_id,))
)


def has_change_detail_action_block_permission(self, request: HttpRequest, object_id: Union[str, int]):
pass
```

### Action with form example
Expand Down
39 changes: 28 additions & 11 deletions src/unfold/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import copy
from functools import update_wrapper
from typing import Any, Callable, Dict, List, Optional, Tuple
from typing import Any, Callable, Dict, List, Optional, Tuple, Union

from django import forms
from django.contrib.admin import ModelAdmin as BaseModelAdmin
Expand Down Expand Up @@ -256,20 +256,33 @@ def get_fieldsets(self, request: HttpRequest, obj=None) -> FieldsetsType:
return super().get_fieldsets(request, obj)

def _filter_unfold_actions_by_permissions(
self, request: HttpRequest, actions: List[UnfoldAction]
self,
request: HttpRequest,
actions: List[UnfoldAction],
object_id: Optional[Union[int, str]] = None,
) -> List[UnfoldAction]:
"""Filter out any Unfold actions that the user doesn't have access to."""
filtered_actions = []
for action in actions:
if not hasattr(action.method, "allowed_permissions"):
filtered_actions.append(action)
continue

permission_checks = (
getattr(self, f"has_{permission}_permission")
for permission in action.method.allowed_permissions
)
if any(has_permission(request) for has_permission in permission_checks):
filtered_actions.append(action)

if object_id:
if any(
has_permission(request, object_id)
for has_permission in permission_checks
):
filtered_actions.append(action)
else:
if any(has_permission(request) for has_permission in permission_checks):
filtered_actions.append(action)

return filtered_actions

def get_actions_list(self, request: HttpRequest) -> List[UnfoldAction]:
Expand All @@ -283,9 +296,11 @@ def _get_base_actions_list(self) -> List[UnfoldAction]:
"""
return [self.get_unfold_action(action) for action in self.actions_list or []]

def get_actions_detail(self, request: HttpRequest) -> List[UnfoldAction]:
def get_actions_detail(
self, request: HttpRequest, object_id: int
) -> List[UnfoldAction]:
return self._filter_unfold_actions_by_permissions(
request, self._get_base_actions_detail()
request, self._get_base_actions_detail(), object_id
)

def _get_base_actions_detail(self) -> List[UnfoldAction]:
Expand All @@ -305,9 +320,11 @@ def _get_base_actions_row(self) -> List[UnfoldAction]:
"""
return [self.get_unfold_action(action) for action in self.actions_row or []]

def get_actions_submit_line(self, request: HttpRequest) -> List[UnfoldAction]:
def get_actions_submit_line(
self, request: HttpRequest, object_id: int
) -> List[UnfoldAction]:
return self._filter_unfold_actions_by_permissions(
request, self._get_base_actions_submit_line()
request, self._get_base_actions_submit_line(), object_id
)

def _get_base_actions_submit_line(self) -> List[UnfoldAction]:
Expand Down Expand Up @@ -405,7 +422,7 @@ def changeform_view(

actions = []
if object_id:
for action in self.get_actions_detail(request):
for action in self.get_actions_detail(request, object_id):
actions.append(
{
"title": action.description,
Expand All @@ -419,7 +436,7 @@ def changeform_view(

extra_context.update(
{
"actions_submit_line": self.get_actions_submit_line(request),
"actions_submit_line": self.get_actions_submit_line(request, object_id),
"actions_detail": actions,
}
)
Expand Down Expand Up @@ -486,7 +503,7 @@ def save_model(
) -> None:
super().save_model(request, obj, form, change)

for action in self.get_actions_submit_line(request):
for action in self.get_actions_submit_line(request, obj.pk):
if action.action_name not in request.POST:
continue

Expand Down
3 changes: 2 additions & 1 deletion src/unfold/dataclasses.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import Dict, Optional
from typing import Dict, Optional, Union

from .typing import ActionFunction

Expand All @@ -11,3 +11,4 @@ class UnfoldAction:
description: str
path: str
attrs: Optional[Dict] = None
object_id: Optional[Union[int, str]] = None

0 comments on commit 7532d0a

Please sign in to comment.