Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/agenda/Agenda.vue
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ const meetingUpdated = computed(() => {
if (!agendaStore.meeting.updated) { return false }

const updatedDatetime = DateTime.fromISO(agendaStore.meeting.updated).setZone(agendaStore.timezone)
if (!updatedDatetime.isValid || updatedDatetime < DateTime.fromISO('1980-01-01')) {
if (!updatedDatetime.isValid) {
return false
}

Expand Down
13 changes: 7 additions & 6 deletions ietf/meeting/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,13 +369,14 @@ def vtimezone(self):

def updated(self):
# should be Meeting.modified, but we don't have that
min_time = pytz.utc.localize(datetime.datetime(1970, 1, 1, 0, 0, 0))
timeslots_updated = self.timeslot_set.aggregate(Max('modified'))["modified__max"] or min_time
sessions_updated = self.session_set.aggregate(Max('modified'))["modified__max"] or min_time
assignments_updated = min_time
timeslots_updated = self.timeslot_set.aggregate(Max('modified'))["modified__max"]
sessions_updated = self.session_set.aggregate(Max('modified'))["modified__max"]
assignments_updated = None
if self.schedule:
assignments_updated = SchedTimeSessAssignment.objects.filter(schedule__in=[self.schedule, self.schedule.base if self.schedule else None]).aggregate(Max('modified'))["modified__max"] or min_time
return max(timeslots_updated, sessions_updated, assignments_updated)
assignments_updated = SchedTimeSessAssignment.objects.filter(schedule__in=[self.schedule, self.schedule.base if self.schedule else None]).aggregate(Max('modified'))["modified__max"]
dts = [timeslots_updated, sessions_updated, assignments_updated]
valid_only = [dt for dt in dts if dt is not None]
return max(valid_only) if valid_only else None

@memoize
def previous_meeting(self):
Expand Down
50 changes: 49 additions & 1 deletion ietf/meeting/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ def test_meeting_agenda(self):
(slot.time + slot.duration).astimezone(meeting.tz()).strftime("%H%M"),
))
self.assertContains(r, f"shown in the {meeting.tz()} time zone")
updated = meeting.updated().astimezone(meeting.tz()).strftime("%Y-%m-%d %H:%M:%S %Z")
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please double check for me that this isn't prone to race condition. Same with line 314 below. Otherwise, I'm happy to patch it with a mock return value instead of directly calling meeting.updated().

P.S. I encountered some errors locally earlier, but I haven't been able to reproduce them since, which made me think that it might be related to race condition.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the tests all run in a single thread in a single process for now - you can't be fighting a race.

It would be nice to be able to use threading, but we have dependencies that would have to change (and we would have to rewrite our custom harness around the django test framework.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Maybe it was a bug I accidentally introduced while updating the code locally. It doesn't appear to be there anymore.

Faster tests would be nice in the future.

self.assertContains(r, f"Updated {updated}")

# text, UTC
r = self.client.get(urlreverse(
Expand All @@ -309,6 +311,16 @@ def test_meeting_agenda(self):
(slot.time + slot.duration).astimezone(datetime.timezone.utc).strftime("%H%M"),
))
self.assertContains(r, "shown in UTC")
updated = meeting.updated().astimezone(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S %Z")
self.assertContains(r, f"Updated {updated}")

# text, invalid updated (none)
with patch("ietf.meeting.models.Meeting.updated", return_value=None):
r = self.client.get(urlreverse(
"ietf.meeting.views.agenda_plain",
kwargs=dict(num=meeting.number, ext=".txt", utc="-utc"),
))
self.assertNotContains(r, "Updated ")

# future meeting, no agenda
r = self.client.get(urlreverse("ietf.meeting.views.agenda_plain", kwargs=dict(num=future_meeting.number, ext=".txt")))
Expand Down Expand Up @@ -859,6 +871,24 @@ def test_important_dates_ical(self):
for d in meeting.importantdate_set.all():
self.assertContains(r, d.date.isoformat())

updated = meeting.updated()
self.assertIsNotNone(updated)
expected_updated = updated.astimezone(datetime.timezone.utc).strftime("%Y%m%dT%H%M%SZ")
self.assertContains(r, f"DTSTAMP:{expected_updated}")
dtstamps_count = r.content.decode("utf-8").count(f"DTSTAMP:{expected_updated}")
self.assertEqual(dtstamps_count, meeting.importantdate_set.count())

# With default cached_updated, 1970-01-01
with patch("ietf.meeting.models.Meeting.updated", return_value=None):
r = self.client.get(url)
for d in meeting.importantdate_set.all():
self.assertContains(r, d.date.isoformat())

expected_updated = "19700101T000000Z"
self.assertContains(r, f"DTSTAMP:{expected_updated}")
dtstamps_count = r.content.decode("utf-8").count(f"DTSTAMP:{expected_updated}")
self.assertEqual(dtstamps_count, meeting.importantdate_set.count())

def test_group_ical(self):
meeting = make_meeting_test_data()
s1 = Session.objects.filter(meeting=meeting, group__acronym="mars").first()
Expand Down Expand Up @@ -4952,7 +4982,23 @@ def test_upcoming_ical(self):
expected_event_count=len(expected_event_summaries))
self.assertNotContains(r, 'Remote instructions:')

def test_upcoming_ical_filter(self):
updated = meeting.updated()
self.assertIsNotNone(updated)
expected_updated = updated.astimezone(datetime.timezone.utc).strftime("%Y%m%dT%H%M%SZ")
self.assertContains(r, f"DTSTAMP:{expected_updated}")

# With default cached_updated, 1970-01-01
with patch("ietf.meeting.models.Meeting.updated", return_value=None):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)

self.assertEqual(meeting.type_id, "ietf")

expected_updated = "19700101T000000Z"
self.assertEqual(1, r.content.decode("utf-8").count(f"DTSTAMP:{expected_updated}"))

@patch("ietf.meeting.utils.preprocess_meeting_important_dates")
def test_upcoming_ical_filter(self, mock_preprocess_meeting_important_dates):
# Just a quick check of functionality - details tested by test_js.InterimTests
make_meeting_test_data(create_interims=True)
url = urlreverse("ietf.meeting.views.upcoming_ical")
Expand All @@ -4974,6 +5020,8 @@ def test_upcoming_ical_filter(self):
],
expected_event_count=2)

# Verify preprocess_meeting_important_dates isn't being called
mock_preprocess_meeting_important_dates.assert_not_called()

def test_upcoming_json(self):
make_meeting_test_data(create_interims=True)
Expand Down
3 changes: 2 additions & 1 deletion ietf/meeting/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,8 @@ def bulk_create_timeslots(meeting, times, locations, other_props):

def preprocess_meeting_important_dates(meetings):
for m in meetings:
m.cached_updated = m.updated()
# cached_updated must be present, set it to 1970-01-01 if necessary
m.cached_updated = m.updated() or pytz.utc.localize(datetime.datetime(1970, 1, 1, 0, 0, 0))
m.important_dates = m.importantdate_set.prefetch_related("name")
for d in m.important_dates:
d.midnight_cutoff = "UTC 23:59" in d.name.name
Expand Down
2 changes: 2 additions & 0 deletions ietf/templates/meeting/agenda.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
{% filter center:72 %}{{ schedule.meeting.agenda_info_note|striptags|wordwrap:72|safe }}{% endfilter %}
{% endif %}
{% filter center:72 %}{{ schedule.meeting.date|date:"F j" }}-{% if schedule.meeting.date.month != schedule.meeting.end_date.month %}{{ schedule.meeting.end_date|date:"F " }}{% endif %}{{ schedule.meeting.end_date|date:"j, Y" }}{% endfilter %}
{% if updated %}
{% filter center:72 %}Updated {{ updated|date:"Y-m-d H:i:s T" }}{% endfilter %}
{% endif %}

{% filter center:72 %}IETF agendas are subject to change, up to and during the meeting.{% endfilter %}
{% filter center:72 %}Times are shown in {% if display_timezone.lower == "utc" %}UTC{% else %}the {{ display_timezone }} time zone{% endif %}.{% endfilter %}
Expand Down