Projet

Général

Profil

0003-api-add-post-method-on-agenda-endpoint-57103.patch

Nicolas Roche, 28 septembre 2021 18:48

Télécharger (8,53 ko)

Voir les différences:

Subject: [PATCH 3/3] api: add post method on agenda endpoint (#57103)

 chrono/api/serializers.py |  34 ++++++++++++-
 chrono/api/views.py       |  25 +++++++++-
 tests/api/test_all.py     | 101 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 158 insertions(+), 2 deletions(-)
chrono/api/serializers.py
1
from django.contrib.auth.models import Group
1 2
from django.utils.translation import ugettext_lazy as _
2 3
from rest_framework import serializers
3 4
from rest_framework.exceptions import ValidationError
4 5

  
5
from chrono.agendas.models import AbsenceReason, Booking, Event
6
from chrono.agendas.models import AbsenceReason, Agenda, Booking, Event
6 7

  
7 8

  
8 9
class StringOrListField(serializers.ListField):
9 10
    def to_internal_value(self, data):
10 11
        if isinstance(data, str):
11 12
            data = [s.strip() for s in data.split(',') if s.strip()]
12 13
        return super().to_internal_value(data)
13 14

  
......
151 152
            'publication_date',
152 153
            'places',
153 154
            'waiting_list_places',
154 155
            'label',
155 156
            'description',
156 157
            'pricing',
157 158
            'url',
158 159
        ]
160

  
161

  
162
class AgendaSerializer(serializers.ModelSerializer):
163
    edit_role = serializers.CharField(required=False)
164
    view_role = serializers.CharField(required=False)
165

  
166
    class Meta:
167
        model = Agenda
168
        fields = [
169
            'slug',
170
            'label',
171
            'kind',
172
            'minimal_booking_delay',
173
            'minimal_booking_delay_in_working_days',
174
            'maximal_booking_delay',
175
            'anonymize_delay',
176
            'edit_role',
177
            'view_role',
178
        ]
179

  
180
    def get_role(self, value):
181
        try:
182
            return Group.objects.get(name=value)
183
        except Group.DoesNotExist:
184
            raise serializers.ValidationError(_('unknown role: %s' % value))
185

  
186
    def validate_edit_role(self, value):
187
        return self.get_role(value)
188

  
189
    def validate_view_role(self, value):
190
        return self.get_role(value)
chrono/api/views.py
684 684
        cancel_callback_url=translate_to_publik_url(payload.get('cancel_callback_url', '')),
685 685
        user_display_label=payload.get('user_display_label', ''),
686 686
        extra_data=extra_data,
687 687
        color=color,
688 688
    )
689 689

  
690 690

  
691 691
class Agendas(APIView):
692
    permission_classes = ()
692
    serializer_class = serializers.AgendaSerializer
693

  
694
    def get_permissions(self):
695

  
696
        if self.request.method == 'GET':
697
            permission_classes = []
698
        else:
699
            permission_classes = [
700
                permissions.IsAuthenticated,
701
            ]
702
        return [permission() for permission in permission_classes]
693 703

  
694 704
    def get(self, request, format=None):
695 705
        agendas_queryset = (
696 706
            Agenda.objects.all()
697 707
            .select_related('absence_reasons_group')
698 708
            .prefetch_related('resources', 'absence_reasons_group__absence_reasons')
699 709
            .order_by('label')
700 710
        )
......
722 732
                not e.full for e in agenda.get_open_events(prefetched_queryset=True)
723 733
            ):
724 734
                # exclude agendas without open events
725 735
                continue
726 736
            agendas.append(get_agenda_detail(request, agenda))
727 737

  
728 738
        return Response({'err': 0, 'data': agendas})
729 739

  
740
    def post(self, request, format=None):
741
        serializer = self.serializer_class(data=request.data)
742
        if not serializer.is_valid():
743
            raise APIError(
744
                _('invalid payload'),
745
                err_class='invalid payload',
746
                errors=serializer.errors,
747
                http_status=status.HTTP_400_BAD_REQUEST,
748
            )
749
        payload = serializer.validated_data
750
        agenda = Agenda.objects.create(**payload)
751
        return Response({'err': 0, 'data': [get_agenda_detail(request, agenda)]})
752

  
730 753

  
731 754
agendas = Agendas.as_view()
732 755

  
733 756

  
734 757
class AgendaDetail(APIView):
735 758
    """
736 759
    Retrieve an agenda instance.
737 760
    """
tests/api/test_all.py
1 1
import datetime
2 2

  
3 3
import pytest
4
from django.contrib.auth.models import Group
4 5
from django.db import connection
5 6
from django.test.utils import CaptureQueriesContext
6 7
from django.utils.timezone import localtime, now
7 8

  
8 9
from chrono.agendas.models import (
9 10
    AbsenceReason,
10 11
    AbsenceReasonGroup,
11 12
    Agenda,
......
590 591
                'id': 'meeting1',
591 592
                'duration': 30,
592 593
                'api': {
593 594
                    'datetimes_url': 'http://testserver/api/agenda/virtual-agenda/meetings/meeting1/datetimes/',
594 595
                },
595 596
            },
596 597
        ]
597 598
    }
599

  
600

  
601
@pytest.mark.freeze_time('2021-07-09')
602
def test_add_agenda(app, user, settings):
603
    api_url = '/api/agenda/'
604

  
605
    # no authentication
606
    resp = app.post(api_url, status=401)
607
    assert resp.json['detail'] == 'Authentication credentials were not provided.'
608

  
609
    # wrong password
610
    app.authorization = ('Basic', ('john.doe', 'wrong'))
611
    resp = app.post(api_url, status=401)
612
    assert resp.json['detail'] == 'Invalid username/password.'
613

  
614
    app.authorization = ('Basic', ('john.doe', 'password'))
615

  
616
    # missing fields
617
    resp = app.post(api_url, status=400)
618
    assert resp.json['err']
619
    assert resp.json['errors'] == {'label': ['This field is required.'], 'slug': ['This field is required.']}
620

  
621
    # slug already used
622
    meeting_agenda = Agenda(label='Foo bar Meeting', kind='meetings')
623
    meeting_agenda.save()
624
    params = {
625
        'label': 'foo',
626
        'slug': meeting_agenda.slug,
627
    }
628
    resp = app.post(api_url, params=params, status=400)
629
    assert resp.json['err']
630
    assert resp.json['errors'] == {'slug': ['agenda with this Identifier already exists.']}
631

  
632
    # unknown kind
633
    params = {
634
        'label': 'foo',
635
        'slug': 'foo',
636
        'kind': 'oups',
637
    }
638
    resp = app.post(api_url, params=params, status=400)
639
    assert resp.json['err']
640
    assert resp.json['errors'] == {'kind': ['"oups" is not a valid choice.']}
641

  
642
    # unknown group
643
    params = {
644
        'label': 'foo',
645
        'slug': 'foo',
646
        'edit_role': 'oups',
647
        'view_role': 'plop',
648
    }
649
    resp = app.post(api_url, params=params, status=400)
650
    assert resp.json['err']
651
    assert resp.json['errors'] == {
652
        'edit_role': ['unknown role: oups'],
653
        'view_role': ['unknown role: plop'],
654
    }
655

  
656
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
657
    edit_group = Group.objects.create(name='Edit')
658
    view_group = Group.objects.create(name='View')
659

  
660
    # add a meetings agenda
661
    params = {
662
        'label': 'foo Meetings',
663
        'slug': 'foo-meetings',
664
        'kind': 'meetings',
665
        'minimal_booking_delay': 1,
666
        'minimal_booking_delay_in_working_days': True,
667
        'maximal_booking_delay': 3,
668
        'anonymize_delay': 30,
669
        'edit_role': 'Edit',
670
        'view_role': 'View',
671
    }
672
    resp = app.post(api_url, params=params)
673
    assert not resp.json['err']
674
    assert len(resp.json['data']) == 1
675
    agenda = Agenda.objects.get(slug='foo-meetings')
676
    assert agenda.min_booking_datetime.date() == datetime.date(2021, 7, 12)
677
    assert agenda.edit_role == edit_group
678
    assert agenda.view_role == view_group
679

  
680
    # add an events agenda
681
    params = {
682
        'label': 'foo Events',
683
        'slug': 'foo-events',
684
        'kind': 'events',
685
        'minimal_booking_delay': 1,
686
        'minimal_booking_delay_in_working_days': True,
687
        'maximal_booking_delay': 3,
688
        'anonymize_delay': 30,
689
        'edit_role': 'Edit',
690
        'view_role': 'View',
691
    }
692
    resp = app.post(api_url, params=params)
693
    assert not resp.json['err']
694
    assert len(resp.json['data']) == 1
695
    agenda = Agenda.objects.get(slug='foo-events')
696
    assert agenda.edit_role == edit_group
697
    assert agenda.view_role == view_group
698
    assert agenda.min_booking_datetime.date() == datetime.date(2021, 7, 12)
598
-