Projet

Général

Profil

0001-api-booking-user_name-and-first-last_name-53172.patch

Lauréline Guérin, 18 mai 2021 09:26

Télécharger (20,2 ko)

Voir les différences:

Subject: [PATCH 1/2] api: booking, user_name and first/last_name (#53172)

 .../migrations/0086_booking_user_name.py      | 21 +++++++
 chrono/agendas/models.py                      | 10 ++-
 chrono/api/views.py                           |  7 ++-
 chrono/manager/views.py                       |  4 +-
 tests/manager/test_all.py                     |  6 +-
 tests/manager/test_event.py                   | 30 ++++-----
 tests/test_agendas.py                         |  6 +-
 tests/test_api.py                             | 61 +++++++++++++------
 8 files changed, 103 insertions(+), 42 deletions(-)
 create mode 100644 chrono/agendas/migrations/0086_booking_user_name.py
chrono/agendas/migrations/0086_booking_user_name.py
1
from django.db import migrations, models
2

  
3

  
4
class Migration(migrations.Migration):
5

  
6
    dependencies = [
7
        ('agendas', '0085_reason_slug'),
8
    ]
9

  
10
    operations = [
11
        migrations.RenameField(
12
            model_name='booking',
13
            old_name='user_name',
14
            new_name='user_last_name',
15
        ),
16
        migrations.AddField(
17
            model_name='booking',
18
            name='user_first_name',
19
            field=models.CharField(blank=True, max_length=250),
20
        ),
21
    ]
chrono/agendas/models.py
1596 1596
        verbose_name=_('Label displayed to user'), max_length=250, blank=True
1597 1597
    )
1598 1598
    user_external_id = models.CharField(max_length=250, blank=True)
1599
    user_name = models.CharField(max_length=250, blank=True)
1599
    user_last_name = models.CharField(max_length=250, blank=True)
1600
    user_first_name = models.CharField(max_length=250, blank=True)
1600 1601
    user_email = models.EmailField(blank=True)
1601 1602
    user_phone_number = models.CharField(max_length=16, blank=True)
1602 1603
    user_was_present = models.NullBooleanField()
......
1607 1608
    cancel_callback_url = models.URLField(blank=True)
1608 1609
    color = models.ForeignKey(BookingColor, null=True, on_delete=models.SET_NULL, related_name='bookings')
1609 1610

  
1611
    @property
1612
    def user_name(self):
1613
        return ('%s %s' % (self.user_first_name, self.user_last_name)).strip()
1614

  
1610 1615
    def save(self, *args, **kwargs):
1611 1616
        with transaction.atomic():
1612 1617
            super(Booking, self).save(*args, **kwargs)
......
1643 1648
            label='',
1644 1649
            user_display_label='',
1645 1650
            user_external_id='',
1646
            user_name='',
1651
            user_last_name='',
1652
            user_first_name='',
1647 1653
            extra_data={},
1648 1654
            anonymization_datetime=now(),
1649 1655
        )
chrono/api/views.py
922 922

  
923 923
    label = serializers.CharField(max_length=250, allow_blank=True)
924 924
    user_external_id = serializers.CharField(max_length=250, allow_blank=True)
925
    user_name = serializers.CharField(max_length=250, allow_blank=True)
925
    user_name = serializers.CharField(max_length=250, allow_blank=True)  # compatibility
926
    user_first_name = serializers.CharField(max_length=250, allow_blank=True)
927
    user_last_name = serializers.CharField(max_length=250, allow_blank=True)
926 928
    user_display_label = serializers.CharField(max_length=250, allow_blank=True)
927 929
    user_email = serializers.CharField(max_length=250, allow_blank=True)
928 930
    user_phone_number = serializers.CharField(max_length=16, allow_blank=True)
......
1267 1269
                        in_waiting_list=in_waiting_list,
1268 1270
                        label=payload.get('label', ''),
1269 1271
                        user_external_id=payload.get('user_external_id', ''),
1270
                        user_name=payload.get('user_name', ''),
1272
                        user_first_name=payload.get('user_first_name', ''),
1273
                        user_last_name=payload.get('user_last_name') or payload.get('user_name') or '',
1271 1274
                        user_email=payload.get('user_email', ''),
1272 1275
                        user_phone_number=payload.get('user_phone_number', ''),
1273 1276
                        form_url=payload.get('form_url', ''),
chrono/manager/views.py
1960 1960
        event = self.object
1961 1961
        context['booked'] = event.booking_set.filter(
1962 1962
            cancellation_datetime__isnull=True, in_waiting_list=False
1963
        ).order_by('user_name')
1963
        ).order_by('user_last_name', 'user_first_name')
1964 1964
        context['booked_without_status'] = any(e.user_was_present is None for e in context['booked'])
1965 1965
        if context['booked_without_status']:
1966 1966
            context['absence_form'] = BookingAbsenceReasonForm(agenda=self.agenda)
1967 1967
        context['waiting'] = event.booking_set.filter(
1968 1968
            cancellation_datetime__isnull=True, in_waiting_list=True
1969
        ).order_by('user_name')
1969
        ).order_by('user_last_name', 'user_first_name')
1970 1970
        for booking in context['booked']:
1971 1971
            booking.form = BookingAbsenceReasonForm(
1972 1972
                agenda=self.agenda, initial={'reason': booking.user_absence_reason}
tests/manager/test_all.py
3233 3233
            booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 14, 0 + i))
3234 3234
        if i == 5:
3235 3235
            booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 15, 0))
3236
            booking.user_name = 'Foo Bar User'
3236
            booking.user_first_name = 'Foo Bar'
3237
            booking.user_last_name = 'User'
3237 3238
        if i == 6:
3238 3239
            booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 16, 0))
3239
            booking.user_name = 'Foo Bar User 2'
3240
            booking.user_first_name = 'Foo Bar'
3241
            booking.user_last_name = 'User 2'
3240 3242
            booking.label = 'Foo Bar Label 2'
3241 3243
        if i == 7:
3242 3244
            booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 17, 0))
tests/manager/test_event.py
1068 1068
        waiting_list_places=5,
1069 1069
        agenda=agenda,
1070 1070
    )
1071
    booking1 = Booking.objects.create(event=event, user_name='User 42')
1072
    Booking.objects.create(event=event, user_name='User 1')
1073
    Booking.objects.create(event=event, user_name='User 17')
1074
    Booking.objects.create(event=event, user_name='User 35')
1075
    Booking.objects.create(event=event, user_name='User 5')
1076
    booking6 = Booking.objects.create(event=event, user_name='User Cancelled')
1071
    booking1 = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
1072
    Booking.objects.create(event=event, user_first_name='User', user_last_name='01')
1073
    Booking.objects.create(event=event, user_first_name='User', user_last_name='17')
1074
    Booking.objects.create(event=event, user_first_name='User', user_last_name='35')
1075
    Booking.objects.create(event=event, user_first_name='User', user_last_name='05')
1076
    booking6 = Booking.objects.create(event=event, user_first_name='User', user_last_name='Cancelled')
1077 1077
    booking6.cancel()
1078
    booking7 = Booking.objects.create(event=event, user_name='User Waiting', in_waiting_list=True)
1078
    booking7 = Booking.objects.create(
1079
        event=event, user_first_name='User', user_last_name='Waiting', in_waiting_list=True
1080
    )
1079 1081
    login(app)
1080 1082

  
1081 1083
    # event not in past
......
1098 1100
    assert 'Waiting List (1/5)' in resp
1099 1101
    assert (
1100 1102
        resp.text.index('Bookings (5/10)')
1101
        < resp.text.index('User 1')
1103
        < resp.text.index('User 01')
1104
        < resp.text.index('User 05')
1102 1105
        < resp.text.index('User 17')
1103 1106
        < resp.text.index('User 35')
1104 1107
        < resp.text.index('User 42')
1105
        < resp.text.index('User 5')
1106 1108
        < resp.text.index('Waiting List (1/5)')
1107 1109
        < resp.text.index('User Waiting')
1108 1110
    )  # user ordering is not optimal ...
......
1174 1176
        waiting_list_places=5,
1175 1177
        agenda=agenda,
1176 1178
    )
1177
    booking = Booking.objects.create(event=event, user_name='User 42')
1179
    booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
1178 1180

  
1179 1181
    login(app)
1180 1182
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
......
1248 1250
        waiting_list_places=5,
1249 1251
        agenda=agenda,
1250 1252
    )
1251
    booking = Booking.objects.create(event=event, user_name='User 42')
1253
    booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
1252 1254

  
1253 1255
    login(app)
1254 1256
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
......
1288 1290
        waiting_list_places=5,
1289 1291
        agenda=agenda,
1290 1292
    )
1291
    booking1 = Booking.objects.create(event=event, user_name='User 42')
1293
    booking1 = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
1292 1294

  
1293 1295
    login(app)
1294 1296
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
......
1309 1311
    assert '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk) not in resp
1310 1312
    assert '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk) not in resp
1311 1313

  
1312
    booking2 = Booking.objects.create(event=event, user_name='User 35')
1314
    booking2 = Booking.objects.create(event=event, user_first_name='User', user_last_name='35')
1313 1315
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
1314 1316
    assert 'Mark all bookings without status' in resp
1315 1317
    assert '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk) in resp
......
1325 1327
    assert booking2.user_was_present is True
1326 1328
    assert booking2.user_absence_reason == ''
1327 1329

  
1328
    booking3 = Booking.objects.create(event=event, user_name='User 51')
1330
    booking3 = Booking.objects.create(event=event, user_first_name='User', user_last_name='51')
1329 1331
    app.post(
1330 1332
        '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
1331 1333
        params={'csrfmiddlewaretoken': token, 'reason': 'Foo reason'},
tests/test_agendas.py
1831 1831
            label='john',
1832 1832
            user_display_label='john',
1833 1833
            user_external_id='john',
1834
            user_name='john',
1834
            user_first_name='john',
1835
            user_last_name='doe',
1835 1836
            backoffice_url='https://example.org',
1836 1837
        )
1837 1838

  
......
1858 1859
            label='',
1859 1860
            user_display_label='',
1860 1861
            user_external_id='',
1861
            user_name='',
1862
            user_first_name='',
1863
            user_last_name='',
1862 1864
            backoffice_url='https://example.org',
1863 1865
            extra_data={},
1864 1866
            anonymization_datetime=now(),
tests/test_api.py
1259 1259
    )
1260 1260
    booking = Booking.objects.get(id=resp.json['booking_id'])
1261 1261
    assert booking.label == 'foo'
1262
    assert booking.user_name == 'bar'
1262
    assert booking.user_first_name == ''
1263
    assert booking.user_last_name == 'bar'
1264
    assert booking.backoffice_url == 'http://example.net/'
1265
    assert booking.cancel_callback_url == 'http://example.net/jump/trigger/'
1266
    assert booking.user_email == 'bar@bar.com'
1267
    assert booking.user_phone_number == '+33123456789'
1268
    assert booking.form_url == 'http://example.net/'
1269

  
1270
    resp = app.post_json(
1271
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
1272
        params={
1273
            'label': 'foo',
1274
            'user_first_name': 'foo',
1275
            'user_last_name': 'bar',
1276
            'backoffice_url': 'http://example.net/',
1277
            'cancel_callback_url': 'http://example.net/jump/trigger/',
1278
            'user_email': 'bar@bar.com',
1279
            'user_phone_number': '+33123456789',
1280
            'form_url': 'http://example.net/',
1281
        },
1282
    )
1283
    booking = Booking.objects.get(id=resp.json['booking_id'])
1284
    assert booking.label == 'foo'
1285
    assert booking.user_first_name == 'foo'
1286
    assert booking.user_last_name == 'bar'
1263 1287
    assert booking.backoffice_url == 'http://example.net/'
1264 1288
    assert booking.cancel_callback_url == 'http://example.net/jump/trigger/'
1265 1289
    assert booking.user_email == 'bar@bar.com'
......
1269 1293
    # blank data are OK
1270 1294
    resp = app.post_json(
1271 1295
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
1272
        params={'label': '', 'user_name': '', 'backoffice_url': ''},
1296
        params={'label': '', 'user_first_name': '', 'user_last_name': '', 'backoffice_url': ''},
1273 1297
    )
1274 1298
    assert Booking.objects.get(id=resp.json['booking_id']).label == ''
1275
    assert Booking.objects.get(id=resp.json['booking_id']).user_name == ''
1299
    assert Booking.objects.get(id=resp.json['booking_id']).user_first_name == ''
1300
    assert Booking.objects.get(id=resp.json['booking_id']).user_last_name == ''
1276 1301
    assert Booking.objects.get(id=resp.json['booking_id']).backoffice_url == ''
1277 1302

  
1278 1303
    # extra data stored in extra_data field
1279 1304
    resp = app.post_json(
1280 1305
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
1281
        params={'label': 'l', 'user_name': 'u', 'backoffice_url': '', 'foo': 'bar'},
1306
        params={'label': 'l', 'user_last_name': 'u', 'backoffice_url': '', 'foo': 'bar'},
1282 1307
    )
1283 1308
    assert Booking.objects.get(id=resp.json['booking_id']).label == 'l'
1284
    assert Booking.objects.get(id=resp.json['booking_id']).user_name == 'u'
1309
    assert Booking.objects.get(id=resp.json['booking_id']).user_last_name == 'u'
1285 1310
    assert Booking.objects.get(id=resp.json['booking_id']).backoffice_url == ''
1286 1311
    assert Booking.objects.get(id=resp.json['booking_id']).extra_data == {'foo': 'bar'}
1287 1312

  
......
1293 1318
    # test invalid data are refused
1294 1319
    resp = app.post_json(
1295 1320
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
1296
        params={'user_name': {'foo': 'bar'}},
1321
        params={'user_last_name': {'foo': 'bar'}},
1297 1322
        status=400,
1298 1323
    )
1299 1324
    assert resp.json['err'] == 1
......
1301 1326
    assert resp.json['err_class'] == 'invalid payload'
1302 1327
    assert resp.json['err_desc'] == 'invalid payload'
1303 1328
    assert len(resp.json['errors']) == 1
1304
    assert 'user_name' in resp.json['errors']
1329
    assert 'user_last_name' in resp.json['errors']
1305 1330

  
1306 1331
    resp = app.post('/api/agenda/foobar/fillslot/%s/' % event.id, status=404)
1307 1332

  
......
1447 1472
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
1448 1473
        params={
1449 1474
            'label': 'foo',
1450
            'user_name': 'bar',
1475
            'user_first_name': 'foo',
1476
            'user_last_name': 'bar',
1451 1477
            'backoffice_url': 'http://example.net/',
1452 1478
            'url': 'http://example.com/booking',
1453 1479
            'user_display_label': 'your booking',
......
1456 1482
    assert Booking.objects.count() == 3
1457 1483
    booking_ics = Booking.objects.get(id=resp.json['booking_id']).get_ics()
1458 1484
    assert 'SUMMARY:your booking\r\n' in booking_ics
1459
    assert 'ATTENDEE:bar\r\n' in booking_ics
1485
    assert 'ATTENDEE:foo bar\r\n' in booking_ics
1460 1486
    assert 'URL:http://example.com/booking\r\n' in booking_ics
1461 1487

  
1462 1488
    # extra data stored in extra_data field
......
1464 1490
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
1465 1491
        params={
1466 1492
            'label': 'l',
1467
            'user_name': 'u',
1468 1493
            'backoffice_url': '',
1469 1494
            'location': 'bar',
1470 1495
            'comment': 'booking comment',
......
1570 1595
            'slots': events_ids,
1571 1596
            'label': 'foo',
1572 1597
            'user_external_id': 'some_external_id',
1573
            'user_name': 'bar',
1598
            'user_last_name': 'bar',
1574 1599
            'user_display_label': 'foo',
1575 1600
            'backoffice_url': 'http://example.net/',
1576 1601
        },
......
1579 1604
    booking = Booking.objects.get(pk=booking_id)
1580 1605
    assert booking.label == 'foo'
1581 1606
    assert booking.user_external_id == 'some_external_id'
1582
    assert booking.user_name == 'bar'
1607
    assert booking.user_last_name == 'bar'
1583 1608
    assert booking.user_display_label == 'foo'
1584 1609
    assert booking.backoffice_url == 'http://example.net/'
1585 1610
    assert Booking.objects.filter(primary_booking=booking_id, label='foo').count() == 2
......
1595 1620
    # extra data stored in extra_data field
1596 1621
    resp = app.post_json(
1597 1622
        '/api/agenda/%s/fillslots/' % agenda.id,
1598
        params={'slots': events_ids, 'label': 'l', 'user_name': 'u', 'backoffice_url': '', 'foo': 'bar'},
1623
        params={'slots': events_ids, 'label': 'l', 'user_last_name': 'u', 'backoffice_url': '', 'foo': 'bar'},
1599 1624
    )
1600 1625
    assert Booking.objects.get(id=resp.json['booking_id']).label == 'l'
1601
    assert Booking.objects.get(id=resp.json['booking_id']).user_name == 'u'
1626
    assert Booking.objects.get(id=resp.json['booking_id']).user_last_name == 'u'
1602 1627
    assert Booking.objects.get(id=resp.json['booking_id']).backoffice_url == ''
1603 1628
    assert Booking.objects.get(id=resp.json['booking_id']).extra_data == {'foo': 'bar'}
1604 1629
    for booking in Booking.objects.filter(primary_booking=resp.json['booking_id']):
......
1607 1632
    # test invalid data are refused
1608 1633
    resp = app.post_json(
1609 1634
        '/api/agenda/%s/fillslots/' % agenda.id,
1610
        params={'slots': events_ids, 'user_name': {'foo': 'bar'}},
1635
        params={'slots': events_ids, 'user_last_name': {'foo': 'bar'}},
1611 1636
        status=400,
1612 1637
    )
1613 1638
    assert resp.json['err'] == 1
......
1615 1640
    assert resp.json['err_class'] == 'invalid payload'
1616 1641
    assert resp.json['err_desc'] == 'invalid payload'
1617 1642
    assert len(resp.json['errors']) == 1
1618
    assert 'user_name' in resp.json['errors']
1643
    assert 'user_last_name' in resp.json['errors']
1619 1644

  
1620 1645
    # empty or missing slots
1621 1646
    resp = app.post_json('/api/agenda/%s/fillslots/' % agenda.id, params={'slots': []}, status=400)
......
1644 1669
        in_bookable_period.return_value = True
1645 1670
        resp = app.post_json(
1646 1671
            '/api/agenda/%s/fillslots/' % agenda.id,
1647
            params={'slots': events_ids, 'label': 'l', 'user_name': 'u', 'backoffice_url': '', 'foo': 'bar'},
1672
            params={'slots': events_ids},
1648 1673
        )
1649 1674
        assert resp.json['err'] == 0
1650 1675
        in_bookable_period.return_value = False
1651 1676
        resp = app.post_json(
1652 1677
            '/api/agenda/%s/fillslots/' % agenda.id,
1653
            params={'slots': events_ids, 'label': 'l', 'user_name': 'u', 'backoffice_url': '', 'foo': 'bar'},
1678
            params={'slots': events_ids},
1654 1679
        )
1655 1680
        assert resp.json['err'] == 1
1656 1681
        assert resp.json['reason'] == 'event not bookable'  # legacy
1657
-