mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-24 17:38:37 -06:00
Fixes #12061: Improve handling of insufficient permissions for widget content
This commit is contained in:
parent
06dec6a2d9
commit
424b336536
@ -11,6 +11,7 @@ from django.urls import NoReverseMatch, reverse
|
|||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from utilities.forms import BootstrapMixin
|
from utilities.forms import BootstrapMixin
|
||||||
|
from utilities.permissions import get_permission_for_model
|
||||||
from utilities.templatetags.builtins.filters import render_markdown
|
from utilities.templatetags.builtins.filters import render_markdown
|
||||||
from utilities.utils import content_type_identifier, content_type_name, get_viewname
|
from utilities.utils import content_type_identifier, content_type_name, get_viewname
|
||||||
from .utils import register_widget
|
from .utils import register_widget
|
||||||
@ -107,8 +108,12 @@ class ObjectCountsWidget(DashboardWidget):
|
|||||||
for content_type_id in self.config['models']:
|
for content_type_id in self.config['models']:
|
||||||
app_label, model_name = content_type_id.split('.')
|
app_label, model_name = content_type_id.split('.')
|
||||||
model = ContentType.objects.get_by_natural_key(app_label, model_name).model_class()
|
model = ContentType.objects.get_by_natural_key(app_label, model_name).model_class()
|
||||||
object_count = model.objects.restrict(request.user, 'view').count
|
permission = get_permission_for_model(model, 'view')
|
||||||
counts.append((model, object_count))
|
if request.user.has_perm(permission):
|
||||||
|
object_count = model.objects.restrict(request.user, 'view').count
|
||||||
|
counts.append((model, object_count))
|
||||||
|
else:
|
||||||
|
counts.append((model, None))
|
||||||
|
|
||||||
return render_to_string(self.template_name, {
|
return render_to_string(self.template_name, {
|
||||||
'counts': counts,
|
'counts': counts,
|
||||||
@ -136,15 +141,21 @@ class ObjectListWidget(DashboardWidget):
|
|||||||
|
|
||||||
def render(self, request):
|
def render(self, request):
|
||||||
app_label, model_name = self.config['model'].split('.')
|
app_label, model_name = self.config['model'].split('.')
|
||||||
content_type = ContentType.objects.get_by_natural_key(app_label, model_name)
|
model = ContentType.objects.get_by_natural_key(app_label, model_name).model_class()
|
||||||
viewname = get_viewname(content_type.model_class(), action='list')
|
viewname = get_viewname(model, action='list')
|
||||||
|
|
||||||
|
# Evaluate user's permission. Note that this controls only whether the HTMX element is
|
||||||
|
# embedded on the page: The view itself will also evaluate permissions separately.
|
||||||
|
permission = get_permission_for_model(model, 'view')
|
||||||
|
has_permission = request.user.has_perm(permission)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
htmx_url = reverse(viewname)
|
htmx_url = reverse(viewname)
|
||||||
except NoReverseMatch:
|
except NoReverseMatch:
|
||||||
htmx_url = None
|
htmx_url = None
|
||||||
|
|
||||||
return render_to_string(self.template_name, {
|
return render_to_string(self.template_name, {
|
||||||
'viewname': viewname,
|
'viewname': viewname,
|
||||||
|
'has_permission': has_permission,
|
||||||
'htmx_url': htmx_url,
|
'htmx_url': htmx_url,
|
||||||
'page_size': self.config.get('page_size'),
|
'page_size': self.config.get('page_size'),
|
||||||
})
|
})
|
||||||
|
@ -3,12 +3,19 @@
|
|||||||
{% if counts %}
|
{% if counts %}
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
{% for model, count in counts %}
|
{% for model, count in counts %}
|
||||||
<a href="{% url model|viewname:"list" %}" class="list-group-item list-group-item-action">
|
{% if count != None %}
|
||||||
<div class="d-flex w-100 justify-content-between align-items-center">
|
<a href="{% url model|viewname:"list" %}" class="list-group-item list-group-item-action">
|
||||||
|
<div class="d-flex w-100 justify-content-between align-items-center">
|
||||||
|
{{ model|meta:"verbose_name_plural"|bettertitle }}
|
||||||
|
<h6 class="mb-1">{{ count }}</h6>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<div class="list-group-item list-group-item-action d-flex w-100 justify-content-between align-items-center">
|
||||||
{{ model|meta:"verbose_name_plural"|bettertitle }}
|
{{ model|meta:"verbose_name_plural"|bettertitle }}
|
||||||
<h6 class="mb-1">{{ count }}</h6>
|
<h6 class="mb-1" title="No permission"><i class="mdi mdi-lock-outline"></i></h6>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
{% if htmx_url %}
|
{% if htmx_url and has_permission %}
|
||||||
<div class="htmx-container" hx-get="{{ htmx_url }}{% if page_size %}?per_page={{ page_size }}{% endif %}" hx-trigger="load"></div>
|
<div class="htmx-container" hx-get="{{ htmx_url }}{% if page_size %}?per_page={{ page_size }}{% endif %}" hx-trigger="load"></div>
|
||||||
|
{% elif htmx_url %}
|
||||||
|
<div class="text-muted text-center">
|
||||||
|
<i class="mdi mdi-lock-outline"></i> No permission to view this content.
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-danger text-center">
|
<div class="text-danger text-center">
|
||||||
<i class="mdi mdi-alert"></i> Unable to load content. Invalid view name: <span class="font-monospace">{{ viewname }}</span>
|
<i class="mdi mdi-alert"></i> Unable to load content. Invalid view name: <span class="font-monospace">{{ viewname }}</span>
|
||||||
|
Loading…
Reference in New Issue
Block a user