From 4f0f71b0ba1e829b5972cdd8658765e706cbf25e Mon Sep 17 00:00:00 2001 From: Rudi Matz Date: Sat, 1 Nov 2025 16:38:31 -0400 Subject: [PATCH 1/3] refactor: use ical for important-dates --- ietf/meeting/views.py | 79 +++++++++++++++++-- ietf/templates/meeting/important_dates.ics | 5 -- .../meeting/important_dates_for_meeting.ics | 24 ------ 3 files changed, 74 insertions(+), 34 deletions(-) delete mode 100644 ietf/templates/meeting/important_dates.ics delete mode 100644 ietf/templates/meeting/important_dates_for_meeting.ics diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 69635d6219..1b9d957ab1 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -4432,6 +4432,78 @@ def upcoming_ical(request): response['Content-Disposition'] = 'attachment; filename="upcoming.ics"' return response +def render_important_dates_ical(meetings, request): + """Generate important dates using the icalendar library""" + cal = Calendar() + cal.add("prodid", "-//IETF//datatracker.ietf.org ical importantdates//EN") + cal.add("version", "2.0") + cal.add("method", "PUBLISH") + + for meeting in meetings: + for important_date in meeting.important_dates: + event = Event() + event.add("uid", f"ietf-{meeting.number}-{important_date.name_id}-{important_date.date.isoformat()}") + event.add("summary", f"IETF {meeting.number}: {important_date.name.name}") + event.add("class", "PUBLIC") + + if not important_date.midnight_cutoff: + event.add("dtstart", important_date.date) + else: + event.add("dtstart", datetime.datetime.combine(important_date.date, datetime.time(23, 59, 0, tzinfo=pytz.UTC))) + + event.add("transp", "TRANSPARENT") + event.add("dtstamp", meeting.cached_updated) + description_lines = [important_date.name.desc] + if important_date.name.slug in ('openreg', 'earlybird'): + description_lines.append("Register here: https://www.ietf.org/how/meetings/register/") + if important_date.name.slug == 'opensched': + description_lines.append("To request a Working Group session, use the IETF Meeting Session Request Tool:") + description_lines.append(f"{request.scheme}://{request.get_host()}{reverse('ietf.meeting.views_session_request.list_view')}") + description_lines.append("If you are working on a BOF request, it is highly recommended to tell the IESG") + description_lines.append("now by sending an email to iesg@ietf.org") + description_lines.append("to get advance help with the request.") + if important_date.name.slug == 'cutoffwgreq': + description_lines.append("To request a Working Group session, use the IETF Meeting Session Request Tool:") + description_lines.append(f"{request.scheme}://{request.get_host()}{reverse('ietf.meeting.views_session_request.list_view')}") + if important_date.name.slug == 'cutoffbofreq': + description_lines.append("To request a BOF, please see instructions on Requesting a BOF:") + description_lines.append("https://www.ietf.org/how/bofs/bof-procedures/") + if important_date.name.slug == 'idcutoff': + description_lines.append("Upload using the I-D Submission Tool:") + description_lines.append(f"{request.scheme}://{request.get_host()}{reverse('ietf.submit.views.upload_submission')}") + if important_date.name.slug in ('draftwgagenda', 'revwgagenda', 'procsub', 'revslug'): + description_lines.append("Upload using the Meeting Materials Management Tool:") + description_lines.append(f"{request.scheme}://{request.get_host()}{reverse('ietf.meeting.views.materials', kwargs={'num': meeting.number})}") + + event.add("description", "\n".join(description_lines)) + cal.add_component(event) + + # {% for d in meeting.important_dates %}BEGIN:VEVENT + # UID:ietf-{{ meeting.number }}-{{ d.name_id }}-{{ d.date.isoformat }} + # SUMMARY:IETF {{ meeting.number }}: {{ d.name.name }} + # CLASS:PUBLIC + # DTSTART{% if not d.midnight_cutoff %};VALUE=DATE{% endif %}:{{ d.date|date:"Ymd" }}{% if d.midnight_cutoff %}235900Z{% endif %} + # DTSTAMP{% ics_date_time meeting.cached_updated|utc 'utc' %} + # TRANSP:TRANSPARENT + # DESCRIPTION:{{ d.name.desc }}{% if first and d.name.slug == 'openreg' or first and d.name.slug == 'earlybird' %}\n + # Register here: https://www.ietf.org/how/meetings/register/{% endif %}{% if d.name.slug == 'opensched' %}\n + # To request a Working Group session, use the IETF Meeting Session Request Tool:\n + # {{ request.scheme }}://{{ request.get_host}}{% url 'ietf.meeting.views_session_request.list_view' %}\n + # If you are working on a BOF request, it is highly recommended to tell the IESG\n + # now by sending an email to iesg@ietf.org to get advance help with the request.{% endif %}{% if d.name.slug == 'cutoffwgreq' %}\n + # To request a Working Group session, use the IETF Meeting Session Request Tool:\n + # {{ request.scheme }}://{{ request.get_host }}{% url 'ietf.meeting.views_session_request.list_view' %}{% endif %}{% if d.name.slug == 'cutoffbofreq' %}\n + # To request a BOF, please see instructions on Requesting a BOF:\n + # https://www.ietf.org/how/bofs/bof-procedures/{% endif %}{% if d.name.slug == 'idcutoff' %}\n + # Upload using the I-D Submission Tool:\n + # {{ request.scheme }}://{{ request.get_host }}{% url 'ietf.submit.views.upload_submission' %}{% endif %}{% if d.name.slug == 'draftwgagenda' or d.name.slug == 'revwgagenda' or d.name.slug == 'procsub' or d.name.slug == 'revslug' %}\n + # Upload using the Meeting Materials Management Tool:\n + # {{ request.scheme }}://{{ request.get_host }}{% url 'ietf.meeting.views.materials' num=meeting.number %}{% endif %} + # END:VEVENT + # {% endfor %} + + + return cal.to_ical().decode("utf-8") def upcoming_json(request): '''Return Upcoming meetings in json format''' @@ -5050,11 +5122,8 @@ def important_dates(request, num=None, output_format=None): if output_format == 'ics': preprocess_meeting_important_dates(meetings) - ics = render_to_string('meeting/important_dates.ics', { - 'meetings': meetings, - }, request=request) - # icalendar response file should have '\r\n' line endings per RFC5545 - response = HttpResponse(parse_ical_line_endings(ics), content_type='text/calendar') + response = HttpResponse(render_important_dates_ical(meetings, request), + content_type='text/calendar') response['Content-Disposition'] = 'attachment; filename="important-dates.ics"' return response diff --git a/ietf/templates/meeting/important_dates.ics b/ietf/templates/meeting/important_dates.ics deleted file mode 100644 index 35079e01eb..0000000000 --- a/ietf/templates/meeting/important_dates.ics +++ /dev/null @@ -1,5 +0,0 @@ -{% load humanize %}{% autoescape off %}{% load ietf_filters %}BEGIN:VCALENDAR -VERSION:2.0 -METHOD:PUBLISH -PRODID:-//IETF//datatracker.ietf.org ical importantdates//EN -{% for meeting in meetings %}{% include "meeting/important_dates_for_meeting.ics" %}{% endfor %}END:VCALENDAR{% endautoescape %} diff --git a/ietf/templates/meeting/important_dates_for_meeting.ics b/ietf/templates/meeting/important_dates_for_meeting.ics deleted file mode 100644 index e6d403da93..0000000000 --- a/ietf/templates/meeting/important_dates_for_meeting.ics +++ /dev/null @@ -1,24 +0,0 @@ -{# Copyright The IETF Trust 2025, All Rights Reserved #} -{% load tz ietf_filters %}{% for d in meeting.important_dates %}BEGIN:VEVENT -UID:ietf-{{ meeting.number }}-{{ d.name_id }}-{{ d.date.isoformat }} -SUMMARY:IETF {{ meeting.number }}: {{ d.name.name }} -CLASS:PUBLIC -DTSTART{% if not d.midnight_cutoff %};VALUE=DATE{% endif %}:{{ d.date|date:"Ymd" }}{% if d.midnight_cutoff %}235900Z{% endif %} -DTSTAMP{% ics_date_time meeting.cached_updated|utc 'utc' %} -TRANSP:TRANSPARENT -DESCRIPTION:{{ d.name.desc }}{% if first and d.name.slug == 'openreg' or first and d.name.slug == 'earlybird' %}\n - Register here: https://www.ietf.org/how/meetings/register/{% endif %}{% if d.name.slug == 'opensched' %}\n - To request a Working Group session, use the IETF Meeting Session Request Tool:\n - {{ request.scheme }}://{{ request.get_host}}{% url 'ietf.meeting.views_session_request.list_view' %}\n - If you are working on a BOF request, it is highly recommended to tell the IESG\n - now by sending an email to iesg@ietf.org to get advance help with the request.{% endif %}{% if d.name.slug == 'cutoffwgreq' %}\n - To request a Working Group session, use the IETF Meeting Session Request Tool:\n - {{ request.scheme }}://{{ request.get_host }}{% url 'ietf.meeting.views_session_request.list_view' %}{% endif %}{% if d.name.slug == 'cutoffbofreq' %}\n - To request a BOF, please see instructions on Requesting a BOF:\n - https://www.ietf.org/how/bofs/bof-procedures/{% endif %}{% if d.name.slug == 'idcutoff' %}\n - Upload using the I-D Submission Tool:\n - {{ request.scheme }}://{{ request.get_host }}{% url 'ietf.submit.views.upload_submission' %}{% endif %}{% if d.name.slug == 'draftwgagenda' or d.name.slug == 'revwgagenda' or d.name.slug == 'procsub' or d.name.slug == 'revslug' %}\n - Upload using the Meeting Materials Management Tool:\n - {{ request.scheme }}://{{ request.get_host }}{% url 'ietf.meeting.views.materials' num=meeting.number %}{% endif %} -END:VEVENT -{% endfor %} From e5af4eae584cf705debc09744a44af4fb38395d9 Mon Sep 17 00:00:00 2001 From: Rudi Matz Date: Sat, 1 Nov 2025 16:57:05 -0400 Subject: [PATCH 2/3] chore: format and cleanup --- ietf/meeting/views.py | 71 ++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 1b9d957ab1..4a8424429d 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -4442,67 +4442,62 @@ def render_important_dates_ical(meetings, request): for meeting in meetings: for important_date in meeting.important_dates: event = Event() - event.add("uid", f"ietf-{meeting.number}-{important_date.name_id}-{important_date.date.isoformat()}") + event.add("uid", f"ietf-{meeting.number}-{important_date.name_id}-" + f"{important_date.date.isoformat()}") event.add("summary", f"IETF {meeting.number}: {important_date.name.name}") event.add("class", "PUBLIC") if not important_date.midnight_cutoff: event.add("dtstart", important_date.date) else: - event.add("dtstart", datetime.datetime.combine(important_date.date, datetime.time(23, 59, 0, tzinfo=pytz.UTC))) + event.add("dtstart", datetime.datetime.combine( + important_date.date, + datetime.time(23, 59, 0, tzinfo=pytz.UTC)) + ) event.add("transp", "TRANSPARENT") event.add("dtstamp", meeting.cached_updated) description_lines = [important_date.name.desc] if important_date.name.slug in ('openreg', 'earlybird'): - description_lines.append("Register here: https://www.ietf.org/how/meetings/register/") + description_lines.append( + "Register here: https://www.ietf.org/how/meetings/register/") if important_date.name.slug == 'opensched': - description_lines.append("To request a Working Group session, use the IETF Meeting Session Request Tool:") - description_lines.append(f"{request.scheme}://{request.get_host()}{reverse('ietf.meeting.views_session_request.list_view')}") - description_lines.append("If you are working on a BOF request, it is highly recommended to tell the IESG") + description_lines.append("To request a Working Group session, use the " + "IETF Meeting Session Request Tool:") + description_lines.append(f"{request.scheme}://{request.get_host()}" + f"{reverse('ietf.meeting.views_session_request.list_view')}") + description_lines.append("If you are working on a BOF request, it is " + "highly recommended to tell the IESG") description_lines.append("now by sending an email to iesg@ietf.org") description_lines.append("to get advance help with the request.") if important_date.name.slug == 'cutoffwgreq': - description_lines.append("To request a Working Group session, use the IETF Meeting Session Request Tool:") - description_lines.append(f"{request.scheme}://{request.get_host()}{reverse('ietf.meeting.views_session_request.list_view')}") + description_lines.append("To request a Working Group session, use the " + "IETF Meeting Session Request Tool:") + description_lines.append(f"{request.scheme}://{request.get_host()}" + f"{reverse('ietf.meeting.views_session_request.list_view')}") if important_date.name.slug == 'cutoffbofreq': - description_lines.append("To request a BOF, please see instructions on Requesting a BOF:") + description_lines.append("To request a BOF, please see instructions on " + "Requesting a BOF:") description_lines.append("https://www.ietf.org/how/bofs/bof-procedures/") if important_date.name.slug == 'idcutoff': description_lines.append("Upload using the I-D Submission Tool:") - description_lines.append(f"{request.scheme}://{request.get_host()}{reverse('ietf.submit.views.upload_submission')}") - if important_date.name.slug in ('draftwgagenda', 'revwgagenda', 'procsub', 'revslug'): - description_lines.append("Upload using the Meeting Materials Management Tool:") - description_lines.append(f"{request.scheme}://{request.get_host()}{reverse('ietf.meeting.views.materials', kwargs={'num': meeting.number})}") + description_lines.append(f"{request.scheme}://{request.get_host()}" + f"{reverse('ietf.submit.views.upload_submission')}") + if important_date.name.slug in ( + 'draftwgagenda', + 'revwgagenda', + 'procsub', + 'revslug' + ): + description_lines.append("Upload using the Meeting Materials " + "Management Tool:") + description_lines.append(f"{request.scheme}://{request.get_host()}" + f"{reverse('ietf.meeting.views.materials', + kwargs={'num': meeting.number})}") event.add("description", "\n".join(description_lines)) cal.add_component(event) - # {% for d in meeting.important_dates %}BEGIN:VEVENT - # UID:ietf-{{ meeting.number }}-{{ d.name_id }}-{{ d.date.isoformat }} - # SUMMARY:IETF {{ meeting.number }}: {{ d.name.name }} - # CLASS:PUBLIC - # DTSTART{% if not d.midnight_cutoff %};VALUE=DATE{% endif %}:{{ d.date|date:"Ymd" }}{% if d.midnight_cutoff %}235900Z{% endif %} - # DTSTAMP{% ics_date_time meeting.cached_updated|utc 'utc' %} - # TRANSP:TRANSPARENT - # DESCRIPTION:{{ d.name.desc }}{% if first and d.name.slug == 'openreg' or first and d.name.slug == 'earlybird' %}\n - # Register here: https://www.ietf.org/how/meetings/register/{% endif %}{% if d.name.slug == 'opensched' %}\n - # To request a Working Group session, use the IETF Meeting Session Request Tool:\n - # {{ request.scheme }}://{{ request.get_host}}{% url 'ietf.meeting.views_session_request.list_view' %}\n - # If you are working on a BOF request, it is highly recommended to tell the IESG\n - # now by sending an email to iesg@ietf.org to get advance help with the request.{% endif %}{% if d.name.slug == 'cutoffwgreq' %}\n - # To request a Working Group session, use the IETF Meeting Session Request Tool:\n - # {{ request.scheme }}://{{ request.get_host }}{% url 'ietf.meeting.views_session_request.list_view' %}{% endif %}{% if d.name.slug == 'cutoffbofreq' %}\n - # To request a BOF, please see instructions on Requesting a BOF:\n - # https://www.ietf.org/how/bofs/bof-procedures/{% endif %}{% if d.name.slug == 'idcutoff' %}\n - # Upload using the I-D Submission Tool:\n - # {{ request.scheme }}://{{ request.get_host }}{% url 'ietf.submit.views.upload_submission' %}{% endif %}{% if d.name.slug == 'draftwgagenda' or d.name.slug == 'revwgagenda' or d.name.slug == 'procsub' or d.name.slug == 'revslug' %}\n - # Upload using the Meeting Materials Management Tool:\n - # {{ request.scheme }}://{{ request.get_host }}{% url 'ietf.meeting.views.materials' num=meeting.number %}{% endif %} - # END:VEVENT - # {% endfor %} - - return cal.to_ical().decode("utf-8") def upcoming_json(request): From e8a4478b1aab755b3b6cd8083bfc9fcc629ac354 Mon Sep 17 00:00:00 2001 From: Rudi Matz Date: Mon, 3 Nov 2025 16:51:55 -0500 Subject: [PATCH 3/3] fix: remove unwanted newline --- ietf/meeting/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 4a8424429d..f20f6b029d 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -4468,8 +4468,8 @@ def render_important_dates_ical(meetings, request): f"{reverse('ietf.meeting.views_session_request.list_view')}") description_lines.append("If you are working on a BOF request, it is " "highly recommended to tell the IESG") - description_lines.append("now by sending an email to iesg@ietf.org") - description_lines.append("to get advance help with the request.") + description_lines.append("now by sending an email to iesg@ietf.org " + "to get advance help with the request.") if important_date.name.slug == 'cutoffwgreq': description_lines.append("To request a Working Group session, use the " "IETF Meeting Session Request Tool:")