From 6730e0903d1f9e17ac170636095dcda2c6e67df0 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Tue, 28 Sep 2021 17:44:50 +0200
Subject: [PATCH 1/3] api: display roles on agenda details (#57103)

---
 chrono/api/views.py   |  4 +++-
 tests/api/test_all.py | 41 ++++++++++++++++++++++++++++++++++-------
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/chrono/api/views.py b/chrono/api/views.py
index ed6992a..65c3b6a 100644
--- a/chrono/api/views.py
+++ b/chrono/api/views.py
@@ -348,16 +348,18 @@ def get_all_slots(
 def get_agenda_detail(request, agenda, check_events=False):
     agenda_detail = {
         'id': agenda.slug,
         'slug': agenda.slug,  # kept for compatibility
         'text': agenda.label,
         'kind': agenda.kind,
         'minimal_booking_delay': agenda.minimal_booking_delay,
         'maximal_booking_delay': agenda.maximal_booking_delay,
+        'edit_role': agenda.edit_role.name if agenda.edit_role else None,
+        'view_role': agenda.view_role.name if agenda.view_role else None,
     }
 
     if agenda.kind == 'meetings':
         agenda_detail['resources'] = [
             {'id': r.slug, 'text': r.label, 'description': r.description} for r in agenda.resources.all()
         ]
     if agenda.kind == 'events':
         agenda_detail['api'] = {
@@ -718,17 +720,17 @@ class Agendas(APIView):
         for agenda in agendas_queryset:
             if with_open_events and not any(
                 not e.full for e in agenda.get_open_events(prefetched_queryset=True)
             ):
                 # exclude agendas without open events
                 continue
             agendas.append(get_agenda_detail(request, agenda))
 
-        return Response({'data': agendas})
+        return Response({'err': 0, 'data': agendas})
 
 
 agendas = Agendas.as_view()
 
 
 class AgendaDetail(APIView):
     """
     Retrieve an agenda instance.
diff --git a/tests/api/test_all.py b/tests/api/test_all.py
index 1e2b617..b640f6f 100644
--- a/tests/api/test_all.py
+++ b/tests/api/test_all.py
@@ -1,11 +1,12 @@
 import datetime
 
 import pytest
+from django.contrib.auth.models import Group
 from django.db import connection
 from django.test.utils import CaptureQueriesContext
 from django.utils.timezone import localtime, now
 
 from chrono.agendas.models import (
     AbsenceReason,
     AbsenceReasonGroup,
     Agenda,
@@ -17,89 +18,109 @@ from chrono.agendas.models import (
     TimePeriodException,
     VirtualMember,
 )
 
 pytestmark = pytest.mark.django_db
 
 
 def test_agendas_api(app):
+    edit_group = Group.objects.create(name='Edit')
+    view_group = Group.objects.create(name='View')
     category_a = Category.objects.create(label='Category A')
     category_b = Category.objects.create(label='Category B')
     group = AbsenceReasonGroup.objects.create(label='Foo')
     reason = AbsenceReason.objects.create(group=group, label='Foo bar')
     reason2 = AbsenceReason.objects.create(group=group, label='Foo bar baz')
-    event_agenda = Agenda.objects.create(label='Foo bar', category=category_a, absence_reasons_group=group)
+    event_agenda = Agenda.objects.create(
+        label='Foo bar', category=category_a, absence_reasons_group=group, edit_role=edit_group
+    )
     Desk.objects.create(agenda=event_agenda, slug='_exceptions_holder')
     event_agenda2 = Agenda.objects.create(label='Foo bar 2', category=category_a)
     Desk.objects.create(agenda=event_agenda2, slug='_exceptions_holder')
     event_agenda3 = Agenda.objects.create(label='Foo bar 3', absence_reasons_group=group)
     Desk.objects.create(agenda=event_agenda3, slug='_exceptions_holder')
-    meetings_agenda1 = Agenda.objects.create(label='Foo bar Meeting', kind='meetings', category=category_b)
+    meetings_agenda1 = Agenda.objects.create(
+        label='Foo bar Meeting', kind='meetings', category=category_b, view_role=view_group
+    )
     Agenda.objects.create(label='Foo bar Meeting 2', kind='meetings')
     resource1 = Resource.objects.create(label='Resource 1', description='Foo bar Resource 1')
     resource2 = Resource.objects.create(label='Resource 2', description='Foo bar Resource 2')
     Resource.objects.create(label='Resource 3')
     meetings_agenda1.resources.add(resource1, resource2)
     Agenda.objects.create(
-        label='Virtual Agenda', kind='virtual', minimal_booking_delay=1, maximal_booking_delay=56
+        label='Virtual Agenda',
+        kind='virtual',
+        minimal_booking_delay=1,
+        maximal_booking_delay=56,
+        edit_role=edit_group,
+        view_role=view_group,
     )
     resp = app.get('/api/agenda/')
     assert resp.json == {
+        'err': 0,
         'data': [
             {
                 'text': 'Foo bar',
                 'id': 'foo-bar',
                 'slug': 'foo-bar',
                 'kind': 'events',
                 'minimal_booking_delay': 1,
                 'maximal_booking_delay': 56,
+                'edit_role': 'Edit',
+                'view_role': None,
                 'absence_reasons': [
                     {'id': reason.slug, 'slug': reason.slug, 'text': reason.label, 'label': reason.label},
                     {'id': reason2.slug, 'slug': reason2.slug, 'text': reason2.label, 'label': reason2.label},
                 ],
                 'api': {
                     'datetimes_url': 'http://testserver/api/agenda/foo-bar/datetimes/',
                     'fillslots_url': 'http://testserver/api/agenda/foo-bar/fillslots/',
                 },
             },
             {
                 'text': 'Foo bar 2',
                 'id': 'foo-bar-2',
                 'kind': 'events',
                 'slug': 'foo-bar-2',
                 'minimal_booking_delay': 1,
                 'maximal_booking_delay': 56,
+                'edit_role': None,
+                'view_role': None,
                 'api': {
                     'datetimes_url': 'http://testserver/api/agenda/foo-bar-2/datetimes/',
                     'fillslots_url': 'http://testserver/api/agenda/foo-bar-2/fillslots/',
                 },
             },
             {
                 'text': 'Foo bar 3',
                 'id': 'foo-bar-3',
                 'kind': 'events',
                 'slug': 'foo-bar-3',
                 'minimal_booking_delay': 1,
                 'maximal_booking_delay': 56,
+                'edit_role': None,
+                'view_role': None,
                 'absence_reasons': [
                     {'id': reason.slug, 'slug': reason.slug, 'text': reason.label, 'label': reason.label},
                     {'id': reason2.slug, 'slug': reason2.slug, 'text': reason2.label, 'label': reason2.label},
                 ],
                 'api': {
                     'datetimes_url': 'http://testserver/api/agenda/foo-bar-3/datetimes/',
                     'fillslots_url': 'http://testserver/api/agenda/foo-bar-3/fillslots/',
                 },
             },
             {
                 'text': 'Foo bar Meeting',
                 'id': 'foo-bar-meeting',
                 'slug': 'foo-bar-meeting',
                 'minimal_booking_delay': 1,
                 'maximal_booking_delay': 56,
+                'edit_role': None,
+                'view_role': 'View',
                 'kind': 'meetings',
                 'resources': [
                     {'id': 'resource-1', 'text': 'Resource 1', 'description': 'Foo bar Resource 1'},
                     {'id': 'resource-2', 'text': 'Resource 2', 'description': 'Foo bar Resource 2'},
                 ],
                 'api': {
                     'meetings_url': 'http://testserver/api/agenda/foo-bar-meeting/meetings/',
                     'desks_url': 'http://testserver/api/agenda/foo-bar-meeting/desks/',
@@ -108,54 +129,58 @@ def test_agendas_api(app):
                 },
             },
             {
                 'text': 'Foo bar Meeting 2',
                 'id': 'foo-bar-meeting-2',
                 'slug': 'foo-bar-meeting-2',
                 'minimal_booking_delay': 1,
                 'maximal_booking_delay': 56,
+                'edit_role': None,
+                'view_role': None,
                 'kind': 'meetings',
                 'resources': [],
                 'api': {
                     'meetings_url': 'http://testserver/api/agenda/foo-bar-meeting-2/meetings/',
                     'desks_url': 'http://testserver/api/agenda/foo-bar-meeting-2/desks/',
                     'resources_url': 'http://testserver/api/agenda/foo-bar-meeting-2/resources/',
                     'fillslots_url': 'http://testserver/api/agenda/foo-bar-meeting-2/fillslots/',
                 },
             },
             {
                 'text': 'Virtual Agenda',
                 'id': 'virtual-agenda',
                 'slug': 'virtual-agenda',
                 'minimal_booking_delay': 1,
                 'maximal_booking_delay': 56,
+                'edit_role': 'Edit',
+                'view_role': 'View',
                 'kind': 'virtual',
                 'api': {
                     'meetings_url': 'http://testserver/api/agenda/virtual-agenda/meetings/',
                     'desks_url': 'http://testserver/api/agenda/virtual-agenda/desks/',
                     'fillslots_url': 'http://testserver/api/agenda/virtual-agenda/fillslots/',
                 },
             },
-        ]
+        ],
     }
 
     resp = app.get('/api/agenda/', params={'q': 'foo'})
     assert len(resp.json['data']) == 5
     resp = app.get('/api/agenda/', params={'q': 'MEET'})
     assert len(resp.json['data']) == 2
     resp = app.get('/api/agenda/', params={'q': ''})
     assert len(resp.json['data']) == 0
 
     with CaptureQueriesContext(connection) as ctx:
         resp = app.get('/api/agenda/')
-        assert len(ctx.captured_queries) == 4
+        assert len(ctx.captured_queries) == 8
     with CaptureQueriesContext(connection) as ctx:
         resp = app.get('/api/agenda/', params={'q': 'MEET'})
-        assert len(ctx.captured_queries) == 2
+        assert len(ctx.captured_queries) == 3
 
     resp = app.get('/api/agenda/', params={'with_open_events': '1'})
     assert len(resp.json['data']) == 0
 
     resp = app.get('/api/agenda/', params={'category': ''})
     assert len(resp.json['data']) == 6
     resp = app.get('/api/agenda/', params={'category': '__none__'})
     assert len(resp.json['data']) == 3
@@ -252,17 +277,17 @@ def test_agendas_api(app):
         TimePeriodException.objects.create(
             desk=event_agenda.desk_set.get(),
             start_datetime=now(),
             end_datetime=now() + datetime.timedelta(hours=1),
         )
 
     with CaptureQueriesContext(connection) as ctx:
         resp = app.get('/api/agenda/', params={'with_open_events': '1'})
-        assert len(ctx.captured_queries) == 8
+        assert len(ctx.captured_queries) == 9
 
 
 def test_agendas_meetingtypes_api(app, some_data, meetings_agenda):
     resp = app.get('/api/agenda/%s/meetings/' % meetings_agenda.slug)
     expected_resp = {
         'data': [
             {
                 'text': 'Blah',
@@ -470,16 +495,18 @@ def test_virtual_agenda_detail(app, virtual_meetings_agenda):
     resp = app.get('/api/agenda/%s/' % virtual_meetings_agenda.slug)
     assert resp.json == {
         'data': {
             'text': 'Virtual Agenda',
             'id': 'virtual-agenda',
             'slug': 'virtual-agenda',
             'minimal_booking_delay': None,
             'maximal_booking_delay': None,
+            'edit_role': None,
+            'view_role': None,
             'kind': 'virtual',
             'api': {
                 'meetings_url': 'http://testserver/api/agenda/%s/meetings/' % virtual_meetings_agenda.slug,
                 'desks_url': 'http://testserver/api/agenda/%s/desks/' % virtual_meetings_agenda.slug,
                 'fillslots_url': 'http://testserver/api/agenda/%s/fillslots/' % virtual_meetings_agenda.slug,
             },
         },
     }
-- 
2.30.2

