Skip to content

Commit

Permalink
fix: Hide last modified field in agenda when unavailable (#7722)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
microamp authored Aug 7, 2024
1 parent 9ef7bff commit b90820e
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 9 deletions.
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")
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

0 comments on commit b90820e

Please sign in to comment.