Projet

Général

Profil

0002-manager-use-user_block-also-in-meetings-agenda-views.patch

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

Télécharger (22,4 ko)

Voir les différences:

Subject: [PATCH 2/2] manager: use user_block also in meetings agenda views
 (#63915)

 chrono/agendas/models.py                      | 23 +++---
 chrono/manager/forms.py                       | 12 +++-
 .../manager_meetings_agenda_day_view.html     |  2 +-
 .../manager_meetings_agenda_month_view.html   |  2 +-
 .../manager_meetings_agenda_settings.html     | 14 ++++
 .../chrono/manager_resource_day_view.html     |  2 +-
 .../chrono/manager_resource_month_view.html   |  2 +-
 chrono/manager/views.py                       | 12 ++--
 tests/manager/test_all.py                     | 72 +++++++++++++++++--
 tests/manager/test_resource.py                | 30 +++++++-
 10 files changed, 140 insertions(+), 31 deletions(-)
chrono/agendas/models.py
797 797
        return [x.strip() for x in self.booking_check_filters.split(',')]
798 798

  
799 799
    def get_booking_user_block_template(self):
800
        return (
801
            self.booking_user_block_template
802
            or '{{ booking.user_name|default:booking.label|default:"%s" }}' % _('Anonymous')
803
        )
800
        if self.kind == 'events':
801
            default = '{{ booking.user_name|default:booking.label|default:"%s" }}' % _('Anonymous')
802
        else:
803
            default = """{%% if booking.label and booking.user_name %%}
804
{{ booking.label }} - {{ booking.user_name }}
805
{%% else %%}
806
{{ booking.user_name|default:booking.label|default:"%s" }}
807
{%% endif %%}""" % _(
808
                'booked'
809
            )
810
        return self.booking_user_block_template or default
804 811

  
805 812
    def get_recurrence_exceptions(self, min_start, max_start):
806 813
        return TimePeriodException.objects.filter(
......
2089 2096
        name = self.user_name or self.label or _('Anonymous')
2090 2097
        return '%s, %s' % (name, date_format(localtime(self.creation_datetime), 'DATETIME_FORMAT'))
2091 2098

  
2092
    def meetings_display(self):
2093
        if self.label and self.user_name:
2094
            return '%s - %s' % (self.label, self.user_name)
2095
        elif self.label or self.user_name:
2096
            return self.label or self.user_name
2097
        else:
2098
            return ugettext('booked')
2099

  
2100 2099
    def get_form_url(self):
2101 2100
        return translate_from_publik_url(self.form_url)
2102 2101

  
chrono/manager/forms.py
1314 1314

  
1315 1315
    def __init__(self, *args, **kwargs):
1316 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
        )
1317
        if kwargs['instance'].kind == 'events':
1318
            self.fields['booking_user_block_template'].help_text = (
1319
                _('Displayed for each booking in event page and check page'),
1320
            )
1321
        else:
1322
            self.fields['booking_user_block_template'].help_text = (
1323
                _('Displayed for each booking in agenda view pages'),
1324
            )
1325
            del self.fields['event_display_template']
1320 1326

  
1321 1327

  
1322 1328
class AgendaBookingCheckSettingsForm(forms.ModelForm):
chrono/manager/templates/chrono/manager_meetings_agenda_day_view.html
46 46
          <div class="booking{% if booking.color %} booking-color-{{ booking.color.index }}{% endif %}"
47 47
              style="height: {{ booking.css_height }}%; min-height: {{ booking.css_height }}%; top: {{ booking.css_top }}%;"
48 48
            ><span class="start-time">{{booking.event.start_datetime|date:"TIME_FORMAT"}}</span>
49
            <a {% if booking.get_backoffice_url %}href="{{booking.get_backoffice_url}}"{% endif %}>{{ booking.meetings_display }}</a>
49
            <a {% if booking.get_backoffice_url %}href="{{booking.get_backoffice_url}}"{% endif %}>{{ booking.get_user_block }}</a>
50 50
            <a rel="popup" class="cancel" href="{% url 'chrono-manager-booking-cancel' pk=booking.event.agenda_id booking_pk=booking.pk %}?next={{ request.path }}">{% trans "Cancel" %}</a>
51 51
            {% if booking.color %}<span class="booking-color-label booking-bg-color-{{ booking.color.index }}">{{ booking.color }}</span>{% endif %}
52 52
          </div>
chrono/manager/templates/chrono/manager_meetings_agenda_month_view.html
36 36
      {% for slot in day.infos.booked_slots %}
37 37
      <div class="booking{% if slot.booking.color %} booking-color-{{ slot.booking.color.index }}{% endif %}" style="left:{{ slot.css_left|stringformat:".1f" }}%;height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;">
38 38
        <span class="start-time">{{slot.booking.event.start_datetime|date:"TIME_FORMAT"}}</span>
39
        <a {% if slot.booking.get_backoffice_url %}href="{{slot.booking.get_backoffice_url}}"{% endif %}>{{ slot.booking.meetings_display }}</a>
39
        <a {% if slot.booking.get_backoffice_url %}href="{{slot.booking.get_backoffice_url}}"{% endif %}>{{ slot.booking.get_user_block }}</a>
40 40
          <a rel="popup" class="cancel" href="{% url 'chrono-manager-booking-cancel' pk=slot.booking.event.agenda_id booking_pk=slot.booking.id %}?next={{ request.path }}">{% trans "Cancel" %}</a>
41 41
        {% if not single_desk %}<span class="desk">{{ slot.desk }}</span>{% endif %}
42 42
        {% if slot.booking.color %}<span class="booking-color-label booking-bg-color-{{ slot.booking.color.index }}">{{ slot.booking.color }}</span>{% endif %}
chrono/manager/templates/chrono/manager_meetings_agenda_settings.html
153 153
{% endif %}
154 154
{% endwith %}
155 155

  
156
<div class="section">
157
<h3>{% trans "Display options" %}
158
    <a rel="popup" class="button" href="{% url 'chrono-manager-agenda-display-settings' pk=object.pk %}">{% trans 'Configure' %}</a>
159
</h3>
160
<div>
161
    <ul>
162
        <li>
163
            {% trans "Booking display template:" %}
164
            <pre>{{ agenda.get_booking_user_block_template }}</pre>
165
        </li>
166
    </ul>
167
</div>
168
</div>
169

  
156 170
{% endblock %}
chrono/manager/templates/chrono/manager_resource_day_view.html
40 40
                      <div class="booking"
41 41
                          style="height: {{ booking.css_height }}%; min-height: {{ booking.css_height }}%; top: {{ booking.css_top }}%;"
42 42
                        ><span class="start-time">{{ booking.event.start_datetime|date:"TIME_FORMAT" }}</span>
43
                        <a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{{ booking.meetings_display }}</a>
43
                        <a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{{ booking.get_user_block }}</a>
44 44
                      </div>
45 45
                    {% endfor %}
46 46
                </td>
chrono/manager/templates/chrono/manager_resource_month_view.html
49 49
                {% for slot in day.infos.booked_slots %}
50 50
                <div class="booking" style="height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%">
51 51
                    <span class="start-time">{{ slot.booking.event.start_datetime|date:"TIME_FORMAT" }}</span>
52
                    <a {% if slot.booking.get_backoffice_url %}href="{{ slot.booking.get_backoffice_url }}"{% endif %}>{{ booking.meetings_display }}</a>
52
                    <a {% if slot.booking.get_backoffice_url %}href="{{ slot.booking.get_backoffice_url }}"{% endif %}>{{ slot.booking.get_user_block }}</a>
53 53
                </div>
54 54
                {% endfor %}
55 55
                {% endif %}
chrono/manager/views.py
287 287

  
288 288
    def get_queryset(self):
289 289
        queryset = (
290
            self.resource.event_set.all().select_related('meeting_type').prefetch_related('booking_set')
290
            self.resource.event_set.all()
291
            .select_related('meeting_type', 'agenda')
292
            .prefetch_related('booking_set')
291 293
        )
292 294
        return queryset
293 295

  
......
402 404

  
403 405
    def get_queryset(self):
404 406
        queryset = (
405
            self.resource.event_set.all().select_related('meeting_type').prefetch_related('booking_set')
407
            self.resource.event_set.all()
408
            .select_related('meeting_type', 'agenda')
409
            .prefetch_related('booking_set')
406 410
        )
407 411
        return queryset
408 412

  
......
1247 1251
    title = _("Configure display options")
1248 1252

  
1249 1253
    def set_agenda(self, **kwargs):
1250
        self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events')
1254
        self.agenda = get_object_or_404(Agenda.objects.exclude(kind='virtual'), pk=kwargs.get('pk'))
1251 1255

  
1252 1256
    def get_initial(self):
1253 1257
        return {'booking_user_block_template': self.agenda.get_booking_user_block_template()}
......
1419 1423
            else:
1420 1424
                queryset = (
1421 1425
                    Event.objects.filter(agenda__virtual_agendas=self.agenda)
1422
                    .select_related('meeting_type')
1426
                    .select_related('meeting_type', 'agenda')
1423 1427
                    .prefetch_related('booking_set')
1424 1428
                )
1425 1429
        return queryset
tests/manager/test_all.py
575 575
        resp = resp.form.submit()
576 576
        assert 'syntax error' in resp.text
577 577

  
578
    # check kind
578
    # and for meetings agenda
579 579
    agenda.kind = 'meetings'
580 580
    agenda.save()
581
    app.get(url, status=404)
581
    resp = app.get(url)
582
    assert 'event_display_template' not in resp.form.fields
583
    assert 'booking_user_block_template' in resp.form.fields
584

  
585
    # check kind
582 586
    agenda.kind = 'virtual'
583 587
    agenda.save()
584 588
    app.get(url, status=404)
......
858 862
    booking_url = resp.json['data'][0]['api']['fillslot_url']
859 863
    booking_url2 = resp.json['data'][2]['api']['fillslot_url']
860 864
    resp = app.post(booking_url)
861
    resp = app.post_json(booking_url2, params={'label': 'foo', 'user': 'bar', 'url': 'http://baz/'})
865
    resp = app.post_json(
866
        booking_url2, params={'label': 'foo', 'user_last_name': "bar's", 'url': 'http://baz/'}
867
    )
862 868

  
863 869
    app.reset()
864 870
    login(app)
865 871
    date = Booking.objects.all()[0].event.start_datetime
866 872
    resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
867 873
    assert resp.text.count('div class="booking') == 2
874
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
875
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
876
    assert 'foo - bar&#39;s' in resp
868 877
    assert 'hourspan-2' in resp.text  # table CSS class
869 878
    assert 'height: 50%; top: 0%;' in resp.text  # booking cells
870 879

  
880
    agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
881
    agenda.save()
882
    resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
883
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
884
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar"
885
    assert '&lt;b&gt;bar&#39;s&lt;/b&gt; Foo Bar' in resp
886

  
871 887
    # create a shorter meeting type, this will change the table CSS class
872 888
    # (and visually this will give more room for events)
873 889
    meetingtype = MeetingType(agenda=agenda, label='Baz', duration=15)
......
1405 1421
    booking_url = resp.json['data'][0]['api']['fillslot_url']
1406 1422
    booking_url2 = resp.json['data'][2]['api']['fillslot_url']
1407 1423
    booking = app.post(booking_url)
1408
    booking_2 = app.post_json(booking_url2, params={'label': 'foo book', 'user': 'bar', 'url': 'http://baz/'})
1424
    booking_2 = app.post_json(
1425
        booking_url2, params={'label': 'foo book', 'user_last_name': "bar's", 'url': 'http://baz/'}
1426
    )
1409 1427

  
1410 1428
    app.reset()
1411 1429
    login(app)
1412 1430
    date = Booking.objects.all()[0].event.start_datetime
1413 1431
    resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month))
1414 1432
    assert resp.text.count('<div class="booking" style="left:1.0%;height:33.0%;') == 2  # booking cells
1433
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
1434
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo book - bar's"
1435
    assert 'foo book - bar&#39;s' in resp
1415 1436
    assert len(resp.pyquery.find('span.desk')) == 0
1416 1437

  
1438
    agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
1439
    agenda.save()
1440
    resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month))
1441
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
1442
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar"
1443
    assert '&lt;b&gt;bar&#39;s&lt;/b&gt; Foo Bar' in resp
1444

  
1417 1445
    desk = Desk.objects.create(agenda=agenda, label='Desk B')
1418 1446
    resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month))
1419 1447
    assert len(resp.pyquery.find('span.desk')) == 2
......
1904 1932
            meeting_type=meetingtype2,
1905 1933
            start_datetime=now().replace(hour=hour, minute=minute),
1906 1934
        )
1907
        Booking.objects.create(event=event)
1935
        Booking.objects.create(event=event, label='foo', user_last_name="bar's")
1908 1936

  
1909 1937
    date = Booking.objects.all()[0].event.start_datetime
1910 1938
    resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
1911 1939
    assert resp.text.count('div class="booking') == 4
1940
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
1941
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
1942
    assert resp.pyquery.find('div.booking a').not_('.cancel')[2].text.strip() == 'booked'
1943
    assert resp.pyquery.find('div.booking a').not_('.cancel')[3].text.strip() == "foo - bar's"
1944
    assert 'foo - bar&#39;s' in resp
1912 1945
    assert 'hourspan-2' in resp.text  # table CSS class
1913 1946
    assert 'height: 50%; top: 0%;' in resp.text  # booking cells
1914 1947

  
1948
    real_agenda_1.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
1949
    real_agenda_1.save()
1950
    real_agenda_2.booking_user_block_template = '<b>{{ booking.user_name }}</b> Bar Foo'
1951
    real_agenda_2.save()
1952
    resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
1953
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
1954
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Bar Foo"
1955
    assert resp.pyquery.find('div.booking a').not_('.cancel')[2].text.strip() == '<b></b> Foo Bar'
1956
    assert resp.pyquery.find('div.booking a').not_('.cancel')[3].text.strip() == "<b>bar's</b> Bar Foo"
1957
    assert '&lt;b&gt;bar&#39;s&lt;/b&gt; Bar Foo' in resp
1958

  
1915 1959
    # create a shorter meeting type, this will change the table CSS class
1916 1960
    # (and visually this will give more room for events)
1917 1961
    MeetingType.objects.create(agenda=real_agenda_1, label='Baz', duration=15)
......
2037 2081
            meeting_type=meetingtype2,
2038 2082
            start_datetime=now().replace(hour=hour, minute=minute),
2039 2083
        )
2040
        Booking.objects.create(event=event)
2084
        Booking.objects.create(event=event, label='foo', user_last_name="bar's")
2041 2085

  
2042 2086
    date = Booking.objects.all()[0].event.start_datetime
2043 2087
    resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month))
......
2045 2089
    assert (
2046 2090
        resp.text.count('<div class="booking" style="left:50.0%;height:50.0%;min-height:50.0%;') == 2
2047 2091
    )  # booking cells
2092
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
2093
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
2094
    assert resp.pyquery.find('div.booking a').not_('.cancel')[2].text.strip() == 'booked'
2095
    assert resp.pyquery.find('div.booking a').not_('.cancel')[3].text.strip() == "foo - bar's"
2096
    assert 'foo - bar&#39;s' in resp
2097

  
2098
    real_agenda_1.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
2099
    real_agenda_1.save()
2100
    real_agenda_2.booking_user_block_template = '<b>{{ booking.user_name }}</b> Bar Foo'
2101
    real_agenda_2.save()
2102
    resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month))
2103
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
2104
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Bar Foo"
2105
    assert resp.pyquery.find('div.booking a').not_('.cancel')[2].text.strip() == '<b></b> Foo Bar'
2106
    assert resp.pyquery.find('div.booking a').not_('.cancel')[3].text.strip() == "<b>bar's</b> Bar Foo"
2107
    assert '&lt;b&gt;bar&#39;s&lt;/b&gt; Bar Foo' in resp
2048 2108

  
2049 2109
    # cancel a booking
2050 2110
    booking = Booking.objects.first()
tests/manager/test_resource.py
102 102
            start_datetime=now().replace(hour=hour, minute=minute),
103 103
        )
104 104
        event.resources.add(resource)
105
        Booking.objects.create(event=event)
105
        if hour == 10:
106
            Booking.objects.create(event=event)
107
        else:
108
            Booking.objects.create(event=event, label='foo', user_last_name="bar's")
106 109

  
107 110
    with CaptureQueriesContext(connection) as ctx:
108 111
        resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
109 112
        assert len(ctx.captured_queries) == 7
110 113
    assert resp.text.count('div class="booking') == 2
114
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
115
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
116
    assert 'foo - bar&#39;s' in resp
111 117
    assert 'hourspan-2' in resp.text  # table CSS class
112 118
    assert 'height: 50%; top: 0%;' in resp.text  # booking cells
113 119
    assert 'height: 50%; top: 50%;' in resp.text  # booking cells
114 120

  
121
    agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
122
    agenda.save()
123
    resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
124
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
125
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar"
126
    assert '&lt;b&gt;bar&#39;s&lt;/b&gt; Foo Bar' in resp
127

  
115 128
    # create a shorter meeting type, this will change the table CSS class
116 129
    # (and visually this will give more room for events)
117 130
    meetingtype = MeetingType.objects.create(agenda=agenda, label='Baz', duration=15)
......
240 253
            start_datetime=now().replace(hour=hour, minute=minute),
241 254
        )
242 255
        event.resources.add(resource)
243
        Booking.objects.create(event=event)
256
        if hour == 10:
257
            Booking.objects.create(event=event)
258
        else:
259
            Booking.objects.create(event=event, label='foo', user_last_name="bar's")
244 260

  
245 261
    today = datetime.date.today()
246 262
    with CaptureQueriesContext(connection) as ctx:
247 263
        resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, today.year, today.month))
248 264
        assert len(ctx.captured_queries) == 8
249 265
    assert resp.text.count('<div class="booking" style="height:33.0%;') == 2  # booking cells
266
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
267
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
268
    assert 'foo - bar&#39;s' in resp
269

  
270
    agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
271
    agenda.save()
272
    resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, today.year, today.month))
273
    assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
274
    assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar"
275
    assert '&lt;b&gt;bar&#39;s&lt;/b&gt; Foo Bar' in resp
250 276

  
251 277
    # cancel booking
252 278
    booking = Booking.objects.first()
253
-