api: add booking ics view (#22930)
This commit is contained in:
parent
e1536441af
commit
0ce55339a7
|
@ -376,6 +376,27 @@ class Booking(models.Model):
|
|||
self.secondary_booking_set.update(in_waiting_list=False)
|
||||
self.save()
|
||||
|
||||
def get_ics(self, request=None):
|
||||
ics = vobject.iCalendar()
|
||||
ics.add('prodid').value = '-//Entr\'ouvert//NON SGML Publik'
|
||||
vevent = vobject.newFromBehavior('vevent')
|
||||
vevent.add('uid').value = '%s-%s-%s' % (self.event.start_datetime.isoformat(), self.event.agenda.pk, self.pk)
|
||||
|
||||
vevent.add('summary').value = self.label
|
||||
vevent.add('dtstart').value = self.event.start_datetime
|
||||
if self.user_name:
|
||||
vevent.add('attendee').value = self.user_name
|
||||
if self.event.meeting_type:
|
||||
vevent.add('dtend').value = self.event.start_datetime + datetime.timedelta(minutes=self.event.meeting_type.duration)
|
||||
|
||||
for field in ('description', 'location', 'comment', 'url'):
|
||||
field_value = request and request.GET.get(field) or self.extra_data.get(field)
|
||||
if field_value:
|
||||
vevent.add(field).value = field_value
|
||||
ics.add(vevent)
|
||||
return ics.serialize()
|
||||
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Desk(models.Model):
|
||||
|
|
|
@ -44,4 +44,6 @@ urlpatterns = [
|
|||
name='api-cancel-booking'),
|
||||
url(r'booking/(?P<booking_pk>\w+)/accept/$', views.accept_booking,
|
||||
name='api-accept-booking'),
|
||||
url(r'booking/(?P<booking_pk>\w+)/ics/$', views.booking_ics,
|
||||
name='api-booking-ics'),
|
||||
]
|
||||
|
|
|
@ -18,7 +18,7 @@ from collections import defaultdict
|
|||
import datetime
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import Http404
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.dateparse import parse_date
|
||||
from django.utils.encoding import force_text
|
||||
|
@ -456,7 +456,9 @@ class Fillslots(APIView):
|
|||
'datetime': localtime(events[0].start_datetime),
|
||||
'api': {
|
||||
'cancel_url': request.build_absolute_uri(
|
||||
reverse('api-cancel-booking', kwargs={'booking_pk': primary_booking.id}))
|
||||
reverse('api-cancel-booking', kwargs={'booking_pk': primary_booking.id})),
|
||||
'ics_url': request.build_absolute_uri(
|
||||
reverse('api-booking-ics', kwargs={'booking_pk': primary_booking.id})),
|
||||
}
|
||||
}
|
||||
if in_waiting_list:
|
||||
|
@ -566,3 +568,14 @@ class SlotStatus(APIView):
|
|||
return Response(response)
|
||||
|
||||
slot_status = SlotStatus.as_view()
|
||||
|
||||
|
||||
class BookingICS(APIView):
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def get(self, request, booking_pk=None, format=None):
|
||||
booking = get_object_or_404(Booking, id=booking_pk)
|
||||
response = HttpResponse(booking.get_ics(request), content_type='text/calendar')
|
||||
return response
|
||||
|
||||
booking_ics = BookingICS.as_view()
|
||||
|
|
|
@ -329,7 +329,9 @@ def test_booking_api(app, some_data, user):
|
|||
assert resp.json['datetime'] == localtime(event.start_datetime).isoformat()
|
||||
assert 'accept_url' not in resp.json['api']
|
||||
assert 'cancel_url' in resp.json['api']
|
||||
assert 'ics_url' in resp.json['api']
|
||||
assert urlparse.urlparse(resp.json['api']['cancel_url']).netloc
|
||||
assert urlparse.urlparse(resp.json['api']['ics_url']).netloc
|
||||
assert Booking.objects.count() == 1
|
||||
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id))
|
||||
|
@ -370,6 +372,76 @@ def test_booking_api(app, some_data, user):
|
|||
|
||||
resp = app.post('/api/agenda/233/fillslot/%s/' % event.id, status=404)
|
||||
|
||||
def test_booking_ics(app, some_data, meetings_agenda, user):
|
||||
agenda = Agenda.objects.filter(label=u'Foo bar')[0]
|
||||
event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.id))
|
||||
|
||||
assert Booking.objects.count() == 1
|
||||
assert 'ics_url' in resp.json['api']
|
||||
assert urlparse.urlparse(resp.json['api']['cancel_url']).netloc
|
||||
assert urlparse.urlparse(resp.json['api']['ics_url']).netloc
|
||||
|
||||
formatted_start_date = event.start_datetime.strftime('%Y%m%dT%H%M%S')
|
||||
booking_ics = Booking.objects.get(id=resp.json['booking_id']).get_ics()
|
||||
assert 'UID:%s-%s-%s\r\n' % (event.start_datetime.isoformat(), agenda.pk, resp.json['booking_id']) in booking_ics
|
||||
assert 'SUMMARY:\r\n' in booking_ics
|
||||
assert 'DTSTART:%sZ\r\n' % formatted_start_date in booking_ics
|
||||
assert 'DTEDND:' not in booking_ics
|
||||
|
||||
# test with additional data
|
||||
resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
|
||||
params={'label': 'foo', 'user_name': 'bar', 'backoffice_url': 'http://example.net/',
|
||||
'url': 'http://example.com/booking'})
|
||||
assert Booking.objects.count() == 2
|
||||
booking_ics = Booking.objects.get(id=resp.json['booking_id']).get_ics()
|
||||
assert 'SUMMARY:foo\r\n' in booking_ics
|
||||
assert 'ATTENDEE:bar\r\n' in booking_ics
|
||||
assert 'URL:http://example.com/booking\r\n' in booking_ics
|
||||
|
||||
# extra data stored in extra_data field
|
||||
resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
|
||||
params={'label': 'l', 'user_name': 'u', 'backoffice_url': '', 'location': 'bar',
|
||||
'comment': 'booking comment', 'description': 'booking description'})
|
||||
assert Booking.objects.count() == 3
|
||||
booking_id = resp.json['booking_id']
|
||||
booking = Booking.objects.get(id=booking_id)
|
||||
booking_ics = booking.get_ics()
|
||||
assert 'COMMENT:booking comment\r\n' in booking_ics
|
||||
assert 'LOCATION:bar\r\n' in booking_ics
|
||||
assert 'DESCRIPTION:booking description\r\n' in booking_ics
|
||||
|
||||
# unauthenticated
|
||||
app.authorization = None
|
||||
app.get('/api/booking/%s/ics/' % resp.json['booking_id'], status=403)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.get('/api/booking/%s/ics/' % resp.json['booking_id'])
|
||||
assert resp.headers['Content-Type'] == 'text/calendar'
|
||||
|
||||
params = {'description': 'custom booking description', 'location': 'custom booking location',
|
||||
'comment': 'custom comment', 'url': 'http://example.com/custom'}
|
||||
resp = app.get('/api/booking/%s/ics/' % booking_id, params=params)
|
||||
assert 'DESCRIPTION:custom booking description\r\n' in resp.text
|
||||
assert 'LOCATION:custom booking location\r\n' in resp.text
|
||||
assert 'COMMENT:custom comment\r\n' in resp.text
|
||||
assert 'URL:http://example.com/custom\r\n' in resp.text
|
||||
|
||||
meetings_agenda_id = Agenda.objects.filter(label=u'Foo bar Meeting')[0].id
|
||||
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
|
||||
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
|
||||
event = resp.json['data'][2]
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/' % (meetings_agenda_id, event['id']))
|
||||
assert Booking.objects.count() == 4
|
||||
assert 'ics_url' in resp.json['api']
|
||||
booking = Booking.objects.get(id=resp.json['booking_id'])
|
||||
booking_ics = booking.get_ics()
|
||||
start = booking.event.start_datetime.strftime('%Y%m%dT%H%M%S')
|
||||
end = (booking.event.start_datetime + datetime.timedelta(minutes=booking.event.meeting_type.duration)).strftime('%Y%m%dT%H%M%S')
|
||||
assert "DTSTART:%sZ\r\n" % start in booking_ics
|
||||
assert "DTEND:%sZ\r\n" % end in booking_ics
|
||||
|
||||
def test_booking_api_fillslots(app, some_data, user):
|
||||
agenda = Agenda.objects.filter(label=u'Foo bar')[0]
|
||||
events_ids = [x.id for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()]
|
||||
|
@ -779,8 +851,10 @@ def test_waiting_list_booking(app, some_data, user):
|
|||
assert resp.json['in_waiting_list'] is True
|
||||
assert 'accept_url' in resp.json['api']
|
||||
assert 'cancel_url' in resp.json['api']
|
||||
assert 'ics_url' in resp.json['api']
|
||||
assert urlparse.urlparse(resp.json['api']['accept_url']).netloc
|
||||
assert urlparse.urlparse(resp.json['api']['cancel_url']).netloc
|
||||
assert urlparse.urlparse(resp.json['api']['ics_url']).netloc
|
||||
|
||||
# cancel a booking that was not on the waiting list
|
||||
booking = Booking.objects.filter(event=event, in_waiting_list=False)[0]
|
||||
|
@ -933,6 +1007,7 @@ def test_multiple_booking_api_fillslots(app, some_data, user):
|
|||
assert resp.json['datetime'] == localtime(events[0].start_datetime).isoformat()
|
||||
assert 'accept_url' not in resp.json['api']
|
||||
assert 'cancel_url' in resp.json['api']
|
||||
assert 'ics_url' in resp.json['api']
|
||||
for event in events:
|
||||
assert Event.objects.get(id=event.id).booked_places == 3
|
||||
|
||||
|
|
Loading…
Reference in New Issue