0001-api-booking-user_name-and-first-last_name-53172.patch
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 |
- |