agendas: add slug form absence reason model (#53147)
This commit is contained in:
parent
b8105d19ff
commit
992189a335
|
@ -0,0 +1,20 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agendas', '0082_text_to_jsonb'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='absencereason',
|
||||
name='slug',
|
||||
field=models.SlugField(max_length=160, null=True, verbose_name='Identifier'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='absencereason',
|
||||
unique_together=['group', 'slug'],
|
||||
),
|
||||
]
|
|
@ -0,0 +1,40 @@
|
|||
from django.db import migrations
|
||||
from django.utils.text import slugify
|
||||
|
||||
|
||||
def generate_slug(instance, **query_filters):
|
||||
base_slug = slugify(instance.label)
|
||||
slug = base_slug
|
||||
i = 1
|
||||
while True:
|
||||
queryset = instance._meta.model.objects.filter(slug=slug, **query_filters).exclude(pk=instance.pk)
|
||||
if not queryset.exists():
|
||||
break
|
||||
slug = '%s-%s' % (base_slug, i)
|
||||
i += 1
|
||||
return slug
|
||||
|
||||
|
||||
def set_slug_on_absence_reasons(apps, schema_editor):
|
||||
AbsenceReason = apps.get_model('agendas', 'AbsenceReason')
|
||||
for reason in AbsenceReason.objects.all().order_by('-pk'):
|
||||
if (
|
||||
reason.slug
|
||||
and not AbsenceReason.objects.filter(slug=reason.slug, group=reason.group)
|
||||
.exclude(pk=reason.pk)
|
||||
.exists()
|
||||
):
|
||||
continue
|
||||
reason.slug = generate_slug(reason, group=reason.group)
|
||||
reason.save(update_fields=['slug'])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agendas', '0083_reason_slug'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(set_slug_on_absence_reasons, migrations.RunPython.noop),
|
||||
]
|
|
@ -0,0 +1,16 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agendas', '0084_reason_slug'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='absencereason',
|
||||
name='slug',
|
||||
field=models.SlugField(max_length=160, verbose_name='Identifier'),
|
||||
),
|
||||
]
|
|
@ -2554,10 +2554,21 @@ class AbsenceReasonGroup(models.Model):
|
|||
|
||||
class AbsenceReason(models.Model):
|
||||
group = models.ForeignKey(AbsenceReasonGroup, on_delete=models.CASCADE, related_name='absence_reasons')
|
||||
slug = models.SlugField(_('Identifier'), max_length=160)
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
|
||||
class Meta:
|
||||
ordering = ['label']
|
||||
unique_together = ['group', 'slug']
|
||||
|
||||
def __str__(self):
|
||||
return self.label
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = generate_slug(self, group=self.group)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def base_slug(self):
|
||||
return slugify(self.label)
|
||||
|
|
|
@ -53,6 +53,20 @@ from . import widgets
|
|||
from .widgets import SplitDateTimeField
|
||||
|
||||
|
||||
class AbsenceReasonForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = AbsenceReason
|
||||
fields = ['label', 'slug']
|
||||
|
||||
def clean_slug(self):
|
||||
slug = self.cleaned_data['slug']
|
||||
|
||||
if self.instance.group.absence_reasons.filter(slug=slug).exclude(pk=self.instance.pk).exists():
|
||||
raise ValidationError(_('Another absence reason exists with the same identifier.'))
|
||||
|
||||
return slug
|
||||
|
||||
|
||||
class AgendaAddForm(forms.ModelForm):
|
||||
edit_role = forms.ModelChoiceField(
|
||||
label=_('Edit Role'), required=False, queryset=Group.objects.all().order_by('name')
|
||||
|
|
|
@ -76,6 +76,7 @@ from chrono.agendas.models import (
|
|||
)
|
||||
|
||||
from .forms import (
|
||||
AbsenceReasonForm,
|
||||
AgendaAddForm,
|
||||
AgendaBookingDelaysForm,
|
||||
AgendaDuplicateForm,
|
||||
|
@ -700,7 +701,7 @@ absence_reason_add = AbsenceReasonAddView.as_view()
|
|||
class AbsenceReasonEditView(UpdateView):
|
||||
template_name = 'chrono/manager_absence_reason_form.html'
|
||||
model = AbsenceReason
|
||||
fields = ['label']
|
||||
form_class = AbsenceReasonForm
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.group_pk = kwargs.pop('group_pk')
|
||||
|
|
|
@ -68,17 +68,24 @@ def test_add_group_as_manager(app, manager_user, agenda_with_restrictions):
|
|||
|
||||
def test_edit_group(app, admin_user):
|
||||
group = AbsenceReasonGroup.objects.create(label='Foo bar')
|
||||
group2 = AbsenceReasonGroup.objects.create(label='baz')
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/absence-reasons/')
|
||||
resp = resp.click(href='/manage/absence-reason/group/%s/edit/' % group.pk)
|
||||
resp.form['label'] = 'Foo bar baz'
|
||||
resp.form['slug'] = 'baz'
|
||||
resp.form['slug'] = group2.slug
|
||||
resp = resp.form.submit()
|
||||
assert resp.context['form'].errors['slug'] == [
|
||||
'Absence reason group with this Identifier already exists.'
|
||||
]
|
||||
|
||||
resp.form['slug'] = 'baz2'
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/absence-reasons/')
|
||||
group.refresh_from_db()
|
||||
assert group.label == 'Foo bar baz'
|
||||
assert group.slug == 'baz'
|
||||
assert group.slug == 'baz2'
|
||||
|
||||
|
||||
def test_edit_group_as_manager(app, manager_user, agenda_with_restrictions):
|
||||
|
@ -121,6 +128,7 @@ def test_add_reason(app, admin_user):
|
|||
assert resp.location.endswith('/manage/absence-reasons/')
|
||||
assert reason.label == 'Foo reason'
|
||||
assert reason.group == group
|
||||
assert reason.slug == 'foo-reason'
|
||||
|
||||
|
||||
def test_add_reason_as_manager(app, manager_user, agenda_with_restrictions):
|
||||
|
@ -133,17 +141,25 @@ def test_add_reason_as_manager(app, manager_user, agenda_with_restrictions):
|
|||
def test_edit_reason(app, admin_user):
|
||||
group = AbsenceReasonGroup.objects.create(label='Foo bar')
|
||||
reason = AbsenceReason.objects.create(label='Foo reason', group=group)
|
||||
reason2 = AbsenceReason.objects.create(label='Baz', group=group)
|
||||
group2 = AbsenceReasonGroup.objects.create(label='Foo bar')
|
||||
reason3 = AbsenceReason.objects.create(label='Foo bar reason', group=group2)
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/absence-reasons/')
|
||||
resp = resp.click(href='/manage/absence-reason/group/%s/%s/edit/' % (group.pk, reason.pk))
|
||||
resp.form['label'] = 'Foo bar reason'
|
||||
resp.form['slug'] = reason2.slug
|
||||
resp = resp.form.submit()
|
||||
assert resp.context['form'].errors['slug'] == ['Another absence reason exists with the same identifier.']
|
||||
|
||||
resp.form['slug'] = reason3.slug
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/absence-reasons/')
|
||||
reason.refresh_from_db()
|
||||
assert reason.label == 'Foo bar reason'
|
||||
assert reason.slug == 'foo-bar-reason'
|
||||
|
||||
group2 = AbsenceReasonGroup.objects.create(label='Foo bar baz')
|
||||
app.get('/manage/absence-reason/group/%s/%s/edit/' % (group2.pk, reason.pk), status=404)
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ from django.test import override_settings
|
|||
from django.utils.timezone import localtime, make_aware, now
|
||||
|
||||
from chrono.agendas.models import (
|
||||
AbsenceReasonGroup,
|
||||
Agenda,
|
||||
AgendaNotificationsSettings,
|
||||
AgendaReminderSettings,
|
||||
|
@ -176,6 +177,25 @@ def test_category_duplicate_slugs():
|
|||
assert category.slug == 'foo-baz-2'
|
||||
|
||||
|
||||
def test_absence_reason_group_slug():
|
||||
group = AbsenceReasonGroup.objects.create(label=u'Foo bar')
|
||||
assert group.slug == 'foo-bar'
|
||||
|
||||
|
||||
def test_absence_reason_group_existing_slug():
|
||||
group = AbsenceReasonGroup.objects.create(label=u'Foo bar', slug='bar')
|
||||
assert group.slug == 'bar'
|
||||
|
||||
|
||||
def test_absence_reason_group_duplicate_slugs():
|
||||
group = AbsenceReasonGroup.objects.create(label=u'Foo baz')
|
||||
assert group.slug == 'foo-baz'
|
||||
group = AbsenceReasonGroup.objects.create(label=u'Foo baz')
|
||||
assert group.slug == 'foo-baz-1'
|
||||
group = AbsenceReasonGroup.objects.create(label=u'Foo baz')
|
||||
assert group.slug == 'foo-baz-2'
|
||||
|
||||
|
||||
@pytest.mark.parametrize('with_prefetch', [True, False])
|
||||
def test_agenda_is_available_for_simple_management(settings, with_prefetch):
|
||||
settings.EXCEPTIONS_SOURCES = {
|
||||
|
|
Loading…
Reference in New Issue