From c463b2cbeae9749ddef23a8c043a0335ebc55e2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 15 May 2020 14:32:37 +0200
Subject: [PATCH 1/8] agendas: Resource model (#38942)

---
 .../migrations/0045_agenda_resources.py       | 38 +++++++++++++++++++
 chrono/agendas/models.py                      | 19 ++++++++++
 chrono/manager/forms.py                       |  4 +-
 tests/test_agendas.py                         | 20 ++++++++++
 4 files changed, 79 insertions(+), 2 deletions(-)
 create mode 100644 chrono/agendas/migrations/0045_agenda_resources.py

diff --git a/chrono/agendas/migrations/0045_agenda_resources.py b/chrono/agendas/migrations/0045_agenda_resources.py
new file mode 100644
index 0000000..de68ba0
--- /dev/null
+++ b/chrono/agendas/migrations/0045_agenda_resources.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('agendas', '0044_event_publication_date'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Resource',
+            fields=[
+                (
+                    'id',
+                    models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
+                ),
+                ('slug', models.SlugField(max_length=160, unique=True, verbose_name='Identifier')),
+                ('label', models.CharField(max_length=150, verbose_name='Label')),
+                (
+                    'description',
+                    models.TextField(
+                        blank=True, help_text='Optional description.', verbose_name='Description'
+                    ),
+                ),
+            ],
+            options={'ordering': ['label']},
+        ),
+        migrations.AddField(
+            model_name='agenda', name='resources', field=models.ManyToManyField(to='agendas.Resource'),
+        ),
+        migrations.AddField(
+            model_name='event', name='resources', field=models.ManyToManyField(to='agendas.Resource'),
+        ),
+    ]
diff --git a/chrono/agendas/models.py b/chrono/agendas/models.py
index 6bacab4..76a5af3 100644
--- a/chrono/agendas/models.py
+++ b/chrono/agendas/models.py
@@ -122,6 +122,7 @@ class Agenda(models.Model):
         verbose_name=_('View Role'),
         on_delete=models.SET_NULL,
     )
+    resources = models.ManyToManyField('Resource')
 
     class Meta:
         ordering = ['label']
@@ -657,6 +658,7 @@ class Event(models.Model):
     full = models.BooleanField(default=False)
     meeting_type = models.ForeignKey(MeetingType, null=True, on_delete=models.CASCADE)
     desk = models.ForeignKey('Desk', null=True, on_delete=models.CASCADE)
+    resources = models.ManyToManyField('Resource')
 
     class Meta:
         ordering = ['agenda', 'start_datetime', 'label']
@@ -1084,6 +1086,23 @@ class Desk(models.Model):
         return [OpeningHour(*time_range) for time_range in (openslots - exceptions)]
 
 
+class Resource(models.Model):
+    slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
+    label = models.CharField(_('Label'), max_length=150)
+    description = models.TextField(_('Description'), blank=True, help_text=_('Optional description.'))
+
+    def __str__(self):
+        return self.label
+
+    class Meta:
+        ordering = ['label']
+
+    def save(self, *args, **kwargs):
+        if not self.slug:
+            self.slug = generate_slug(self)
+        super().save(*args, **kwargs)
+
+
 def ics_directory_path(instance, filename):
     return 'ics/{0}/{1}'.format(str(uuid.uuid4()), filename)
 
diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py
index b6be7c6..fb52dfb 100644
--- a/chrono/manager/forms.py
+++ b/chrono/manager/forms.py
@@ -75,7 +75,7 @@ class NewEventForm(forms.ModelForm):
             'start_datetime': DateTimeWidget(),
             'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
         }
-        exclude = ['full', 'meeting_type', 'desk', 'slug']
+        exclude = ['full', 'meeting_type', 'desk', 'slug', 'resources']
 
 
 class EventForm(forms.ModelForm):
@@ -86,7 +86,7 @@ class EventForm(forms.ModelForm):
             'start_datetime': DateTimeWidget(),
             'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
         }
-        exclude = ['full', 'meeting_type', 'desk']
+        exclude = ['full', 'meeting_type', 'desk', 'resources']
 
 
 class NewMeetingTypeForm(forms.ModelForm):
diff --git a/tests/test_agendas.py b/tests/test_agendas.py
index d3b0fd9..14f9ac8 100644
--- a/tests/test_agendas.py
+++ b/tests/test_agendas.py
@@ -16,6 +16,7 @@ from chrono.agendas.models import (
     Event,
     ICSError,
     MeetingType,
+    Resource,
     TimePeriod,
     TimePeriodException,
     TimePeriodExceptionSource,
@@ -129,6 +130,25 @@ def test_duplicate_slugs():
     assert agenda.slug == 'foo-baz-2'
 
 
+def test_resource_slug():
+    resource = Resource.objects.create(label=u'Foo bar')
+    assert resource.slug == 'foo-bar'
+
+
+def test_resource_existing_slug():
+    resource = Resource.objects.create(label=u'Foo bar', slug='bar')
+    assert resource.slug == 'bar'
+
+
+def test_resource_duplicate_slugs():
+    resource = Resource.objects.create(label=u'Foo baz')
+    assert resource.slug == 'foo-baz'
+    resource = Resource.objects.create(label=u'Foo baz')
+    assert resource.slug == 'foo-baz-1'
+    resource = Resource.objects.create(label=u'Foo baz')
+    assert resource.slug == 'foo-baz-2'
+
+
 def test_event_manager():
     agenda = Agenda(label=u'Foo baz')
     agenda.save()
-- 
2.20.1

