Projet

Général

Profil

0001-manager-user_block-used-also-in-event-detail-page-63.patch

Lauréline Guérin, 24 mai 2022 15:14

Télécharger (19,8 ko)

Voir les différences:

Subject: [PATCH 1/2] manager: user_block used also in event detail page
 (#63915)

 .../0086_booking_user_block_template.py       |  1 -
 chrono/agendas/models.py                      | 10 +--
 chrono/manager/forms.py                       | 20 ++++--
 .../chrono/manager_event_detail_fragment.html |  4 +-
 .../manager_events_agenda_settings.html       | 27 ++++++--
 chrono/manager/urls.py                        |  5 ++
 chrono/manager/views.py                       | 15 ++++
 tests/manager/test_all.py                     | 68 +++++++++++--------
 tests/manager/test_event.py                   | 47 ++++++++++---
 9 files changed, 141 insertions(+), 56 deletions(-)
chrono/agendas/migrations/0086_booking_user_block_template.py
15 15
            name='booking_user_block_template',
16 16
            field=models.TextField(
17 17
                blank=True,
18
                help_text='Displayed for each booking in event check page',
19 18
                verbose_name='User block template',
20 19
                validators=[chrono.agendas.models.django_template_validator],
21 20
            ),
chrono/agendas/models.py
45 45
from django.utils.encoding import force_text
46 46
from django.utils.formats import date_format
47 47
from django.utils.functional import cached_property
48
from django.utils.html import escape
48 49
from django.utils.module_loading import import_string
49 50
from django.utils.safestring import mark_safe
50 51
from django.utils.text import slugify
......
226 227
    )
227 228
    booking_user_block_template = models.TextField(
228 229
        _('User block template'),
229
        help_text=_('Displayed for each booking in event check page'),
230 230
        blank=True,
231 231
        validators=[django_template_validator],
232 232
    )
......
2030 2030
            self.event.set_is_checked()
2031 2031

  
2032 2032
    def get_user_block(self):
2033
        template_vars = Context(settings.TEMPLATE_VARS)
2033
        template_vars = Context(settings.TEMPLATE_VARS, autoescape=False)
2034 2034
        template_vars.update(
2035 2035
            {
2036 2036
                'booking': self,
2037 2037
            }
2038 2038
        )
2039 2039
        try:
2040
            return Template(self.event.agenda.get_booking_user_block_template()).render(template_vars)
2040
            return escape(Template(self.event.agenda.get_booking_user_block_template()).render(template_vars))
2041 2041
        except (VariableDoesNotExist, TemplateSyntaxError):
2042 2042
            return
2043 2043

  
......
3181 3181
        return _('Subscription')
3182 3182

  
3183 3183
    def get_user_block(self):
3184
        template_vars = Context(settings.TEMPLATE_VARS)
3184
        template_vars = Context(settings.TEMPLATE_VARS, autoescape=False)
3185 3185
        template_vars.update(
3186 3186
            {
3187 3187
                'booking': self,
3188 3188
            }
3189 3189
        )
3190 3190
        try:
3191
            return Template(self.agenda.get_booking_user_block_template()).render(template_vars)
3191
            return escape(Template(self.agenda.get_booking_user_block_template()).render(template_vars))
3192 3192
        except (VariableDoesNotExist, TemplateSyntaxError):
3193 3193
            return
3194 3194

  
chrono/manager/forms.py
133 133
            'anonymize_delay',
134 134
            'default_view',
135 135
            'booking_form_url',
136
            'event_display_template',
137 136
            'events_type',
138 137
        ]
139 138

  
......
141 140
        super().__init__(*args, **kwargs)
142 141
        if kwargs['instance'].kind != 'events':
143 142
            del self.fields['booking_form_url']
144
            del self.fields['event_display_template']
145 143
            del self.fields['events_type']
146 144
            self.fields['default_view'].choices = [
147 145
                (k, v) for k, v in self.fields['default_view'].choices if k != 'open_events'
......
1305 1303
        fields = []
1306 1304

  
1307 1305

  
1306
class AgendaDisplaySettingsForm(forms.ModelForm):
1307
    class Meta:
1308
        model = Agenda
1309
        fields = [
1310
            'event_display_template',
1311
            'booking_user_block_template',
1312
        ]
1313
        widgets = {'booking_user_block_template': forms.Textarea(attrs={'rows': 3})}
1314

  
1315
    def __init__(self, *args, **kwargs):
1316
        super().__init__(*args, **kwargs)
1317
        self.fields['booking_user_block_template'].help_text = (
1318
            _('Displayed for each booking in event page and check page'),
1319
        )
1320

  
1321

  
1308 1322
class AgendaBookingCheckSettingsForm(forms.ModelForm):
1309 1323
    class Meta:
1310 1324
        model = Agenda
1311 1325
        fields = [
1312 1326
            'check_type_group',
1313 1327
            'booking_check_filters',
1314
            'booking_user_block_template',
1315 1328
            'mark_event_checked_auto',
1316 1329
            'disable_check_update',
1317 1330
        ]
1318
        widgets = {'booking_user_block_template': forms.Textarea(attrs={'rows': 3})}
1319 1331

  
1320 1332
    def __init__(self, *args, **kwargs):
1321 1333
        super().__init__(*args, **kwargs)
chrono/manager/templates/chrono/manager_event_detail_fragment.html
29 29
  <ul class="objects-list single-links">
30 30
    {% for booking in booked %}
31 31
    <li>
32
    <a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{{ booking.events_display }}</a>
32
    <a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{{ booking.get_user_block }}, {{ booking.creation_datetime|date:"DATETIME_FORMAT" }}</a>
33 33
    {% if not booking.primary_booking %}
34 34
    <a rel="popup" class="delete" href="{% url 'chrono-manager-booking-cancel' pk=agenda.id booking_pk=booking.id %}?next={{ request.path }}">{% trans "Cancel" %}</a>
35 35
    {% else %}
......
53 53
<div>
54 54
  <ul class="objects-list single-links">
55 55
    {% for booking in waiting %}
56
    <li><a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{{ booking.events_display }}</a></li>
56
    <li><a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{{ booking.get_user_block }}, {{ booking.creation_datetime|date:"DATETIME_FORMAT" }}</a></li>
57 57
    {% endfor %}
58 58
  </ul>
59 59
</div>
chrono/manager/templates/chrono/manager_events_agenda_settings.html
33 33
</div>
34 34
</div>
35 35

  
36
<div class="section">
37
<h3>{% trans "Display options" %}
38
    <a rel="popup" class="button" href="{% url 'chrono-manager-agenda-display-settings' pk=object.pk %}">{% trans 'Configure' %}</a>
39
</h3>
40
<div>
41
    <ul>
42
        <li>
43
            {% if agenda.event_display_template %}
44
                {% trans "Event display template:" %}
45
                <pre>{{ agenda.event_display_template }}</pre>
46
            {% else %}
47
            {% trans "No event display template configured for this agenda." %}
48
            {% endif %}
49
        </li>
50
        <li>
51
            {% trans "Booking display template:" %}
52
            <pre>{{ agenda.get_booking_user_block_template }}</pre>
53
        </li>
54
    </ul>
55
</div>
56
</div>
57

  
36 58
<div class="section">
37 59
<h3>{% trans "Booking check options" %}
38 60
    <a rel="popup" class="button" href="{% url 'chrono-manager-agenda-booking-check-settings' pk=object.pk %}">{% trans 'Configure' %}</a>
......
82 104
        {% endif %}
83 105
    {% endwith %}
84 106

  
85
        <li>
86
            {% trans "User block template:" %}
87
            <pre>{{ agenda.get_booking_user_block_template }}</pre>
88
        </li>
89

  
90 107
        <li>{% trans "Automatically mark event as checked when all bookings have been checked:" %} {{ agenda.mark_event_checked_auto|yesno }}</li>
91 108
        <li>{% trans "Prevent the check of bookings when event was marked as checked:" %} {{ agenda.disable_check_update|yesno }}</li>
92 109
    </ul>
chrono/manager/urls.py
166 166
        name='chrono-manager-agenda-booking-delays',
167 167
    ),
168 168
    url(r'^agendas/(?P<pk>\d+)/roles$', views.agenda_roles, name='chrono-manager-agenda-roles'),
169
    url(
170
        r'^agendas/(?P<pk>\d+)/display-options$',
171
        views.agenda_display_settings,
172
        name='chrono-manager-agenda-display-settings',
173
    ),
169 174
    url(
170 175
        r'^agendas/(?P<pk>\d+)/check-options$',
171 176
        views.agenda_booking_check_settings,
chrono/manager/views.py
94 94
    AgendaAddForm,
95 95
    AgendaBookingCheckSettingsForm,
96 96
    AgendaBookingDelaysForm,
97
    AgendaDisplaySettingsForm,
97 98
    AgendaDuplicateForm,
98 99
    AgendaEditForm,
99 100
    AgendaNotificationsForm,
......
1241 1242
agenda_roles = AgendaRolesView.as_view()
1242 1243

  
1243 1244

  
1245
class AgendaDisplaySettingsView(AgendaEditView):
1246
    form_class = AgendaDisplaySettingsForm
1247
    title = _("Configure display options")
1248

  
1249
    def set_agenda(self, **kwargs):
1250
        self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events')
1251

  
1252
    def get_initial(self):
1253
        return {'booking_user_block_template': self.agenda.get_booking_user_block_template()}
1254

  
1255

  
1256
agenda_display_settings = AgendaDisplaySettingsView.as_view()
1257

  
1258

  
1244 1259
class AgendaBookingCheckSettingsView(AgendaEditView):
1245 1260
    form_class = AgendaBookingCheckSettingsForm
1246 1261
    title = _("Configure booking check options")
tests/manager/test_all.py
387 387
    assert resp.context['form'].initial['default_view'] == 'month'
388 388
    assert 'open_events' in [k for k, v in resp.context['form'].fields['default_view'].choices]
389 389
    assert 'booking_form_url' in resp.context['form'].fields
390
    assert 'event_display_template' in resp.context['form'].fields
391 390
    resp = resp.form.submit()
392 391
    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda_events.pk)
393 392
    resp = resp.follow()
......
401 400
    assert 'default_view' in resp.context['form'].fields
402 401
    assert 'open_events' not in [k for k, v in resp.context['form'].fields['default_view'].choices]
403 402
    assert 'booking_form_url' not in resp.context['form'].fields
404
    assert 'event_display_template' not in resp.context['form'].fields
405 403

  
406 404
    resp.form['default_view'] = 'month'
407 405
    resp.form.submit()
......
416 414
    assert 'default_view' in resp.context['form'].fields
417 415
    assert 'open_events' not in [k for k, v in resp.context['form'].fields['default_view'].choices]
418 416
    assert 'booking_form_url' not in resp.context['form'].fields
419
    assert 'event_display_template' not in resp.context['form'].fields
420 417

  
421 418

  
422 419
def test_options_events_agenda_events_type(app, admin_user):
......
529 526
    assert agenda.maximal_booking_delay is None
530 527

  
531 528

  
532
def test_options_agenda_booking_check_options(app, admin_user):
529
def test_options_agenda_booking_display_options(app, admin_user):
533 530
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
534 531

  
532
    app = login(app)
533

  
535 534
    # check user template
536 535
    assert agenda.booking_user_block_template == ''
537 536
    assert (
......
539 538
        == '{{ booking.user_name|default:booking.label|default:"Anonymous" }}'
540 539
    )
541 540

  
542
    app = login(app)
543
    url = '/manage/agendas/%s/check-options' % agenda.pk
541
    url = '/manage/agendas/%s/display-options' % agenda.pk
544 542
    resp = app.get(url)
545 543
    resp.form['booking_user_block_template'] = '{{ booking.user_name }} Foo Bar'
546 544
    resp = resp.form.submit()
......
558 556
        == '{{ booking.user_name|default:booking.label|default:"Anonymous" }}'
559 557
    )
560 558

  
559
    resp = app.get(url)
560
    valid_template = '{{ event.label|default:event.slug }} - {{ event.remaining_places|add:"5" }} / {{ event.start_datetime|date }} - {{ event.agenda.name }}'
561
    resp.form['event_display_template'] = valid_template
562
    resp = resp.form.submit().follow()
563

  
564
    agenda.refresh_from_db()
565
    assert agenda.event_display_template == valid_template
566

  
567
    invalid_templates = [
568
        '{{ syntax error }}',
569
        '{{ event.label|invalidfilter }}',
570
        '{{ event.label|default:notexist }}',
571
    ]
572
    for template in invalid_templates:
573
        resp = app.get(url)
574
        resp.form['event_display_template'] = template
575
        resp = resp.form.submit()
576
        assert 'syntax error' in resp.text
577

  
578
    # check kind
579
    agenda.kind = 'meetings'
580
    agenda.save()
581
    app.get(url, status=404)
582
    agenda.kind = 'virtual'
583
    agenda.save()
584
    app.get(url, status=404)
585

  
586

  
587
def test_options_agenda_booking_check_options(app, admin_user):
588
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
589

  
590
    app = login(app)
591

  
561 592
    # check filters
562 593
    assert agenda.booking_check_filters == ''
563 594
    assert agenda.get_booking_check_filters() == []
564 595

  
596
    url = '/manage/agendas/%s/check-options' % agenda.pk
565 597
    resp = app.get(url)
566 598
    resp.form['booking_check_filters'] = 'foo,bar,baz'
567 599
    resp = resp.form.submit()
......
594 626
    app.get(url, status=404)
595 627

  
596 628

  
597
def test_options_agenda_event_display_template(app, admin_user):
598
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
599
    Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
600
    app = login(app)
601
    resp = app.get('/manage/agendas/%s/edit' % agenda.pk)
602
    valid_template = '{{ event.label|default:event.slug }} - {{ event.remaining_places|add:"5" }} / {{ event.start_datetime|date }} - {{ event.agenda.name }}'
603
    resp.form['event_display_template'] = valid_template
604
    resp = resp.form.submit().follow()
605

  
606
    agenda.refresh_from_db()
607
    assert agenda.event_display_template == valid_template
608

  
609
    invalid_templates = [
610
        '{{ syntax error }}',
611
        '{{ event.label|invalidfilter }}',
612
        '{{ event.label|default:notexist }}',
613
    ]
614
    for template in invalid_templates:
615
        resp = app.get('/manage/agendas/%s/edit' % agenda.pk)
616
        resp.form['event_display_template'] = template
617
        resp = resp.form.submit()
618
        assert 'syntax error' in resp.text
619

  
620

  
621 629
def test_options_agenda_as_manager(app, manager_user):
622 630
    agenda = Agenda(label='Foo bar')
623 631
    agenda.view_role = manager_user.groups.all()[0]
tests/manager/test_event.py
1112 1112
    app.get('/manage/agendas/%s/import-events' % agenda.id, status=404)
1113 1113

  
1114 1114

  
1115
@pytest.mark.freeze_time('2022-05-24')
1116
def test_event_detail(app, admin_user):
1117
    agenda = Agenda.objects.create(label='Events', kind='events')
1118
    event = Event.objects.create(
1119
        label='xyz',
1120
        start_datetime=now() + datetime.timedelta(days=1),
1121
        places=10,
1122
        waiting_list_places=2,
1123
        agenda=agenda,
1124
    )
1125
    Booking.objects.create(event=event, user_last_name="User's 1")
1126
    Booking.objects.create(event=event, user_last_name='User 2', in_waiting_list=True)
1127

  
1128
    login(app)
1129
    resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
1130
    assert 'Bookings (1/10)' in resp.text
1131
    assert 'User&#39;s 1, May 24, 2022, 2 a.m.' in resp.text
1132
    assert 'Waiting List (1/2): 1 remaining place' in resp.text
1133
    assert 'User 2, May 24, 2022, 2 a.m.' in resp.text
1134

  
1135
    agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
1136
    agenda.save()
1137
    resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
1138
    assert 'Bookings (1/10)' in resp.text
1139
    assert '&lt;b&gt;User&#39;s 1&lt;/b&gt; Foo Bar, May 24, 2022, 2 a.m.' in resp.text
1140
    assert 'Waiting List (1/2): 1 remaining place' in resp.text
1141
    assert '&lt;b&gt;User 2&lt;/b&gt; Foo Bar, May 24, 2022, 2 a.m.' in resp.text
1142

  
1143

  
1115 1144
def test_event_cancellation(app, admin_user):
1116 1145
    agenda = Agenda.objects.create(label='Events', kind='events')
1117 1146
    event = Event.objects.create(
......
1125 1154
    resp = resp.click('Cancel', href='/cancel')
1126 1155
    assert 'related bookings' not in resp.text
1127 1156

  
1128
    Booking.objects.create(event=event)
1129
    Booking.objects.create(event=event)
1157
    Booking.objects.create(event=event, user_last_name='User 1')
1158
    Booking.objects.create(event=event, user_last_name='User 2')
1130 1159

  
1131 1160
    resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
1132 1161
    assert 'Bookings (2/10)' in resp.text
......
1366 1395
        event=event, user_external_id='user:1', user_first_name='User', user_last_name='42'
1367 1396
    )
1368 1397
    Booking.objects.create(
1369
        event=event, user_external_id='user:2', user_first_name='User', user_last_name='01'
1398
        event=event, user_external_id='user:2', user_first_name="User's", user_last_name='01'
1370 1399
    )
1371 1400
    Booking.objects.create(
1372 1401
        event=event, user_external_id='user:3', user_first_name='User', user_last_name='17'
......
1424 1453
    resp = resp.click('Check')
1425 1454
    assert (
1426 1455
        resp.text.index('Bookings (6/10)')
1427
        < resp.text.index('User 01')
1456
        < resp.text.index("User&#39;s 01")
1428 1457
        < resp.text.index('User 05')
1429 1458
        < resp.text.index('User 17')
1430 1459
        < resp.text.index('User 35')
......
1486 1515
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
1487 1516
    assert (
1488 1517
        resp.text.index('Bookings (6/10)')
1489
        < resp.text.index('User 01')
1518
        < resp.text.index("User&#39;s 01")
1490 1519
        < resp.text.index('User 05')
1491 1520
        < resp.text.index('User 12 Cancelled')
1492 1521
        < resp.text.index('Subscription 14')
......
1504 1533
    assert 'Subscription too soon' not in resp
1505 1534
    assert 'Subscription too late' not in resp
1506 1535

  
1507
    agenda.booking_user_block_template = '{{ booking.user_name }} Foo Bar'
1536
    agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
1508 1537
    agenda.save()
1509 1538
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
1510
    assert 'User 01 Foo Bar' in resp
1511
    assert 'Subscription 14 Foo Bar' in resp
1512
    assert 'User Waiting Foo Bar' in resp
1539
    assert '&lt;b&gt;User&#39;s 01&lt;/b&gt; Foo Bar' in resp
1540
    assert '&lt;b&gt;Subscription 14&lt;/b&gt; Foo Bar' in resp
1541
    assert '&lt;b&gt;User Waiting&lt;/b&gt; Foo Bar' in resp
1513 1542

  
1514 1543
    # cancelled booking
1515 1544
    token = resp.context['csrf_token']
1516
-