Skip to content

Commit 65f0f5e

Browse files
committed
fix: clarify operator precedence, add warning for add-only prefill, add permission tests
- Add parentheses around or-condition in _rules_to_yaml_data for clarity - Warn add-only users when rule_id prefill is skipped due to missing view permission - Add comment explaining why duplicate detection is skipped without view permission - Add tests for add-only user: blank form with warning on prefill, and save_rule skipping duplicate check
1 parent 79022ca commit 65f0f5e

2 files changed

Lines changed: 53 additions & 1 deletion

File tree

netbox_interface_name_rules/tests/test_views.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,53 @@ def test_post_no_permission_raises_403(self):
402402
self.assertEqual(response.status_code, 403)
403403

404404

405+
class RuleTestViewAddOnlyPermissionTest(ViewTestBase2):
406+
"""Test RuleTestView behaviour for users with add but not view permission."""
407+
408+
def _url(self):
409+
return reverse("plugins:netbox_interface_name_rules:interfacenamerule_test")
410+
411+
def _create_add_only_user(self):
412+
from django.contrib.auth.models import Permission
413+
from django.contrib.contenttypes.models import ContentType
414+
415+
user = User.objects.create_user(username="add_only_tester", password=TEST_PASSWORD)
416+
ct = ContentType.objects.get_for_model(InterfaceNameRule)
417+
perm = Permission.objects.get(content_type=ct, codename="add_interfacenamerule")
418+
user.user_permissions.add(perm)
419+
return user
420+
421+
def test_get_with_rule_id_add_only_shows_blank_form_with_warning(self):
422+
"""GET with ?rule_id= when user has add but not view permission returns blank form."""
423+
user = self._create_add_only_user()
424+
self.client.force_login(user)
425+
response = self.client.get(self._url() + f"?rule_id={self.rule.pk}")
426+
self.assertEqual(response.status_code, 200)
427+
form = response.context["form"]
428+
self.assertFalse(form.initial, "Form should have no initial data for add-only user")
429+
self.assertIsNone(response.context.get("loaded_rule"))
430+
from django.contrib.messages import get_messages
431+
432+
msgs = [str(m) for m in get_messages(response.wsgi_request)]
433+
self.assertTrue(any("permission" in m.lower() for m in msgs))
434+
435+
def test_save_rule_add_only_skips_duplicate_check(self):
436+
"""POST save_rule with add-only permission skips duplicate detection, redirects to add."""
437+
user = self._create_add_only_user()
438+
self.client.force_login(user)
439+
add_url = reverse("plugins:netbox_interface_name_rules:interfacenamerule_add")
440+
data = {
441+
"name_template": "ge-0/0/{bay_position}",
442+
"channel_count": "0",
443+
"channel_start": "0",
444+
"module_type": str(self.module_type.pk),
445+
"action": "save_rule",
446+
}
447+
response = self.client.post(self._url(), data)
448+
self.assertEqual(response.status_code, 302)
449+
self.assertIn(add_url, response["Location"])
450+
451+
405452
class RuleApplyDetailViewGetPermissionTest(ViewTestBase2):
406453
"""Test RuleApplyDetailView.get() permission check for unprivileged users."""
407454

netbox_interface_name_rules/views.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def _rules_to_yaml_data(self, queryset):
132132
for rule in queryset.select_related("module_type", "parent_module_type", "device_type", "platform"):
133133
entry = {}
134134
for header, value in zip(InterfaceNameRule.csv_headers, rule.to_csv()):
135-
if value != "" and value is not None or header in {"name_template"}:
135+
if (value != "" and value is not None) or header in {"name_template"}:
136136
entry[header] = value
137137
records.append(entry)
138138
return records
@@ -179,6 +179,8 @@ def get(self, request):
179179
loaded_rule = None
180180
rule_id = request.GET.get("rule_id")
181181
can_view = request.user.has_perm("netbox_interface_name_rules.view_interfacenamerule")
182+
if rule_id and not can_view:
183+
messages.warning(request, "You do not have permission to load an existing rule.")
182184
if rule_id and can_view:
183185
try:
184186
loaded_rule = InterfaceNameRule.objects.select_related(
@@ -240,6 +242,9 @@ def _handle_save_rule(self, request, cd):
240242
module_type = cd.get("module_type")
241243
module_type_pattern = cd.get("module_type_pattern", "")
242244

245+
# Skip duplicate detection when the user lacks view permission — we cannot
246+
# query existing rules without it, so add-only users always land on the
247+
# create form (potentially allowing duplicates).
243248
if request.user.has_perm("netbox_interface_name_rules.view_interfacenamerule"):
244249
qs = InterfaceNameRule.objects.all()
245250
if module_type_is_regex:

0 commit comments

Comments
 (0)