0001-manager-show-when-an-event-is-checked-53707.patch
chrono/agendas/migrations/0090_checked.py | ||
---|---|---|
1 |
from django.db import migrations, models |
|
2 | ||
3 | ||
4 |
class Migration(migrations.Migration): |
|
5 | ||
6 |
dependencies = [ |
|
7 |
('agendas', '0089_agenda_event_display_template'), |
|
8 |
] |
|
9 | ||
10 |
operations = [ |
|
11 |
migrations.AddField( |
|
12 |
model_name='agenda', |
|
13 |
name='mark_event_checked_auto', |
|
14 |
field=models.BooleanField( |
|
15 |
default=False, verbose_name='Automatically mark events when they are checked' |
|
16 |
), |
|
17 |
), |
|
18 |
migrations.AddField( |
|
19 |
model_name='event', |
|
20 |
name='checked', |
|
21 |
field=models.BooleanField(default=False), |
|
22 |
), |
|
23 |
] |
chrono/agendas/models.py | ||
---|---|---|
205 | 205 |
_('Booking form URL'), max_length=200, blank=True, validators=[django_template_validator] |
206 | 206 |
) |
207 | 207 |
desk_simple_management = models.BooleanField(default=False) |
208 |
mark_event_checked_auto = models.BooleanField( |
|
209 |
_('Automatically mark events when they are checked'), default=False |
|
210 |
) |
|
208 | 211 |
booking_check_filters = models.CharField( |
209 | 212 |
_('Filters'), |
210 | 213 |
max_length=250, |
... | ... | |
1206 | 1209 |
full = models.BooleanField(default=False) |
1207 | 1210 |
cancelled = models.BooleanField(default=False) |
1208 | 1211 |
cancellation_scheduled = models.BooleanField(default=False) |
1212 |
checked = models.BooleanField(default=False) |
|
1209 | 1213 |
meeting_type = models.ForeignKey(MeetingType, null=True, on_delete=models.CASCADE) |
1210 | 1214 |
desk = models.ForeignKey('Desk', null=True, on_delete=models.CASCADE) |
1211 | 1215 |
resources = models.ManyToManyField('Resource') |
... | ... | |
1256 | 1260 |
) |
1257 | 1261 |
self.almost_full = bool(self.booked_places >= 0.9 * self.places) |
1258 | 1262 | |
1263 |
def set_is_checked(self): |
|
1264 |
if not self.agenda.mark_event_checked_auto: |
|
1265 |
return |
|
1266 |
if self.checked: |
|
1267 |
return |
|
1268 |
booking_qs = self.booking_set.filter( |
|
1269 |
cancellation_datetime__isnull=True, |
|
1270 |
in_waiting_list=False, |
|
1271 |
user_was_present__isnull=True, |
|
1272 |
) |
|
1273 |
if booking_qs.exists(): |
|
1274 |
return |
|
1275 |
self.checked = True |
|
1276 |
self.save(update_fields=['checked']) |
|
1277 | ||
1259 | 1278 |
def in_bookable_period(self): |
1260 | 1279 |
if self.publication_date and localtime(now()).date() < self.publication_date: |
1261 | 1280 |
return False |
... | ... | |
1686 | 1705 |
self.secondary_booking_set.update(in_waiting_list=True) |
1687 | 1706 |
self.save() |
1688 | 1707 | |
1708 |
def mark_user_absence(self, reason=None): |
|
1709 |
self.user_absence_reason = reason |
|
1710 |
self.user_was_present = False |
|
1711 |
self.save() |
|
1712 |
self.event.set_is_checked() |
|
1713 | ||
1714 |
def mark_user_presence(self): |
|
1715 |
self.user_absence_reason = '' |
|
1716 |
self.user_was_present = True |
|
1717 |
self.save() |
|
1718 |
self.event.set_is_checked() |
|
1719 | ||
1689 | 1720 |
def get_user_block(self): |
1690 | 1721 |
template_vars = Context(settings.TEMPLATE_VARS) |
1691 | 1722 |
template_vars.update( |
chrono/api/views.py | ||
---|---|---|
1523 | 1523 |
serializer.save() |
1524 | 1524 |
if 'user_was_present' in request.data: |
1525 | 1525 |
self.booking.secondary_booking_set.update(user_was_present=self.booking.user_was_present) |
1526 |
self.booking.event.set_is_checked() |
|
1526 | 1527 |
if 'user_absence_reason' in request.data: |
1527 | 1528 |
self.booking.secondary_booking_set.update(user_absence_reason=self.booking.user_absence_reason) |
1528 | 1529 |
if 'extra_data' in request.data: |
chrono/manager/forms.py | ||
---|---|---|
784 | 784 |
class AgendaBookingCheckSettingsForm(forms.ModelForm): |
785 | 785 |
class Meta: |
786 | 786 |
model = Agenda |
787 |
fields = ['absence_reasons_group', 'booking_check_filters', 'booking_user_block_template'] |
|
787 |
fields = [ |
|
788 |
'absence_reasons_group', |
|
789 |
'booking_check_filters', |
|
790 |
'booking_user_block_template', |
|
791 |
'mark_event_checked_auto', |
|
792 |
] |
|
788 | 793 |
widgets = {'booking_user_block_template': forms.Textarea(attrs={'rows': 3})} |
789 | 794 | |
790 | 795 |
def __init__(self, *args, **kwargs): |
chrono/manager/templates/chrono/manager_agenda_event_fragment.html | ||
---|---|---|
11 | 11 |
><a href="{% if view_mode == 'settings_view' %}{% url 'chrono-manager-event-edit' pk=agenda.pk event_pk=event.pk %}?next=settings{% elif event.pk %}{% url 'chrono-manager-event-view' pk=agenda.pk event_pk=event.pk %}{% else %}{% url 'chrono-manager-event-create-recurrence' pk=agenda.pk event_identifier=event.slug %}{% endif %}"> |
12 | 12 |
{% if event.cancellation_status %} |
13 | 13 |
<span class="tag">{{ event.cancellation_status }}</span> |
14 |
{% elif event.main_list_full %} |
|
15 |
<span class="full tag">{% trans "Full" %}</span> |
|
14 |
{% else %} |
|
15 |
{% if event.main_list_full %} |
|
16 |
<span class="full tag">{% trans "Full" %}</span> |
|
17 |
{% endif %} |
|
18 |
{% if event.checked %} |
|
19 |
<span class="checked tag">{% trans "Checked" %}</span> |
|
20 |
{% endif %} |
|
16 | 21 |
{% endif %} |
17 | 22 |
<span class="event-info"> |
18 | 23 |
{% if view_mode == 'settings_view' %} |
chrono/manager/templates/chrono/manager_event_check.html | ||
---|---|---|
27 | 27 |
</form> |
28 | 28 |
<table class="main check-bookings"> |
29 | 29 |
<tbody> |
30 |
{% if booked and not event.checked %} |
|
31 |
<tr class="booking all-bookings"> |
|
32 |
<td class="booking-actions"> |
|
33 |
<form method="post" action="{% url 'chrono-manager-event-checked' pk=agenda.pk event_pk=object.pk %}"> |
|
34 |
{% csrf_token %} |
|
35 |
<button class="submit-button">{% trans "Mark the event as checked" %}</button> |
|
36 |
</form> |
|
37 |
</td> |
|
38 |
</tr> |
|
39 |
{% endif %} |
|
30 | 40 |
{% if booked_without_status %} |
31 | 41 |
<tr class="booking all-bookings"> |
32 | 42 |
<td colspan="2"><b>{% trans "Mark all bookings without status:" %}</b></td> |
chrono/manager/templates/chrono/manager_events_agenda_settings.html | ||
---|---|---|
61 | 61 |
{% endif %} |
62 | 62 |
{% endwith %} |
63 | 63 | |
64 |
<p>{% trans "User block template" %}:</p>
|
|
64 |
<p>{% trans "User block template:" %}</p>
|
|
65 | 65 |
<pre>{{ agenda.get_booking_user_block_template }}</pre> |
66 | ||
67 |
<p>{% trans "Automatically mark events when they are checked:" %} {{ agenda.mark_event_checked_auto|yesno }}</p> |
|
66 | 68 |
</div> |
67 | 69 |
</div> |
68 | 70 |
chrono/manager/urls.py | ||
---|---|---|
221 | 221 |
views.event_absence, |
222 | 222 |
name='chrono-manager-event-absence', |
223 | 223 |
), |
224 |
url( |
|
225 |
r'^agendas/(?P<pk>\d+)/events/(?P<event_pk>\d+)/checked$', |
|
226 |
views.event_checked, |
|
227 |
name='chrono-manager-event-checked', |
|
228 |
), |
|
224 | 229 |
url( |
225 | 230 |
r'^agendas/(?P<pk>\d+)/event_cancellation_report/(?P<report_pk>\d+)/$', |
226 | 231 |
views.event_cancellation_report, |
chrono/manager/views.py | ||
---|---|---|
2024 | 2024 |
def post(self, request, *args, **kwargs): |
2025 | 2025 |
bookings = self.get_bookings() |
2026 | 2026 |
bookings.update(user_absence_reason='', user_was_present=True) |
2027 |
self.event.set_is_checked() |
|
2027 | 2028 |
return self.response(request) |
2028 | 2029 | |
2029 | 2030 | |
... | ... | |
2045 | 2046 |
qs_kwargs['user_absence_reason'] = form.cleaned_data['reason'] |
2046 | 2047 |
bookings = self.get_bookings() |
2047 | 2048 |
bookings.update(user_was_present=False, **qs_kwargs) |
2049 |
self.event.set_is_checked() |
|
2048 | 2050 |
return self.response(request) |
2049 | 2051 | |
2050 | 2052 | |
2051 | 2053 |
event_absence = EventAbsenceView.as_view() |
2052 | 2054 | |
2053 | 2055 | |
2056 |
class EventCheckedView(EventCheckMixin, ViewableAgendaMixin, View): |
|
2057 |
def post(self, request, *args, **kwargs): |
|
2058 |
if not self.event.checked: |
|
2059 |
self.event.checked = True |
|
2060 |
self.event.save(update_fields=['checked']) |
|
2061 |
return self.response(request) |
|
2062 | ||
2063 | ||
2064 |
event_checked = EventCheckedView.as_view() |
|
2065 | ||
2066 | ||
2054 | 2067 |
class AgendaAddResourceView(ManagedAgendaMixin, FormView): |
2055 | 2068 |
template_name = 'chrono/manager_agenda_resource_form.html' |
2056 | 2069 |
form_class = AgendaResourceForm |
... | ... | |
2750 | 2763 |
class BookingPresenceView(ViewableAgendaMixin, BookingCheckMixin, View): |
2751 | 2764 |
def post(self, request, *args, **kwargs): |
2752 | 2765 |
booking = self.get_booking(**kwargs) |
2753 |
booking.user_absence_reason = '' |
|
2754 |
booking.user_was_present = True |
|
2755 |
booking.save() |
|
2766 |
booking.mark_user_presence() |
|
2756 | 2767 |
return self.response(request, booking) |
2757 | 2768 | |
2758 | 2769 | |
... | ... | |
2770 | 2781 |
def post(self, request, *args, **kwargs): |
2771 | 2782 |
booking = self.get_booking(**kwargs) |
2772 | 2783 |
form = self.get_form() |
2784 |
reason = None |
|
2773 | 2785 |
if form.is_valid(): |
2774 |
booking.user_absence_reason = form.cleaned_data['reason'] |
|
2775 |
booking.user_was_present = False |
|
2776 |
booking.save() |
|
2786 |
reason = form.cleaned_data['reason'] |
|
2787 |
booking.mark_user_absence(reason=reason) |
|
2777 | 2788 |
return self.response(request, booking) |
2778 | 2789 | |
2779 | 2790 |
tests/manager/test_all.py | ||
---|---|---|
562 | 562 |
assert agenda.booking_check_filters == 'foo,bar,baz' |
563 | 563 |
assert agenda.get_booking_check_filters() == ['foo', 'bar', 'baz'] |
564 | 564 | |
565 |
# check auto checked |
|
566 |
assert agenda.mark_event_checked_auto is False |
|
567 |
resp = app.get(url) |
|
568 |
resp.form['mark_event_checked_auto'] = True |
|
569 |
resp = resp.form.submit() |
|
570 |
agenda.refresh_from_db() |
|
571 |
assert agenda.mark_event_checked_auto is True |
|
572 | ||
565 | 573 |
# check kind |
566 | 574 |
agenda.kind = 'meetings' |
567 | 575 |
agenda.save() |
tests/manager/test_event.py | ||
---|---|---|
1178 | 1178 |
event.cancellation_datetime = None |
1179 | 1179 | |
1180 | 1180 | |
1181 |
def test_event_checked(app, admin_user): |
|
1182 |
agenda = Agenda.objects.create(label='Events', kind='events', booking_check_filters='foo,bar') |
|
1183 |
event = Event.objects.create( |
|
1184 |
label='xyz', |
|
1185 |
start_datetime=now() - datetime.timedelta(days=1), |
|
1186 |
places=10, |
|
1187 |
agenda=agenda, |
|
1188 |
) |
|
1189 |
login(app) |
|
1190 | ||
1191 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
|
1192 |
assert 'Mark the event as checked' not in resp |
|
1193 | ||
1194 |
Booking.objects.create(event=event, user_first_name='User') |
|
1195 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
|
1196 |
assert 'Mark the event as checked' in resp |
|
1197 |
assert event.checked is False |
|
1198 |
resp = app.get('/manage/agendas/%s/settings' % agenda.id) |
|
1199 |
assert 'checked tag' not in resp |
|
1200 | ||
1201 |
token = resp.context['csrf_token'] |
|
1202 |
resp = app.post( |
|
1203 |
'/manage/agendas/%s/events/%s/checked' % (agenda.pk, event.pk), |
|
1204 |
params={'csrfmiddlewaretoken': token}, |
|
1205 |
) |
|
1206 |
assert resp.location.endswith('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
|
1207 |
event.refresh_from_db() |
|
1208 |
assert event.checked is True |
|
1209 |
resp = resp.follow() |
|
1210 |
assert 'Mark the event as checked' not in resp |
|
1211 |
resp = app.get('/manage/agendas/%s/settings' % agenda.id) |
|
1212 |
assert 'checked tag' in resp |
|
1213 | ||
1214 | ||
1181 | 1215 |
def test_event_check_filters(app, admin_user): |
1182 | 1216 |
agenda = Agenda.objects.create(label='Events', kind='events', booking_check_filters='foo,bar') |
1183 | 1217 |
event = Event.objects.create( |
... | ... | |
1274 | 1308 |
agenda=agenda, |
1275 | 1309 |
) |
1276 | 1310 |
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42') |
1311 |
assert agenda.mark_event_checked_auto is False |
|
1277 | 1312 | |
1278 | 1313 |
login(app) |
1279 | 1314 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
... | ... | |
1294 | 1329 |
booking.refresh_from_db() |
1295 | 1330 |
assert booking.user_was_present is True |
1296 | 1331 |
assert booking.user_absence_reason == '' |
1332 |
event.refresh_from_db() |
|
1333 |
assert event.checked is False |
|
1334 | ||
1335 |
agenda.mark_event_checked_auto = True |
|
1336 |
agenda.save() |
|
1297 | 1337 | |
1298 | 1338 |
# set as absent without reason |
1299 | 1339 |
resp = app.post( |
... | ... | |
1306 | 1346 |
booking.refresh_from_db() |
1307 | 1347 |
assert booking.user_was_present is False |
1308 | 1348 |
assert booking.user_absence_reason == '' |
1349 |
event.refresh_from_db() |
|
1350 |
assert event.checked is True |
|
1309 | 1351 | |
1310 | 1352 |
agenda.absence_reasons_group = group |
1311 | 1353 |
agenda.save() |
... | ... | |
1388 | 1430 |
agenda=agenda, |
1389 | 1431 |
) |
1390 | 1432 |
booking1 = Booking.objects.create(event=event, user_first_name='User', user_last_name='42') |
1433 |
assert agenda.mark_event_checked_auto is False |
|
1391 | 1434 | |
1392 | 1435 |
login(app) |
1393 | 1436 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
... | ... | |
1402 | 1445 |
booking1.refresh_from_db() |
1403 | 1446 |
assert booking1.user_was_present is False |
1404 | 1447 |
assert booking1.user_absence_reason == '' |
1448 |
event.refresh_from_db() |
|
1449 |
assert event.checked is False |
|
1450 | ||
1451 |
agenda.mark_event_checked_auto = True |
|
1452 |
agenda.save() |
|
1405 | 1453 | |
1406 | 1454 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
1407 | 1455 |
assert 'Mark all bookings without status' not in resp |
... | ... | |
1423 | 1471 |
booking2.refresh_from_db() |
1424 | 1472 |
assert booking2.user_was_present is True |
1425 | 1473 |
assert booking2.user_absence_reason == '' |
1474 |
event.refresh_from_db() |
|
1475 |
assert event.checked is True |
|
1426 | 1476 | |
1427 | 1477 |
booking3 = Booking.objects.create(event=event, user_first_name='User', user_last_name='51') |
1428 | 1478 |
app.post( |
tests/test_api.py | ||
---|---|---|
2646 | 2646 |
agenda = Agenda.objects.create(kind='events') |
2647 | 2647 |
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10) |
2648 | 2648 |
booking = Booking.objects.create(event=event) |
2649 |
assert agenda.mark_event_checked_auto is False |
|
2649 | 2650 | |
2650 | 2651 |
app.authorization = ('Basic', ('john.doe', 'password')) |
2651 | 2652 | |
... | ... | |
2653 | 2654 |
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag}) |
2654 | 2655 |
booking.refresh_from_db() |
2655 | 2656 |
assert booking.user_was_present == flag |
2657 |
event.refresh_from_db() |
|
2658 |
assert event.checked is False |
|
2659 | ||
2660 |
agenda.mark_event_checked_auto = True |
|
2661 |
agenda.save() |
|
2662 |
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag}) |
|
2663 |
booking.refresh_from_db() |
|
2664 |
assert booking.user_was_present == flag |
|
2665 |
event.refresh_from_db() |
|
2666 |
assert event.checked == (flag is not None) |
|
2656 | 2667 | |
2657 | 2668 |
# reset |
2658 | 2669 |
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': None}) |
2659 |
- |