[ADD] HORILLA VIEWS: Accessibility method dynamic mapping to the HCV and HLV

This commit is contained in:
Horilla
2024-06-15 14:07:15 +05:30
parent 20bc0a6c24
commit b55a5ca849
7 changed files with 104 additions and 30 deletions

View File

@@ -2,6 +2,7 @@
horilla/cbv_methods.py horilla/cbv_methods.py
""" """
import types
import uuid import uuid
from urllib.parse import urlencode from urllib.parse import urlencode
from venv import logger from venv import logger
@@ -236,6 +237,14 @@ def sortby(
) )
reverse = cache[request.session.session_key].reverse reverse = cache[request.session.session_key].reverse
none_ids = [] none_ids = []
none_queryset = []
model = queryset.model
model_attr = getattribute(model, sort_key)
is_method = isinstance(model_attr, types.FunctionType)
if not is_method:
none_queryset = queryset.filter(**{f"{sort_key}__isnull": True})
none_ids = list(none_queryset.values_list("id", flat=True))
queryset = queryset.exclude(id__in=none_ids)
def _sortby(object): def _sortby(object):
result = getattribute(object, attr=sort_key) result = getattribute(object, attr=sort_key)
@@ -258,10 +267,14 @@ def sortby(
except TypeError: except TypeError:
none_queryset = list(queryset.filter(id__in=none_ids)) none_queryset = list(queryset.filter(id__in=none_ids))
queryset = sorted(queryset.exclude(id__in=none_ids), key=_sortby, reverse=order) queryset = sorted(queryset.exclude(id__in=none_ids), key=_sortby, reverse=order)
queryset = queryset + none_queryset
cache[request.session.session_key].reverse = order cache[request.session.session_key].reverse = order
order = "asc" if not order else "desc" if order:
order = "asc"
queryset = list(queryset) + list(none_queryset)
else:
queryset = list(none_queryset) + list(queryset)
order = "desc"
setattr(request, "sort_order", order) setattr(request, "sort_order", order)
setattr(request, "sort_key", sort_key) setattr(request, "sort_key", sort_key)
return queryset return queryset

View File

@@ -52,6 +52,23 @@ class HorillaListView(ListView):
bulk_select_option: bool = True bulk_select_option: bool = True
action_method: str = """""" action_method: str = """"""
"""
eg:
def accessibility(
request, instance: object = None, user_perms: PermWrapper = [], *args, **kwargs
)->bool:
# True if accessible to the action else False
return True
actions = [
{
"action": "Edit",
"accessibility": "path_to_your.accessibility", # path to your accessibility method
"attrs": '''{instance_attributes_called_like_this}''',
},
etc..
]
"""
actions: list = [] actions: list = []
option_method: str = "" option_method: str = ""
@@ -392,7 +409,23 @@ class HorillaCardView(ListView):
search_url: str = "" search_url: str = ""
details: dict = {} details: dict = {}
"""
eg:
def accessibility(
request, instance: object = None, user_perms: PermWrapper = [], *args, **kwargs
)->bool:
# True if accessible to the action else False
return True
actions = [
{
"action": "Edit",
"accessibility": "path_to_your.accessibility", # path to your accessibility method
"attrs": '''{instance_attributes_called_like_this}''',
},
etc..
]
"""
actions: list = [] actions: list = []
card_attrs: str = """""" card_attrs: str = """"""

View File

@@ -199,13 +199,15 @@
{% if not option_method %} {% if not option_method %}
<div class="oh-btn-group"> <div class="oh-btn-group">
{% for option in options %} {% for option in options %}
<a {% if option.accessibility|accessibility:instance %}
href="#" <a
title="{{option.option|safe}}" href="#"
{{option.attrs|format:instance|safe}} title="{{option.option|safe}}"
> {{option.attrs|format:instance|safe}}
<ion-icon name="{{option.icon}}"></ion-icon> >
</a> <ion-icon name="{{option.icon}}"></ion-icon>
</a>
{% endif %}
{% endfor %} {% endfor %}
</div> </div>
{% else %} {{instance|getattribute:option_method|safe}} {% endif %} {% else %} {{instance|getattribute:option_method|safe}} {% endif %}
@@ -215,13 +217,15 @@
{% if not action_method %} {% if not action_method %}
<div class="oh-btn-group"> <div class="oh-btn-group">
{% for action in actions %} {% for action in actions %}
<a {% if action.accessibility|accessibility:instance %}
href="#" <a
title="{{action.action|safe}}" href="#"
{{action.attrs|format:instance|safe}} title="{{action.action|safe}}"
> {{action.attrs|format:instance|safe}}
<ion-icon name="{{action.icon}}"></ion-icon> >
</a> <ion-icon name="{{action.icon}}"></ion-icon>
</a>
{% endif %}
{% endfor %} {% endfor %}
</div> </div>
{% else %} {{instance|getattribute:action_method|safe}} {% endif %} {% else %} {{instance|getattribute:action_method|safe}} {% endif %}

View File

@@ -48,9 +48,11 @@
> >
<ul class="oh-dropdown__items"> <ul class="oh-dropdown__items">
{% for action in actions %} {% for action in actions %}
{% if action.accessibility|accessibility:instance %}
<li class="oh-dropdown__item"> <li class="oh-dropdown__item">
<a {{action.attrs|format:instance|safe}}>{{instance|getattribute:action.action|default:action.action}}</a> <a {{action.attrs|format:instance|safe}}>{{instance|getattribute:action.action|default:action.action}}</a>
</li> </li>
{% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>

View File

@@ -218,13 +218,15 @@
{% if not option_method %} {% if not option_method %}
<div class="oh-btn-group"> <div class="oh-btn-group">
{% for option in options %} {% for option in options %}
<a {% if option.accessibility|accessibility:instance %}
href="#" <a
title="{{option.option|safe}}" href="#"
{{option.attrs|format:instance|safe}} title="{{option.option|safe}}"
> {{option.attrs|format:instance|safe}}
<ion-icon name="{{option.icon}}"></ion-icon> >
</a> <ion-icon name="{{option.icon}}"></ion-icon>
</a>
{% endif %}
{% endfor %} {% endfor %}
</div> </div>
{% else %} {{instance|getattribute:option_method|safe}} {% endif %} {% else %} {{instance|getattribute:option_method|safe}} {% endif %}
@@ -234,13 +236,15 @@
{% if not action_method %} {% if not action_method %}
<div class="oh-btn-group"> <div class="oh-btn-group">
{% for action in actions %} {% for action in actions %}
<a {% if action.accessibility|accessibility:instance %}
href="#" <a
title="{{action.action|safe}}" href="#"
{{action.attrs|format:instance|safe}} title="{{action.action|safe}}"
> {{action.attrs|format:instance|safe}}
<ion-icon name="{{action.icon}}"></ion-icon> >
</a> <ion-icon name="{{action.icon}}"></ion-icon>
</a>
{% endif %}
{% endfor %} {% endfor %}
</div> </div>
{% else %} {{instance|getattribute:action_method|safe}} {% endif %} {% else %} {{instance|getattribute:action_method|safe}} {% endif %}

View File

@@ -10,3 +10,4 @@ $("#{{dynamic_id}} [name={{field.name}}]").change(function (e) {
} }
}); });
</script> </script>

View File

@@ -10,8 +10,12 @@ import types
from django import template from django import template
from django.conf import settings from django.conf import settings
from django.contrib.auth.context_processors import PermWrapper
from django.template.defaultfilters import register from django.template.defaultfilters import register
from base.thread_local_middleware import _thread_locals
from horilla.config import import_method
register = template.Library() register = template.Library()
@@ -60,3 +64,16 @@ def format(string: str, instance: object):
formatted_string = string.format(**format_context) formatted_string = string.format(**format_context)
return formatted_string return formatted_string
@register.filter("accessibility")
def accessibility(method: str, instance=None):
if method:
request = getattr(_thread_locals, "request")
method = import_method(method)
return method(
request,
instance,
PermWrapper(request.user),
)
return True