From 59b49c846b995972407975e61b02ef76d0a83b75 Mon Sep 17 00:00:00 2001 From: Henrik Levkowetz Date: Sat, 19 Dec 2020 22:55:11 +0000 Subject: [PATCH] Fixed a number of TimeSlot-related issues, in particular related to getting the correct date from a timeslot. Also fixed the displayed slot times in the new schedule editors to show local times, not UTC times. - Legacy-Id: 18785 --- ietf/meeting/helpers.py | 6 +-- ietf/meeting/tests_js.py | 44 ++++++++++--------- ietf/meeting/tests_views.py | 14 +++--- ietf/meeting/views.py | 26 +++++------ ietf/secr/meetings/forms.py | 3 ++ ietf/secr/meetings/views.py | 2 +- ietf/secr/proceedings/proc_utils.py | 2 +- ietf/templates/meeting/agenda.html | 2 +- ietf/templates/meeting/agenda.txt | 2 +- ietf/templates/meeting/diff_schedules.html | 6 +-- .../meeting/edit_meeting_schedule.html | 4 +- ...t_meeting_timeslots_and_misc_sessions.html | 2 +- ietf/templates/meeting/room-view.html | 2 +- ietf/templates/meeting/session_details.html | 4 +- ietf/templates/meeting/timeslot_edit.html | 2 +- .../migrations/0002_convert_timestamps.py | 2 +- ietf/utils/test_runner.py | 33 ++++++++++---- 17 files changed, 90 insertions(+), 66 deletions(-) diff --git a/ietf/meeting/helpers.py b/ietf/meeting/helpers.py index 345643de4..758742434 100644 --- a/ietf/meeting/helpers.py +++ b/ietf/meeting/helpers.py @@ -85,7 +85,7 @@ def build_all_agenda_slices(meeting): date_slices = {} for ts in meeting.timeslot_set.filter(type__in=['regular',]).order_by('time','name'): - ymd = ts.time.date() + ymd = ts.local_date() if ymd not in date_slices and ts.location != None: date_slices[ymd] = [] @@ -629,7 +629,7 @@ def send_interim_meeting_cancellation_notice(meeting): acronym=group.acronym, type=group.type.slug.upper(), date=meeting.date.strftime('%Y-%m-%d')) - start_time = session.official_timeslotassignment().timeslot.time.astimezone(meeting.tz()) + start_time = session.official_timeslotassignment().timeslot.local_start_time() end_time = start_time + session.requested_duration is_multi_day = session.meeting.session_set.with_current_status().filter(current_status='sched').count() > 1 template = 'meeting/interim_meeting_cancellation_notice.txt' @@ -646,7 +646,7 @@ def send_interim_meeting_cancellation_notice(meeting): def send_interim_session_cancellation_notice(session): """Sends an email that one session of a scheduled interim meeting has been cancelled.""" group = session.group - start_time = session.official_timeslotassignment().timeslot.time + start_time = session.official_timeslotassignment().timeslot.local_start_time() end_time = start_time + session.requested_duration (to_email, cc_list) = gather_address_lists('interim_cancelled',group=group) from_email = settings.INTERIM_ANNOUNCE_FROM_EMAIL_PROGRAM if group.type_id=='program' else settings.INTERIM_ANNOUNCE_FROM_EMAIL_DEFAULT diff --git a/ietf/meeting/tests_js.py b/ietf/meeting/tests_js.py index ec2efedbb..ffde1e060 100644 --- a/ietf/meeting/tests_js.py +++ b/ietf/meeting/tests_js.py @@ -2,38 +2,41 @@ # -*- coding: utf-8 -*- -import time import datetime -import shutil import os +import pytz import re +import shutil +import time + from unittest import skipIf import django from django.db.models import F from django.urls import reverse as urlreverse -from django.utils import timezone from django.utils.text import slugify #from django.test.utils import override_settings import debug # pyflakes:ignore +from ietf import settings from ietf.doc.factories import DocumentFactory from ietf.doc.models import State from ietf.group import colors -from ietf.person.models import Person -from ietf.group.models import Group from ietf.group.factories import GroupFactory +from ietf.group.models import Group from ietf.meeting.factories import SessionFactory -from ietf.meeting.test_data import make_meeting_test_data, make_interim_meeting from ietf.meeting.models import (Schedule, SchedTimeSessAssignment, Session, Room, TimeSlot, Constraint, ConstraintName, - Meeting, SchedulingEvent, SessionStatusName) + Meeting, SchedulingEvent, SessionStatusName, + Person) +from ietf.meeting.test_data import make_meeting_test_data, make_interim_meeting from ietf.meeting.utils import add_event_info_to_session_qs from ietf.utils.pipe import pipe from ietf.utils.test_runner import IetfLiveServerTestCase from ietf.utils.test_utils import assert_ical_response_is_valid -from ietf import settings +from ietf.utils.timezone import datetime_today_start + skip_selenium = False skip_message = "" @@ -102,7 +105,7 @@ class EditMeetingScheduleTests(MeetingTestCase): schedule = Schedule.objects.filter(meeting=meeting, owner__user__username="plain").first() room1 = Room.objects.get(name="Test Room") - slot1 = TimeSlot.objects.filter(meeting=meeting, location=room1).order_by('_time').first() + slot1 = TimeSlot.objects.filter(meeting=meeting, location=room1).order_by('time').first() room2 = Room.objects.create(meeting=meeting, name="Test Room2", capacity=1) room2.session_types.add('regular') @@ -265,14 +268,14 @@ class EditMeetingScheduleTests(MeetingTestCase): # hide timeslots self.driver.find_element_by_css_selector(".timeslot-group-toggles button").click() self.assertTrue(self.driver.find_element_by_css_selector("#timeslot-group-toggles-modal").is_displayed()) - self.driver.find_element_by_css_selector("#timeslot-group-toggles-modal [value=\"{}\"]".format("ts-group-{}-{}".format(slot2.time.strftime("%Y%m%d-%H%M"), int(slot2.duration.total_seconds() / 60)))).click() + self.driver.find_element_by_css_selector("#timeslot-group-toggles-modal [value=\"{}\"]".format("ts-group-{}-{}".format(slot2.local_start_time().strftime("%Y%m%d-%H%M"), int(slot2.duration.total_seconds() / 60)))).click() self.driver.find_element_by_css_selector("#timeslot-group-toggles-modal [data-dismiss=\"modal\"]").click() self.assertTrue(not self.driver.find_element_by_css_selector("#timeslot-group-toggles-modal").is_displayed()) # swap days - self.driver.find_element_by_css_selector(".day [data-target=\"#swap-days-modal\"][data-dayid=\"{}\"]".format(slot4.time.date().isoformat())).click() + self.driver.find_element_by_css_selector(".day [data-target=\"#swap-days-modal\"][data-dayid=\"{}\"]".format(slot4.local_date().isoformat())).click() self.assertTrue(self.driver.find_element_by_css_selector("#swap-days-modal").is_displayed()) - self.driver.find_element_by_css_selector("#swap-days-modal input[name=\"target_day\"][value=\"{}\"]".format(slot1.time.date().isoformat())).click() + self.driver.find_element_by_css_selector("#swap-days-modal input[name=\"target_day\"][value=\"{}\"]".format(slot1.local_date().isoformat())).click() self.driver.find_element_by_css_selector("#swap-days-modal button[type=\"submit\"]").click() self.assertTrue(self.driver.find_elements_by_css_selector('#timeslot{} #session{}'.format(slot4.pk, s1.pk))) @@ -734,13 +737,15 @@ class AgendaTests(MeetingTestCase): # for others (break, reg, other): # row-------- meeting_number = components[1] - start_time = datetime.datetime( + meeting = Meeting.objects.get(number=meeting_number) + tz = pytz.timezone(meeting.time_zone) + start_time = tz.localize(datetime.datetime( year=int(components[2]), month=int(components[3]), day=int(components[4]), hour=int(components[6][0:2]), minute=int(components[6][2:4]), - ) + )) # If labeled as plenary, it's plenary... if components[7] == '1plenary': session_type = 'plenary' @@ -756,8 +761,7 @@ class AgendaTests(MeetingTestCase): else: # Last component was a group, this is a regular session session_type = 'regular' - - meeting = Meeting.objects.get(number=meeting_number) + possible_assignments = SchedTimeSessAssignment.objects.filter( schedule__in=[meeting.schedule, meeting.schedule.base], timeslot__time=start_time, @@ -916,7 +920,7 @@ class InterimTests(MeetingTestCase): # Create a group with a plenary interim session for testing type filters somegroup = GroupFactory(acronym='sg', name='Some Group') - sg_interim = make_interim_meeting(somegroup, timezone.now().date() + datetime.timedelta(days=20)) + sg_interim = make_interim_meeting(somegroup, datetime_today_start() + datetime.timedelta(days=20)) sg_sess = sg_interim.session_set.first() sg_slot = sg_sess.timeslotassignments.first().timeslot sg_sess.type_id = 'plenary' @@ -946,7 +950,7 @@ class InterimTests(MeetingTestCase): Session.objects.filter( meeting__type_id='interim', timeslotassignments__schedule=F('meeting__schedule'), - timeslotassignments__timeslot__time__gte=datetime.datetime.today() + timeslotassignments__timeslot__time__gte=datetime_today_start() ) ).filter(current_status__in=('sched','canceled')) meetings = [] @@ -959,7 +963,7 @@ class InterimTests(MeetingTestCase): def all_ietf_meetings(self): meetings = Meeting.objects.filter( type_id='ietf', - date__gte=datetime.datetime.today()-datetime.timedelta(days=7) + date__gte=datetime_today_start()-datetime.timedelta(days=7) ) for m in meetings: m.calendar_label = 'IETF %s' % m.number @@ -1084,7 +1088,7 @@ class InterimTests(MeetingTestCase): expected_assignments = list(SchedTimeSessAssignment.objects.filter( schedule__in=expected_schedules, session__in=expected_interim_sessions, - timeslot__time__gte=timezone.now().date(), + timeslot__time__gte=datetime_today_start(), )) # The UID formats should match those in the upcoming.ics template expected_uids = [ diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index e12c2cc41..60e30072a 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -1421,8 +1421,8 @@ class EditTests(TestCase): r = self.client.post(url, { 'action': 'swapdays', - 'source_day': timeslots[0].time.date().isoformat(), - 'target_day': timeslots[2].time.date().isoformat(), + 'source_day': timeslots[0].local_date().isoformat(), + 'target_day': timeslots[2].local_date().isoformat(), }) self.assertResponseStatus(r, 302) @@ -1434,8 +1434,8 @@ class EditTests(TestCase): # swap back r = self.client.post(url, { 'action': 'swapdays', - 'source_day': timeslots[2].time.date().isoformat(), - 'target_day': timeslots[0].time.date().isoformat(), + 'source_day': timeslots[2].local_date().isoformat(), + 'target_day': timeslots[0].local_date().isoformat(), }) self.assertResponseStatus(r, 302) @@ -1469,7 +1469,7 @@ class EditTests(TestCase): break_slot = TimeSlot.objects.get(location=break_room, type='break') - room_row = q(".room-row[data-day=\"{}\"][data-room=\"{}\"]".format(break_slot.time.date().isoformat(), break_slot.location_id)) + room_row = q(".room-row[data-day=\"{}\"][data-room=\"{}\"]".format(break_slot.local_date().isoformat(), break_slot.location_id)) self.assertTrue(room_row) self.assertTrue(room_row.find("#timeslot{}".format(break_slot.pk))) @@ -1584,7 +1584,7 @@ class EditTests(TestCase): r = self.client.post(url, { 'timeslot': assignment.timeslot_id, - 'day': assignment.timeslot.time.date().isoformat(), + 'day': assignment.timeslot.local_date().isoformat(), 'time': assignment.timeslot.time.time().isoformat(), 'duration': assignment.timeslot.duration, 'location': assignment.timeslot.location_id, @@ -3248,7 +3248,7 @@ class InterimTests(TestCase): data.update(form_initial) r = self.client.post(url, data) if r.status_code != 302: - self.save_response(r) + self.debug_save_response(r) self.assertRedirects(r, urlreverse('ietf.meeting.views.interim_request_details', kwargs={'number': meeting.number})) self.assertEqual(len(outbox),length_before+1) self.assertIn('CHANGED', outbox[-1]['Subject']) diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 78c28d2b7..84858f814 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -654,8 +654,8 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None): source_day = swap_days_form.cleaned_data['source_day'] target_day = swap_days_form.cleaned_data['target_day'] - source_timeslots = [ts for ts in timeslots_qs if ts.time.date() == source_day] - target_timeslots = [ts for ts in timeslots_qs if ts.time.date() == target_day] + source_timeslots = [ts for ts in timeslots_qs if ts.local_date() == source_day] + target_timeslots = [ts for ts in timeslots_qs if ts.local_date() == target_day] swap_meeting_schedule_timeslot_assignments(schedule, source_timeslots, target_timeslots, target_day - source_day) return HttpResponseRedirect(request.get_full_path()) @@ -668,10 +668,10 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None): room_has_timeslots = set() for t in timeslots_qs: room_has_timeslots.add(t.location_id) - timeslots_by_room_and_day[(t.location_id, t.time.date())].append(t) + timeslots_by_room_and_day[(t.location_id, t.local_date())].append(t) days = [] - for day in sorted(set(t.time.date() for t in timeslots_qs)): + for day in sorted(set(t.local_date() for t in timeslots_qs)): room_timeslots = [] for r in rooms: if r.pk not in room_has_timeslots: @@ -694,8 +694,8 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None): # possible timeslot start/ends timeslot_groups = defaultdict(set) for ts in timeslots_qs: - ts.start_end_group = "ts-group-{}-{}".format(ts.time.strftime("%Y%m%d-%H%M"), int(ts.duration.total_seconds() / 60)) - timeslot_groups[ts.time.date()].add((ts.time, ts.end_time(), ts.start_end_group)) + ts.start_end_group = "ts-group-{}-{}".format(ts.local_start_time().strftime("%Y%m%d-%H%M"), int(ts.duration.total_seconds() / 60)) + timeslot_groups[ts.local_date()].add((ts.local_start_time(), ts.local_end_time(), ts.start_end_group)) # prepare sessions prepare_sessions_for_display(sessions) @@ -792,7 +792,7 @@ class TimeSlotForm(forms.Form): if timeslot: self.initial = { - 'day': timeslot.time.date(), + 'day': timeslot.local_date(), 'time': timeslot.time.time(), 'duration': timeslot.duration, 'location': timeslot.location_id, @@ -1033,7 +1033,7 @@ def edit_meeting_timeslots_and_misc_sessions(request, num=None, owner=None, name timeslots_by_day_and_room = defaultdict(list) for t in timeslot_qs: - timeslots_by_day_and_room[(t.time.date(), t.location_id)].append(t) + timeslots_by_day_and_room[(t.local_date(), t.location_id)].append(t) min_time = min([t.time.time() for t in timeslot_qs] + [datetime.time(8)]) max_time = max([t.end_time().time() for t in timeslot_qs] + [datetime.time(22)]) @@ -1567,7 +1567,7 @@ def agenda_by_room(request, num=None, name=None, owner=None): for day in assignments.dates('timeslot__time','day'): ss_by_day[day]=[] for ss in assignments.order_by('timeslot__location__functional_name','timeslot__location__name','timeslot__time'): - day = ss.timeslot.time.date() + day = ss.timeslot.local_date() ss_by_day[day].append(ss) return render(request,"meeting/agenda_by_room.html",{"meeting":meeting,"schedule":schedule,"ss_by_day":ss_by_day}) @@ -3233,8 +3233,8 @@ def interim_request_session_cancel(request, sessionid): messages.success(request, 'Interim meeting session cancelled') return redirect(interim_request_details, number=session.meeting.number) else: - session_time = session.official_timeslotassignment().timeslot.time - form = InterimCancelForm(initial={'group': group.acronym, 'date': session_time.date()}) + date = session.official_timeslotassignment().timeslot.local_date() + form = InterimCancelForm(initial={'group': group.acronym, 'date': date}) return render(request, "meeting/interim_request_cancel.html", { "form": form, @@ -3732,8 +3732,8 @@ def api_set_session_video_url(request): else: return err(400, "URL is the same") else: - time = session.official_timeslotassignment().timeslot.time - title = 'Video recording for %s on %s at %s' % (acronym, time.date(), time.time()) + timeslot = session.official_timeslotassignment().timeslot + title = 'Video recording for %s on %s at %s' % (acronym, timeslot.local_date(), timeslot.time.time()) create_recording(session, url, title=title, user=user) else: return err(405, "Method not allowed") diff --git a/ietf/secr/meetings/forms.py b/ietf/secr/meetings/forms.py index 9de3219a3..99436ea01 100644 --- a/ietf/secr/meetings/forms.py +++ b/ietf/secr/meetings/forms.py @@ -30,6 +30,9 @@ def get_next_slot(slot): aren't any. You must check availability of the slot as we sometimes need to get the next slot whether it's available or not. For use with combine option. ''' + # timezone-aware note: The following works because the slot times are + # saved as if they were local timezone-naive times, even if Django sees + # them as UTC times when USE_TZ == True. same_day_slots = TimeSlot.objects.filter(meeting=slot.meeting,location=slot.location,time__day=slot.time.day).order_by('time') try: i = list(same_day_slots).index(slot) diff --git a/ietf/secr/meetings/views.py b/ietf/secr/meetings/views.py index 0b6d10355..322d4e8f5 100644 --- a/ietf/secr/meetings/views.py +++ b/ietf/secr/meetings/views.py @@ -553,7 +553,7 @@ def misc_session_edit(request, meeting_id, schedule_name, slot_id): else: # we need to pass the session to the form in order to disallow changing # of group after materials have been uploaded - delta = slot.time.date() - meeting.date + delta = slot.local_date() - meeting.date initial = {'location':slot.location, 'group':session.group, 'name':session.name, diff --git a/ietf/secr/proceedings/proc_utils.py b/ietf/secr/proceedings/proc_utils.py index 3ad85b70f..13a6fc8ac 100644 --- a/ietf/secr/proceedings/proc_utils.py +++ b/ietf/secr/proceedings/proc_utils.py @@ -147,7 +147,7 @@ def create_recording(session, url, title=None, user=None): ''' sequence = get_next_sequence(session.group,session.meeting,'recording') name = 'recording-{}-{}-{}'.format(session.meeting.number,session.group.acronym,sequence) - time = session.official_timeslotassignment().timeslot.time.strftime('%Y-%m-%d %H:%M') + time = session.official_timeslotassignment().timeslot.local_start_time().strftime('%Y-%m-%d %H:%M') if not title: if url.endswith('mp3'): title = 'Audio recording for {}'.format(time) diff --git a/ietf/templates/meeting/agenda.html b/ietf/templates/meeting/agenda.html index 05ee0f6d3..e463cb092 100644 --- a/ietf/templates/meeting/agenda.html +++ b/ietf/templates/meeting/agenda.html @@ -284,7 +284,7 @@ {% if "-utc" in request.path %} {{ item.session.rescheduled_to.utc_start_time|date:"l G:i"|upper }}-{{ item.session.rescheduled_to.utc_end_time|date:"G:i" }} {% else %} - {{ item.session.rescheduled_to.time|date:"l G:i"|upper }}-{{ item.session.rescheduled_to.end_time|date:"G:i" }} + {{ item.session.rescheduled_to.local_start_time|date:"l G:i"|upper }}-{{ item.session.rescheduled_to.local_end_time|date:"G:i" }} {% endif %} {% endif %} diff --git a/ietf/templates/meeting/agenda.txt b/ietf/templates/meeting/agenda.txt index 9a3a1df2c..38185bed7 100644 --- a/ietf/templates/meeting/agenda.txt +++ b/ietf/templates/meeting/agenda.txt @@ -23,7 +23,7 @@ {% endif %}{% if item.timeslot.type_id == 'regular' %}{% if item.session.historic_group %}{% ifchanged %} {{ item.timeslot.time_desc }} {{ item.timeslot.name }} -{% endifchanged %}{{ item.timeslot.location.name|ljust:14 }} {{ item.session.historic_group.historic_parent.acronym|upper|ljust:4 }} {{ item.session.historic_group.acronym|ljust:10 }} {{ item.session.historic_group.name }} {% if item.session.historic_group.state_id == "bof" %}BOF{% elif item.session.historic_group.type_id == "wg" %}WG{% endif %}{% if item.session.agenda_note %} - {{ item.session.agenda_note }}{% endif %}{% if item.session.current_status == 'canceled' %} *** CANCELLED ***{% elif item.session.current_status == 'resched' %} *** RESCHEDULED{% if item.session.rescheduled_to %} TO {{ item.session.rescheduled_to.time|date:"l G:i"|upper }}-{{ item.session.rescheduled_to.end_time|date:"G:i" }}{% endif %} ***{% endif %} +{% endifchanged %}{{ item.timeslot.location.name|ljust:14 }} {{ item.session.historic_group.historic_parent.acronym|upper|ljust:4 }} {{ item.session.historic_group.acronym|ljust:10 }} {{ item.session.historic_group.name }} {% if item.session.historic_group.state_id == "bof" %}BOF{% elif item.session.historic_group.type_id == "wg" %}WG{% endif %}{% if item.session.agenda_note %} - {{ item.session.agenda_note }}{% endif %}{% if item.session.current_status == 'canceled' %} *** CANCELLED ***{% elif item.session.current_status == 'resched' %} *** RESCHEDULED{% if item.session.rescheduled_to %} TO {{ item.session.rescheduled_to.local_start_time|date:"l G:i"|upper }}-{{ item.session.rescheduled_to.local_end_time|date:"G:i" }}{% endif %} ***{% endif %} {% endif %}{% endif %}{% if item.timeslot.type.slug == "break" %} {{ item.timeslot.time_desc }} {{ item.timeslot.name }}{% if schedule.meeting.break_area and item.timeslot.show_location %} - {{ schedule.meeting.break_area }}{% endif %}{% endif %}{% if item.timeslot.type.slug == "other" %} {{ item.timeslot.time_desc }} {{ item.timeslot.name }} - {{ item.timeslot.location.name }}{% endif %}{% endfor %} diff --git a/ietf/templates/meeting/diff_schedules.html b/ietf/templates/meeting/diff_schedules.html index dce06e921..2a6c5d4a7 100644 --- a/ietf/templates/meeting/diff_schedules.html +++ b/ietf/templates/meeting/diff_schedules.html @@ -22,11 +22,11 @@ {% if d.change == 'schedule' %} - Scheduled {{ d.session.session_label }} to {{ d.to.time|date:"l G:i" }} at {{ d.to.location.name }} + Scheduled {{ d.session.session_label }} to {{ d.to.local_start_time|date:"l G:i" }} at {{ d.to.location.name }} {% elif d.change == 'move' %} - Moved {{ d.session.session_label }} from {{ d.from.time|date:"l G:i" }} at {{ d.from.location.name }} to {{ d.to.time|date:"l G:i" }} at {{ d.to.location.name }} + Moved {{ d.session.session_label }} from {{ d.from.local_start_time|date:"l G:i" }} at {{ d.from.location.name }} to {{ d.to.local_start_time|date:"l G:i" }} at {{ d.to.location.name }} {% elif d.change == 'unschedule' %} - Unscheduled {{ d.session.session_label }} from {{ d.from.time|date:"l G:i" }} at {{ d.from.location.name }} + Unscheduled {{ d.session.session_label }} from {{ d.from.local_start_time|date:"l G:i" }} at {{ d.from.location.name }} {% endif %} diff --git a/ietf/templates/meeting/edit_meeting_schedule.html b/ietf/templates/meeting/edit_meeting_schedule.html index 47b252c54..b9abf1bdd 100644 --- a/ietf/templates/meeting/edit_meeting_schedule.html +++ b/ietf/templates/meeting/edit_meeting_schedule.html @@ -85,9 +85,9 @@
{% for t in timeslots %} -
+
- {{ t.time|date:"G:i" }} - {{ t.end_time|date:"G:i" }} + {{ t.local_start_time|date:"G:i" }} - {{ t.local_end_time|date:"G:i" }}
diff --git a/ietf/templates/meeting/edit_meeting_timeslots_and_misc_sessions.html b/ietf/templates/meeting/edit_meeting_timeslots_and_misc_sessions.html index a83b31bd9..168143239 100644 --- a/ietf/templates/meeting/edit_meeting_timeslots_and_misc_sessions.html +++ b/ietf/templates/meeting/edit_meeting_timeslots_and_misc_sessions.html @@ -62,7 +62,7 @@ {{ t.type.name }} {% endif %} {% endfor %} - {{ t.time|date:"G:i" }}-{{ t.end_time|date:"G:i" }} + {{ t.local_start_time|date:"G:i" }}-{{ t.local_end_time|date:"G:i" }}
{% endfor %}
diff --git a/ietf/templates/meeting/room-view.html b/ietf/templates/meeting/room-view.html index 20a304f54..e003a9525 100644 --- a/ietf/templates/meeting/room-view.html +++ b/ietf/templates/meeting/room-view.html @@ -20,7 +20,7 @@ {% for slot in unavailable %} if (room_names.indexOf("{{slot.get_hidden_location}}") >= 0 ) { - items.push({room_index:room_names.indexOf("{{slot.get_hidden_location}}"),day:{{slot.day}}, delta_from_beginning:{{slot.delta_from_beginning}},time:"{{slot.time|date:"Hi"}}-{{slot.end_time|date:"Hi"}}", verbose_time:"{{slot.time|date:"D M d Hi"}}-{{slot.end_time|date:"Hi"}}",duration:{{slot.duration.total_seconds}}, type:"{{slot.type}}", name:"Unavailable", dayname:"{{ slot.time|date:"l"|upper }}, {{ slot.time|date:"F j, Y" }}" }); + items.push({room_index:room_names.indexOf("{{slot.get_hidden_location}}"),day:{{slot.day}}, delta_from_beginning:{{slot.delta_from_beginning}},time:"{{slot.local_start_time|date:"Hi"}}-{{slot.local_end_time|date:"Hi"}}", verbose_time:"{{slot.local_start_time|date:"D M d Hi"}}-{{slot.local_end_time|date:"Hi"}}",duration:{{slot.duration.total_seconds}}, type:"{{slot.type}}", name:"Unavailable", dayname:"{{ slot.local_start_time|date:"l"|upper }}, {{ slot.local_start_time|date:"F j, Y" }}" }); } {% endfor %} {% for ss in assignments %} diff --git a/ietf/templates/meeting/session_details.html b/ietf/templates/meeting/session_details.html index 17cd98887..252d0cc17 100644 --- a/ietf/templates/meeting/session_details.html +++ b/ietf/templates/meeting/session_details.html @@ -55,9 +55,9 @@
{% for s in pending_suggestions %} {% if can_manage_materials %} -

{{s.submitter}} - {{s.title}} ({{s.time}})

+

{{s.submitter}} - {{s.title}} ({{s.local_start_time}})

{% else %} -

{{s.title}} ({{s.time}})

+

{{s.title}} ({{s.local_start_time}})

{% endif %} {% endfor %}
diff --git a/ietf/templates/meeting/timeslot_edit.html b/ietf/templates/meeting/timeslot_edit.html index d75ad70d3..05dd06b33 100644 --- a/ietf/templates/meeting/timeslot_edit.html +++ b/ietf/templates/meeting/timeslot_edit.html @@ -33,7 +33,7 @@ {% for day in time_slices %} {% for slot in slot_slices|lookup:day %} - {{slot.time|date:'Hi'}}-{{slot.end_time|date:'Hi'}} + {{slot.local_start_time|date:'Hi'}}-{{slot.local_end_time|date:'Hi'}} {% endfor %} {% endfor %} diff --git a/ietf/utils/migrations/0002_convert_timestamps.py b/ietf/utils/migrations/0002_convert_timestamps.py index 7e37954cb..b97970ca3 100644 --- a/ietf/utils/migrations/0002_convert_timestamps.py +++ b/ietf/utils/migrations/0002_convert_timestamps.py @@ -94,7 +94,7 @@ def convert(apps, tzfrom, tzto): if values and inv_count: with open(datafn, "w") as f: json.dump(values, f) - note(f" Saved {inv_count} new unconverted datetime field values") + note(f" Saved {inv_count:,} new unconverted datetime field values") else: note(" No new unconverted datetime field values") if error: diff --git a/ietf/utils/test_runner.py b/ietf/utils/test_runner.py index fc74f4b44..74e4e56b6 100644 --- a/ietf/utils/test_runner.py +++ b/ietf/utils/test_runner.py @@ -35,23 +35,26 @@ import datetime +import factory.random +import gzip +import importlib +import inspect import io -import re +import json import os +import pytz +import re +import socket import sys import time -import json -import pytz -import importlib -import socket -import gzip import unittest -import factory.random + from fnmatch import fnmatch from coverage.report import Reporter from coverage.results import Numbers from coverage.misc import NotPython +from unittest.util import strclass import django from django.conf import settings @@ -806,4 +809,18 @@ class IetfLiveServerTestCase(StaticLiveServerTestCase): super(IetfLiveServerTestCase, cls).tearDownClass() set_coverage_checking(True) - + def __str__(self): + return u"%s (%s.%s)" % (self._testMethodName, strclass(self.__class__),self._testMethodName) + + def debug_save_response(self, r): + """ + This is intended as a debug help, to be inserted whenever one wants + to save a page response in a test case; not for production. + """ + stack = inspect.stack() # stack[0] is the current frame + caller = stack[1] + fn = caller.function + '.html' + with open(fn, 'bw') as f: + f.write(r.content) + sys.stderr.write(f'Wrote response to {fn}\n') + \ No newline at end of file