misc: use Django native split datetime field (#45108)

This commit is contained in:
Benjamin Dauvergne 2020-07-16 14:34:19 +02:00
parent 8e56a48b4f
commit 449805969f
7 changed files with 93 additions and 98 deletions

View File

@ -44,7 +44,7 @@ from chrono.agendas.models import (
)
from . import widgets
from .widgets import DateTimeWidget
from .widgets import SplitDateTimeField
class AgendaAddForm(forms.ModelForm):
@ -112,10 +112,12 @@ class NewEventForm(forms.ModelForm):
model = Event
widgets = {
'agenda': forms.HiddenInput(),
'start_datetime': DateTimeWidget(),
'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
}
exclude = ['full', 'meeting_type', 'desk', 'slug', 'resources']
field_classes = {
'start_datetime': SplitDateTimeField,
}
class EventForm(forms.ModelForm):
@ -123,9 +125,11 @@ class EventForm(forms.ModelForm):
model = Event
widgets = {
'agenda': forms.HiddenInput(),
'start_datetime': DateTimeWidget(),
'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
}
field_classes = {
'start_datetime': SplitDateTimeField,
}
exclude = ['full', 'meeting_type', 'desk', 'resources']
@ -255,8 +259,10 @@ class TimePeriodExceptionForm(forms.ModelForm):
fields = ['desk', 'start_datetime', 'end_datetime', 'label']
widgets = {
'desk': forms.HiddenInput(),
'start_datetime': DateTimeWidget(),
'end_datetime': DateTimeWidget(),
}
field_classes = {
'start_datetime': SplitDateTimeField,
'end_datetime': SplitDateTimeField,
}
def clean(self):

View File

@ -45,8 +45,8 @@
<script>
{% if not object.id %}
$('[name="start_datetime$date"]').on('change', function() {
var $end_datetime = $('[name="end_datetime$date"]');
$('[name="start_datetime_0"]').on('change', function() {
var $end_datetime = $('[name="end_datetime_0"]');
if (! $end_datetime.val()) {
var value = $(this).val();
if (value && new Date(value).getFullYear() > 999) {
@ -56,13 +56,13 @@
});
{% endif %}
$('button#allday').on('click', function() {
var $start_datetime = $('[name="start_datetime$date"]');
var $start_datetime = $('[name="start_datetime_0"]');
if ($start_datetime.val()) {
var new_date = new Date($start_datetime.val());
new_date.setDate(new_date.getDate() + 1);
$('[name="start_datetime$time"]').val('00:00');
$('[name="end_datetime$date"]').val(new_date.toISOString().substring(0, 10));
$('[name="end_datetime$time"]').val('00:00');
$('[name="start_datetime_1"]').val('00:00');
$('[name="end_datetime_0"]').val(new_date.toISOString().substring(0, 10));
$('[name="end_datetime_1"]').val('00:00');
}
});
</script>

View File

@ -0,0 +1,9 @@
<span class="datetime">
{% with widget=widget.subwidgets.0 %}
<input type="date" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value }}"{% endif %}{% include "django/forms/widgets/attrs.html" %} />
{% endwith %}
{% with widget=widget.subwidgets.1 %}
<!-- {{ widget.value|pprint }} -->
<input type="time" name="{{ widget.name }}" pattern="[0-9]{2}:[0-9]{2}" step="300" {% if widget.value != None %} value="{{ widget.value }}"{% endif %}{% include "django/forms/widgets/attrs.html" %} />
{% endwith %}
</span>

View File

@ -1,4 +0,0 @@
<span class="datetime">
<input type="date" name="{{ widget.name }}$date" {% if widget.value.date != None %} value="{{ widget.value.date }}"{% endif %}{% include "django/forms/widgets/attrs.html" %} />
<input type="time" name="{{ widget.name }}$time" pattern="[0-9]{2}:[0-9]{2}" step="300" {% if widget.value.time != None %} value="{{ widget.value.time }}"{% endif %}{% include "django/forms/widgets/attrs.html" %} />
</span>

View File

@ -15,35 +15,21 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import datetime
from django.forms.widgets import DateTimeInput, TimeInput, SelectMultiple
from django.utils import dateparse
from django.forms.fields import SplitDateTimeField
from django.forms.widgets import TimeInput, SelectMultiple, SplitDateTimeWidget
from django.utils.safestring import mark_safe
class DateTimeWidget(DateTimeInput):
template_name = 'chrono/widget_datetime.html'
class SplitDateTimeWidget(SplitDateTimeWidget):
template_name = 'chrono/splitdatetime.html'
def format_value(self, value):
if value:
x = {
'date': value.date().strftime('%Y-%m-%d'),
'time': value.time().strftime('%H:%M'),
}
return x
return None
def __init__(self, *args, **kwargs):
kwargs['time_format'] = '%H:%M'
super().__init__(*args, **kwargs)
def value_from_datadict(self, data, files, name):
date_string = data.get(name + '$date')
time_string = data.get(name + '$time')
if not date_string or not time_string:
return None
date_value = dateparse.parse_date(date_string)
time_value = dateparse.parse_time(time_string)
if not date_value or not time_value:
return None
return datetime.datetime.combine(date_value, time_value)
class SplitDateTimeField(SplitDateTimeField):
widget = SplitDateTimeWidget
class TimeWidget(TimeInput):

View File

@ -1110,8 +1110,8 @@ def test_add_event(app, admin_user):
assert "This agenda doesn't have any event yet." in resp.text
year = now().year + 1
resp = resp.click('New Event')
resp.form['start_datetime$date'] = '%s-02-15' % year
resp.form['start_datetime$time'] = '17:00'
resp.form['start_datetime_0'] = '%s-02-15' % year
resp.form['start_datetime_1'] = '17:00'
resp.form['places'] = 10
resp = resp.form.submit()
resp = resp.follow()
@ -1130,8 +1130,8 @@ def test_add_event(app, admin_user):
# add with a description
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click('New Event')
resp.form['start_datetime$date'] = '%s-02-15' % year
resp.form['start_datetime$time'] = '18:00'
resp.form['start_datetime_0'] = '%s-02-15' % year
resp.form['start_datetime_1'] = '18:00'
resp.form['publication_date'] = '2020-05-11'
resp.form['places'] = 11
resp.form['description'] = 'A description'
@ -1151,11 +1151,15 @@ def test_add_event(app, admin_user):
):
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click('New Event')
resp.form['start_datetime$date'] = parts[0]
resp.form['start_datetime$time'] = parts[1]
resp.form['start_datetime_0'] = parts[0]
resp.form['start_datetime_1'] = parts[1]
resp.form['places'] = 10
resp = resp.form.submit()
assert resp.text.count('This field is required.') == 1
assert (
resp.text.count('Enter a valid date')
or resp.text.count('Enter a valid time') == 1
or resp.text.count('This field is required.') == 1
)
def test_add_event_on_missing_agenda(app, admin_user):
@ -1177,8 +1181,8 @@ def test_add_event_as_manager(app, manager_user):
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
assert '<h2>Settings' in resp.text
resp = resp.click('New Event')
resp.form['start_datetime$date'] = '2016-02-15'
resp.form['start_datetime$time'] = '17:00'
resp.form['start_datetime_0'] = '2016-02-15'
resp.form['start_datetime_1'] = '17:00'
resp.form['places'] = 10
resp = resp.form.submit()
resp = resp.follow()
@ -1192,8 +1196,8 @@ def test_add_event_as_manager(app, manager_user):
assert event.end_datetime is None
resp = resp.click('New Event')
resp.form['start_datetime$date'] = '2016-02-15'
resp.form['start_datetime$time'] = '17:00'
resp.form['start_datetime_0'] = '2016-02-15'
resp.form['start_datetime_1'] = '17:00'
resp.form['duration'] = 45
resp.form['places'] = 12
resp = resp.form.submit()
@ -1213,12 +1217,12 @@ def test_edit_event(app, admin_user):
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click('Feb. 15, 2016, 5 p.m.')
assert resp.form['start_datetime$date'].value == '2016-02-15'
assert resp.form['start_datetime$time'].value == '17:00'
assert resp.form['start_datetime_0'].value == '2016-02-15'
assert resp.form['start_datetime_1'].value == '17:00'
assert resp.form['publication_date'].value == ''
assert resp.form['duration'].value == ''
resp.form['start_datetime$date'] = '2016-02-16'
resp.form['start_datetime$time'] = '17:00'
resp.form['start_datetime_0'] = '2016-02-16'
resp.form['start_datetime_1'] = '17:00'
resp.form['publication_date'] = '2020-05-11'
resp.form['duration'].value = 45
resp.form['places'] = 20
@ -1256,11 +1260,11 @@ def test_edit_event_as_manager(app, manager_user):
agenda.save()
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click('Feb. 15, 2016, 5 p.m.')
assert resp.form['start_datetime$date'].value == '2016-02-15'
assert resp.form['start_datetime$time'].value == '17:00'
assert resp.form['start_datetime_0'].value == '2016-02-15'
assert resp.form['start_datetime_1'].value == '17:00'
assert resp.form['publication_date'].value == '2020-05-11'
resp.form['start_datetime$date'] = '2016-02-16'
resp.form['start_datetime$time'] = '17:00'
resp.form['start_datetime_0'] = '2016-02-16'
resp.form['start_datetime_1'] = '17:00'
resp.form['publication_date'] = ''
resp.form['places'] = 20
resp = resp.form.submit()
@ -1884,10 +1888,10 @@ def test_meetings_agenda_add_time_period_exception(app, admin_user):
tomorrow = make_aware(today + datetime.timedelta(days=1))
dt_format = '%Y-%m-%d %H:%M'
resp.form['label'] = 'Exception 1'
resp.form['start_datetime$date'] = tomorrow.strftime('%Y-%m-%d')
resp.form['start_datetime$time'] = '08:00'
resp.form['end_datetime$date'] = tomorrow.strftime('%Y-%m-%d')
resp.form['end_datetime$time'] = '16:00'
resp.form['start_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
resp.form['start_datetime_1'] = '08:00'
resp.form['end_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
resp.form['end_datetime_1'] = '16:00'
resp = resp.form.submit().follow()
assert TimePeriodException.objects.count() == 1
time_period_exception = TimePeriodException.objects.first()
@ -1901,10 +1905,10 @@ def test_meetings_agenda_add_time_period_exception(app, admin_user):
resp = resp.click('Add a time period exception', index=1)
future = tomorrow + datetime.timedelta(days=15)
resp.form['label'] = 'Exception 2'
resp.form['start_datetime$date'] = future.strftime('%Y-%m-%d')
resp.form['start_datetime$time'] = '00:00'
resp.form['end_datetime$date'] = future.strftime('%Y-%m-%d')
resp.form['end_datetime$time'] = '16:00'
resp.form['start_datetime_0'] = future.strftime('%Y-%m-%d')
resp.form['start_datetime_1'] = '00:00'
resp.form['end_datetime_0'] = future.strftime('%Y-%m-%d')
resp.form['end_datetime_1'] = '16:00'
resp = resp.form.submit().follow()
assert TimePeriodException.objects.count() == 2
assert 'Exception 1' in resp.text
@ -1932,10 +1936,10 @@ def test_meetings_agenda_add_time_period_exception_when_booking_exists(app, admi
# fields should be marked with errors
assert resp.text.count('This field is required.') == 2
# try again with data in fields
resp.form['start_datetime$date'] = '2017-05-22'
resp.form['start_datetime$time'] = '08:00'
resp.form['end_datetime$date'] = '2017-05-26'
resp.form['end_datetime$time'] = '17:30'
resp.form['start_datetime_0'] = '2017-05-22'
resp.form['start_datetime_1'] = '08:00'
resp.form['end_datetime_0'] = '2017-05-26'
resp.form['end_datetime_1'] = '17:30'
resp = resp.form.submit().follow()
assert 'Exception added. Note: one or several bookings exists within this time slot.' in resp.text
assert TimePeriodException.objects.count() == 1
@ -1957,10 +1961,10 @@ def test_meetings_agenda_add_time_period_exception_when_cancelled_booking_exists
login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
resp = resp.click('Add a time period exception')
resp.form['start_datetime$date'] = '2017-05-22'
resp.form['start_datetime$time'] = '08:00'
resp.form['end_datetime$date'] = '2017-05-26'
resp.form['end_datetime$time'] = '17:30'
resp.form['start_datetime_0'] = '2017-05-22'
resp.form['start_datetime_1'] = '08:00'
resp.form['end_datetime_0'] = '2017-05-26'
resp.form['end_datetime_1'] = '17:30'
resp = resp.form.submit().follow()
assert 'Exception added. Note: one or several bookings exists within this time slot.' not in resp.text
assert TimePeriodException.objects.count() == 1
@ -1969,10 +1973,10 @@ def test_meetings_agenda_add_time_period_exception_when_cancelled_booking_exists
def test_meetings_agenda_add_invalid_time_period_exception():
form = TimePeriodExceptionForm(
data={
'start_datetime$date': '2017-05-26',
'start_datetime$time': '17:30',
'end_datetime$date': '2017-05-22',
'end_datetime$time': '08:00',
'start_datetime_0': '2017-05-26',
'start_datetime_1': '17:30',
'end_datetime_0': '2017-05-22',
'end_datetime_1': '08:00',
}
)
assert form.is_valid() is False
@ -1981,10 +1985,10 @@ def test_meetings_agenda_add_invalid_time_period_exception():
# start_datetime is invalid
form = TimePeriodExceptionForm(
data={
'start_datetime$date': '2017-05-26',
'start_datetime$time': 'foo',
'end_datetime$date': '2017-05-22',
'end_datetime$time': '08:00',
'start_datetime_0': '2017-05-26',
'start_datetime_1': 'foo',
'end_datetime_0': '2017-05-22',
'end_datetime_1': '08:00',
}
)
assert form.is_valid() is False
@ -1992,10 +1996,10 @@ def test_meetings_agenda_add_invalid_time_period_exception():
# end_datetime is invalid
form = TimePeriodExceptionForm(
data={
'start_datetime$date': '2017-05-26',
'start_datetime$time': '17:30',
'end_datetime$date': 'bar',
'end_datetime$time': '08:00',
'start_datetime_0': '2017-05-26',
'start_datetime_1': '17:30',
'end_datetime_0': 'bar',
'end_datetime_1': '08:00',
}
)
assert form.is_valid() is False
@ -2015,10 +2019,10 @@ def test_meetings_agenda_delete_time_period_exception(app, admin_user):
tomorrow = make_aware(today + datetime.timedelta(days=15))
dt_format = '%Y-%m-%d %H:%M'
resp.form['label'] = 'Exception 1'
resp.form['start_datetime$date'] = tomorrow.strftime('%Y-%m-%d')
resp.form['start_datetime$time'] = '08:00'
resp.form['end_datetime$date'] = tomorrow.strftime('%Y-%m-%d')
resp.form['end_datetime$time'] = '16:00'
resp.form['start_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
resp.form['start_datetime_1'] = '08:00'
resp.form['end_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
resp.form['end_datetime_1'] = '16:00'
resp = resp.form.submit().follow()
assert TimePeriodException.objects.count() == 1
time_period_exception = TimePeriodException.objects.first()
@ -3099,8 +3103,8 @@ def test_agenda_view_edit_event(app, manager_user):
resp = app.get(event_url)
assert 'Options' in resp.text
resp = resp.click('Options')
resp.form['start_datetime$date'] = agenda.event_set.first().start_datetime.strftime('%Y-%m-%d')
resp.form['start_datetime$time'] = agenda.event_set.first().start_datetime.strftime('%H:%M')
resp.form['start_datetime_0'] = agenda.event_set.first().start_datetime.strftime('%Y-%m-%d')
resp.form['start_datetime_1'] = agenda.event_set.first().start_datetime.strftime('%H:%M')
resp = resp.form.submit(status=302).follow()
assert event_url == resp.request.url

View File

@ -9,7 +9,6 @@ from django.utils.timezone import now
import pytest
from chrono.manager.widgets import DateTimeWidget, TimeWidget
from chrono.agendas.models import Agenda
from chrono.agendas.models import Booking
from chrono.agendas.models import Desk
@ -19,11 +18,6 @@ from chrono.agendas.models import MeetingType
pytestmark = pytest.mark.django_db
def test_widgets_init():
DateTimeWidget()
TimeWidget()
def check_ignore_reason(event, value):
with connection.cursor() as cursor:
cursor.execute("SELECT _ignore_reason FROM agendas_event WHERE id = %s", [event.pk])