manager: configuer user block on check page (#53237)
This commit is contained in:
parent
7eea2968b7
commit
f1b62254e5
|
@ -0,0 +1,23 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
import chrono.agendas.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agendas', '0085_reason_slug'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='agenda',
|
||||
name='booking_user_block_template',
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text='Displayed for each booking in event check page',
|
||||
verbose_name='User block template',
|
||||
validators=[chrono.agendas.models.django_template_validator],
|
||||
),
|
||||
),
|
||||
]
|
|
@ -204,6 +204,12 @@ class Agenda(models.Model):
|
|||
_('Booking form URL'), max_length=200, blank=True, validators=[django_template_validator]
|
||||
)
|
||||
desk_simple_management = models.BooleanField(default=False)
|
||||
booking_user_block_template = models.TextField(
|
||||
_('User block template'),
|
||||
help_text=_('Displayed for each booking in event check page'),
|
||||
blank=True,
|
||||
validators=[django_template_validator],
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['label']
|
||||
|
@ -714,6 +720,12 @@ class Agenda(models.Model):
|
|||
except (VariableDoesNotExist, TemplateSyntaxError):
|
||||
return
|
||||
|
||||
def get_booking_user_block_template(self):
|
||||
return (
|
||||
self.booking_user_block_template
|
||||
or '{{ booking.user_name|default:booking.label|default:"%s" }}' % _('Unknown')
|
||||
)
|
||||
|
||||
def get_recurrence_exceptions(self, min_start, max_start):
|
||||
return TimePeriodException.objects.filter(
|
||||
Q(desk__slug='_exceptions_holder', desk__agenda=self)
|
||||
|
@ -1637,6 +1649,18 @@ class Booking(models.Model):
|
|||
self.secondary_booking_set.update(in_waiting_list=True)
|
||||
self.save()
|
||||
|
||||
def get_user_block(self):
|
||||
template_vars = Context(settings.TEMPLATE_VARS)
|
||||
template_vars.update(
|
||||
{
|
||||
'booking': self,
|
||||
}
|
||||
)
|
||||
try:
|
||||
return Template(self.event.agenda.get_booking_user_block_template()).render(template_vars)
|
||||
except (VariableDoesNotExist, TemplateSyntaxError):
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def anonymize_bookings(cls, bookings_queryset):
|
||||
bookings_queryset.update(
|
||||
|
|
|
@ -27,12 +27,13 @@ from django.db import transaction
|
|||
from django.forms import ValidationError
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.six import StringIO
|
||||
from django.utils.timezone import make_aware, make_naive, now
|
||||
from django.utils.timezone import make_aware, now
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from chrono.agendas.models import (
|
||||
WEEKDAYS_LIST,
|
||||
AbsenceReason,
|
||||
AbsenceReasonGroup,
|
||||
Agenda,
|
||||
AgendaNotificationsSettings,
|
||||
AgendaReminderSettings,
|
||||
|
@ -743,6 +744,18 @@ class EventCancelForm(forms.ModelForm):
|
|||
fields = []
|
||||
|
||||
|
||||
class AgendaBookingCheckSettingsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Agenda
|
||||
fields = ['absence_reasons_group', 'booking_user_block_template']
|
||||
widgets = {'booking_user_block_template': forms.Textarea(attrs={'rows': 3})}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
if not AbsenceReasonGroup.objects.exists():
|
||||
del self.fields['absence_reasons_group']
|
||||
|
||||
|
||||
class AgendaNotificationsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = AgendaNotificationsSettings
|
||||
|
|
|
@ -55,13 +55,15 @@
|
|||
<h3>
|
||||
{% blocktrans with places=object.waiting_list_places booked_places=waiting|length %}Waiting List ({{ booked_places }}/{{ places }}){% endblocktrans %}
|
||||
</h3>
|
||||
<div>
|
||||
<ul class="objects-list single-links">
|
||||
{% for booking in waiting %}
|
||||
<li><a>{{ booking.user_name|default:booking.label|default:_('Unknown') }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<table class="main check-bookings">
|
||||
<tbody>
|
||||
{% for booking in waiting %}
|
||||
<tr><td class="booking-username">{{ booking.get_user_block }}</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% load i18n %}
|
||||
|
||||
<td class="booking-username">{{ booking.user_name|default:booking.label|default:_('Unknown') }}</td>
|
||||
<td class="booking-username">{{ booking.get_user_block }}</td>
|
||||
<td class="booking-status {% if booking.user_was_present is None %}without-status{% endif %}">
|
||||
{{ booking.user_was_present|yesno:_('Present,Absent,-') }}
|
||||
{% if booking.user_was_present is False and booking.user_absence_reason %}
|
||||
|
|
|
@ -30,25 +30,28 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{% if has_absence_reasons %}
|
||||
<div class="section">
|
||||
<h3>{% trans "Absence reasons" %}
|
||||
<a rel="popup" class="button" href="{% url 'chrono-manager-agenda-absence-reasons' pk=object.id %}">{% trans 'Configure' %}</a>
|
||||
<h3>{% trans "Booking check options" %}
|
||||
<a rel="popup" class="button" href="{% url 'chrono-manager-agenda-booking-check-settings' pk=object.pk %}">{% trans 'Configure' %}</a>
|
||||
</h3>
|
||||
<div>
|
||||
{% if agenda.absence_reasons_group %}
|
||||
<p>{% trans "Absence reasons group:" %} {{ agenda.absence_reasons_group }}</p>
|
||||
<ul>
|
||||
{% for reason in agenda.absence_reasons_group.absence_reasons.all %}
|
||||
<li>{{ reason }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>{% trans "No absence reasons configured for this agenda." %}</p>
|
||||
{% endif %}
|
||||
{% if has_absence_reasons %}
|
||||
{% if agenda.absence_reasons_group %}
|
||||
<p>{% trans "Absence reasons group:" %} {{ agenda.absence_reasons_group }}</p>
|
||||
<ul>
|
||||
{% for reason in agenda.absence_reasons_group.absence_reasons.all %}
|
||||
<li>{{ reason }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>{% trans "No absence reasons configured for this agenda." %}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<p>{% trans "User block template" %}:</p>
|
||||
<pre>{{ agenda.get_booking_user_block_template }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="section">
|
||||
<h3>{% trans "Notifications" %}
|
||||
|
|
|
@ -148,9 +148,9 @@ urlpatterns = [
|
|||
),
|
||||
url(r'^agendas/(?P<pk>\d+)/roles$', views.agenda_roles, name='chrono-manager-agenda-roles'),
|
||||
url(
|
||||
r'^agendas/(?P<pk>\d+)/absence-reasons$',
|
||||
views.agenda_absence_reasons,
|
||||
name='chrono-manager-agenda-absence-reasons',
|
||||
r'^agendas/(?P<pk>\d+)/check-options$',
|
||||
views.agenda_booking_check_settings,
|
||||
name='chrono-manager-agenda-booking-check-settings',
|
||||
),
|
||||
url(r'^agendas/(?P<pk>\d+)/delete$', views.agenda_delete, name='chrono-manager-agenda-delete'),
|
||||
url(r'^agendas/(?P<pk>\d+)/export$', views.agenda_export, name='chrono-manager-agenda-export'),
|
||||
|
|
|
@ -78,6 +78,7 @@ from chrono.agendas.models import (
|
|||
from .forms import (
|
||||
AbsenceReasonForm,
|
||||
AgendaAddForm,
|
||||
AgendaBookingCheckSettingsForm,
|
||||
AgendaBookingDelaysForm,
|
||||
AgendaDuplicateForm,
|
||||
AgendaEditForm,
|
||||
|
@ -913,16 +914,18 @@ class AgendaRolesView(AgendaEditView):
|
|||
agenda_roles = AgendaRolesView.as_view()
|
||||
|
||||
|
||||
class AgendaAbsenceReasonsView(AgendaEditView):
|
||||
form_class = None
|
||||
fields = ['absence_reasons_group']
|
||||
title = _('Configure absence reasons')
|
||||
class AgendaBookingCheckSettingsView(AgendaEditView):
|
||||
form_class = AgendaBookingCheckSettingsForm
|
||||
title = _("Configure booking check options")
|
||||
|
||||
def set_agenda(self, **kwargs):
|
||||
self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events')
|
||||
|
||||
def get_initial(self):
|
||||
return {'booking_user_block_template': self.agenda.get_booking_user_block_template()}
|
||||
|
||||
agenda_absence_reasons = AgendaAbsenceReasonsView.as_view()
|
||||
|
||||
agenda_booking_check_settings = AgendaBookingCheckSettingsView.as_view()
|
||||
|
||||
|
||||
class AgendaDeleteView(DeleteView):
|
||||
|
|
|
@ -214,16 +214,17 @@ def test_agenda_group(app, admin_user):
|
|||
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
||||
assert 'has_absence_reasons' in resp.context
|
||||
assert resp.context['has_absence_reasons'] is False
|
||||
assert 'Absence reasons' not in resp
|
||||
assert 'No absence reasons configured for this agenda.' not in resp
|
||||
assert '/manage/agendas/%s/absence-reasons' % agenda.pk not in resp
|
||||
resp = resp.click(href='/manage/agendas/%s/check-options' % agenda.pk)
|
||||
assert 'absence_reasons_group' not in resp.context['form'].fields
|
||||
|
||||
group = AbsenceReasonGroup.objects.create(label='Foo bar')
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
||||
assert 'has_absence_reasons' in resp.context
|
||||
assert resp.context['has_absence_reasons'] is True
|
||||
assert 'Absence reasons' in resp
|
||||
assert 'No absence reasons configured for this agenda.' in resp
|
||||
resp = resp.click(href='/manage/agendas/%s/absence-reasons' % agenda.pk)
|
||||
resp = resp.click(href='/manage/agendas/%s/check-options' % agenda.pk)
|
||||
resp.form['absence_reasons_group'] = group.pk
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'Absence reasons group: Foo bar' in resp
|
||||
|
|
|
@ -507,7 +507,7 @@ def test_options_agenda_cant_unset_delays(app, admin_user):
|
|||
assert agenda.minimal_booking_delay == 1
|
||||
|
||||
|
||||
def test_options_virtuale_agenda_can_unset_delays(app, admin_user):
|
||||
def test_options_virtual_agenda_can_unset_delays(app, admin_user):
|
||||
agenda = Agenda.objects.create(label=u'Foo bar', kind='virtual', maximal_booking_delay=2)
|
||||
assert agenda.maximal_booking_delay == 2
|
||||
app = login(app)
|
||||
|
@ -519,6 +519,42 @@ def test_options_virtuale_agenda_can_unset_delays(app, admin_user):
|
|||
assert agenda.maximal_booking_delay is None
|
||||
|
||||
|
||||
def test_options_agenda_booking_user_block_template(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
assert agenda.booking_user_block_template == ''
|
||||
assert (
|
||||
agenda.get_booking_user_block_template()
|
||||
== '{{ booking.user_name|default:booking.label|default:"Unknown" }}'
|
||||
)
|
||||
|
||||
app = login(app)
|
||||
url = '/manage/agendas/%s/check-options' % agenda.pk
|
||||
resp = app.get(url)
|
||||
resp.form['booking_user_block_template'] = '{{ booking.user_name }} Foo Bar'
|
||||
resp = resp.form.submit()
|
||||
agenda.refresh_from_db()
|
||||
assert agenda.booking_user_block_template == '{{ booking.user_name }} Foo Bar'
|
||||
assert agenda.get_booking_user_block_template() == '{{ booking.user_name }} Foo Bar'
|
||||
|
||||
resp = app.get(url)
|
||||
resp.form['booking_user_block_template'] = ''
|
||||
resp = resp.form.submit()
|
||||
agenda.refresh_from_db()
|
||||
assert agenda.booking_user_block_template == ''
|
||||
assert (
|
||||
agenda.get_booking_user_block_template()
|
||||
== '{{ booking.user_name|default:booking.label|default:"Unknown" }}'
|
||||
)
|
||||
|
||||
# check kind
|
||||
agenda.kind = 'meetings'
|
||||
agenda.save()
|
||||
app.get(url, status=404)
|
||||
agenda.kind = 'virtual'
|
||||
agenda.save()
|
||||
app.get(url, status=404)
|
||||
|
||||
|
||||
def test_options_agenda_as_manager(app, manager_user):
|
||||
agenda = Agenda(label=u'Foo bar')
|
||||
agenda.view_role = manager_user.groups.all()[0]
|
||||
|
|
|
@ -1108,6 +1108,12 @@ def test_event_check(app, admin_user):
|
|||
) # user ordering is not optimal ...
|
||||
assert 'User Cancelled' not in resp
|
||||
|
||||
agenda.booking_user_block_template = '{{ booking.user_name }} Foo Bar'
|
||||
agenda.save()
|
||||
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
|
||||
assert 'User 1 Foo Bar' in resp
|
||||
assert 'User Waiting Foo Bar' in resp
|
||||
|
||||
# cancelled booking
|
||||
token = resp.context['csrf_token']
|
||||
app.post(
|
||||
|
|
Loading…
Reference in New Issue