fix: Hide last modified field in agenda when unavailable (#7722)

* test: Update tests to check for Updated field in agenda.txt

* fix: Hide Updated in agenda.txt if too old

* test: Remove confusing tests on CSV agenda

* refactor: Make updated() return None when no valid timestamp found

* refactor: Remove walrus operator
This commit is contained in:
Sangho Na 2024-08-08 02:15:01 +12:00 committed by GitHub
parent 9ef7bff77c
commit b90820eb7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 61 additions and 9 deletions

View file

@ -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
}

View file

@ -369,13 +369,14 @@ class Meeting(models.Model):
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):

View file

@ -294,6 +294,8 @@ class MeetingTests(BaseMeetingTestCase):
(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")
self.assertContains(r, f"Updated {updated}")
# text, UTC
r = self.client.get(urlreverse(
@ -309,6 +311,16 @@ class MeetingTests(BaseMeetingTestCase):
(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")))
@ -859,6 +871,24 @@ class MeetingTests(BaseMeetingTestCase):
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()
@ -4952,7 +4982,23 @@ class InterimTests(TestCase):
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")
@ -4974,6 +5020,8 @@ class InterimTests(TestCase):
],
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)

View file

@ -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

View file

@ -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 %}