Skip to content

Commit a6ca8e9

Browse files
authored
feat: ability to edit category slug in django admin (#1543)
* feat: make it possible to edit category slug in django admin * feat: add feature flag for category slug editability in Django admin * test: add tests for category slug editability based on feature flag
1 parent b6e6aa6 commit a6ca8e9

File tree

4 files changed

+62
-4
lines changed

4 files changed

+62
-4
lines changed

app/signals/apps/signals/admin/category.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
# Copyright (C) 2022 Gemeente Amsterdam
33
import csv
44

5+
from django.conf import settings
56
from django.contrib import admin
67
from django.db.models import Q
8+
from django.forms import ModelForm
79
from django.http import HttpResponse
810
from django.utils import timezone
911
from import_export.admin import ExportActionMixin, ImportExportModelAdmin
@@ -69,6 +71,17 @@ class StatusMessageCategoryInline(admin.TabularInline):
6971
extra = 1
7072

7173

74+
class CategoryAdminForm(ModelForm):
75+
class Meta:
76+
model = Category
77+
fields = '__all__'
78+
help_texts = {
79+
'slug': (
80+
"<br><b>Note:</b> After modifying the slug, the machine learning model must be retrained."
81+
),
82+
}
83+
84+
7285
class CategoryAdmin(ImportExportModelAdmin, ExportActionMixin):
7386
resource_class = CategoryResource
7487

@@ -80,14 +93,24 @@ class CategoryAdmin(ImportExportModelAdmin, ExportActionMixin):
8093
inlines = (ServiceLevelObjectiveInline, CategoryDepartmentInline, StatusMessageCategoryInline)
8194
fields = ('name', 'slug', 'parent', 'is_active', 'description', 'handling_message', 'public_name',
8295
'is_public_accessible', 'icon',)
83-
readonly_fields = ('slug',)
8496
view_on_site = True
8597

8698
search_fields = ('name', 'public_name',)
8799
ordering = ('parent__name', 'name',)
88100

89101
actions = ['download_csv']
90102

103+
def get_form(self, request, obj=None, **kwargs):
104+
if settings.FEATURE_FLAGS.get('CATEGORY_SLUG_EDITABLE', False):
105+
kwargs['form'] = CategoryAdminForm
106+
return super().get_form(request, obj, **kwargs)
107+
108+
def get_readonly_fields(self, request, obj=None):
109+
readonly_fields = super().get_readonly_fields(request, obj)
110+
if not settings.FEATURE_FLAGS.get('CATEGORY_SLUG_EDITABLE', False):
111+
readonly_fields = list(readonly_fields) + ['slug']
112+
return readonly_fields
113+
91114
def has_delete_permission(self, request, obj=None):
92115
return False
93116

app/signals/apps/signals/models/category.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ class Category(TrackFields, models.Model):
9292
null=True, blank=True)
9393

9494
# SIG-1135, the slug is auto populated using the django-extensions "AutoSlugField"
95-
slug = AutoSlugField(populate_from=['name', ], blank=False, overwrite=False, editable=False)
95+
slug = AutoSlugField(populate_from=['name', ], blank=False,
96+
overwrite=False, editable=settings.FEATURE_FLAGS.get('CATEGORY_SLUG_EDITABLE', False))
9697

9798
name = models.CharField(max_length=255)
9899

@@ -188,7 +189,7 @@ def has_icon(self):
188189
def clean(self):
189190
super().clean()
190191

191-
if self.pk and self.slug:
192+
if self.pk and self.slug and not settings.FEATURE_FLAGS.get('CATEGORY_SLUG_EDITABLE', False):
192193
if not Category.objects.filter(id=self.pk, slug=self.slug).exists():
193194
raise ValidationError('Category slug cannot be changed')
194195

app/signals/apps/signals/tests/test_models.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,37 @@ def test_invalid_show_in_filter_and_additional_config_parent_category_configurat
703703
self.assertIn('Value of "show_children_in_filter" is not a valid boolean', messages)
704704
self.assertIn('Only "show_children_in_filter" is allowed', messages)
705705

706+
@override_settings(FEATURE_FLAGS={'CATEGORY_SLUG_EDITABLE': True})
707+
def test_slug_can_be_updated_when_feature_flag_enabled(self):
708+
"""
709+
When CATEGORY_SLUG_EDITABLE feature flag is True, category slug should be editable
710+
"""
711+
category = factories.CategoryFactory(name='Original Name')
712+
original_slug = category.slug
713+
714+
category.slug = 'new-custom-slug'
715+
category.save()
716+
category.refresh_from_db()
717+
718+
self.assertEqual(category.slug, 'new-custom-slug')
719+
self.assertNotEqual(category.slug, original_slug)
720+
721+
@override_settings(FEATURE_FLAGS={'CATEGORY_SLUG_EDITABLE': False})
722+
def test_slug_cannot_be_updated_when_feature_flag_disabled(self):
723+
"""
724+
When CATEGORY_SLUG_EDITABLE feature flag is False, category slug should not be editable
725+
"""
726+
category = factories.CategoryFactory(name='Original Name')
727+
original_slug = category.slug
728+
729+
category.slug = 'new-custom-slug'
730+
731+
with self.assertRaises(ValidationError):
732+
category.save()
733+
734+
category.refresh_from_db()
735+
self.assertEqual(category.slug, original_slug)
736+
706737

707738
class TestCategoryDeclarations(TestCase):
708739

app/signals/settings.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,10 @@ def is_super_user(user) -> bool:
543543
'DSL_RUN_ROUTING_EXPRESSIONS_ON_UPDATES': os.getenv('DSL_RUN_ROUTING_EXPRESSIONS_ON_UPDATES', False) in TRUE_VALUES,
544544

545545
# Enable/Disable showing employee details in the PDF export
546-
'SHOW_EMPLOYEE_DETAILS_IN_PDF': os.getenv('SHOW_EMPLOYEE_DETAILS_IN_PDF', True) in TRUE_VALUES
546+
'SHOW_EMPLOYEE_DETAILS_IN_PDF': os.getenv('SHOW_EMPLOYEE_DETAILS_IN_PDF', True) in TRUE_VALUES,
547+
548+
# Enable/Disable editing category slug in Django admin
549+
'CATEGORY_SLUG_EDITABLE': os.getenv('CATEGORY_SLUG_EDITABLE', False) in TRUE_VALUES
547550
}
548551

549552
# Per default log to console

0 commit comments

Comments
 (0)