Repository: ietf-tools/datatracker

Issue:
Long session names lead to unwieldy agenda filter parameter keywords
The agenda filtering system assigns a keyword to enable/disable display of many types of sessions based on the session's assigned name. If that session has a long name as is sometimes done to add important information to the agenda, this translates into impractically long keywords. (E.g., `/meeting/agenda/?show=newcomers-dinner-open-to-newcomers-note-that-pre-registration-is-required-and-a-25usd-fee-will-be-charged`)

This is not a technical problem, but contradicts the goal of having human-manageable URL parameters for the agenda page. 


Discussion:
At the 114 sprint, get Liz to explain _why_ the session has all this extra stuff in the _name_. We may be able to better model what she needs and avoid this problem altogether.
Talked to @flynnliz (who should correct me if I get this wrong). The need was for a way to show additional essential information directly on the agenda. A subtitle or description field that appears prominently along with the session name should avoid the temptation to use long names.
Related #4457
I think using the existing `agenda_note` may do the trick. Setting that causes a note to show up below the session title as is most visible for the "Joint with xyz" notes on recent meeting agendas.

![Screenshot from 2023-02-08 16-48-50](https://user-images.githubusercontent.com/19472766/217648699-c5e2ae84-aa56-43fd-8513-5513198ae609.png)

I'm planning to make it easier to edit that field.

Resolving patch:
diff --git a/ietf/meeting/forms.py b/ietf/meeting/forms.py
--- a/ietf/meeting/forms.py
+++ b/ietf/meeting/forms.py
@@ -743,7 +743,8 @@ class Meta:
         model = Session
         fields = (
             'purpose', 'name', 'short', 'type', 'requested_duration',
-            'on_agenda', 'remote_instructions', 'attendees', 'comments',
+            'on_agenda', 'agenda_note', 'remote_instructions', 'attendees',
+            'comments',
         )
         labels = {'requested_duration': 'Length'}
 
diff --git a/ietf/meeting/migrations/0060_normalize_canceled_sessions.py b/ietf/meeting/migrations/0060_normalize_canceled_sessions.py
new file mode 100644
--- /dev/null
+++ b/ietf/meeting/migrations/0060_normalize_canceled_sessions.py
@@ -0,0 +1,49 @@
+# Generated by Django 2.2.28 on 2023-02-08 22:41
+
+from django.db import migrations
+from django.db.models import Subquery, OuterRef, Value, TextField
+from django.db.models.functions import Coalesce
+
+
+def forward(apps, schema_editor):
+    Session = apps.get_model('meeting', 'Session')
+    SchedulingEvent = apps.get_model('meeting', 'SchedulingEvent')
+    Person = apps.get_model('person', 'Person')
+
+    # annotation borrowed from SessionQuerySet.with_current_status()
+    sessions = Session.objects.annotate(
+        # coalesce with '' to avoid nulls which give funny
+        # results, e.g. .exclude(current_status='canceled') also
+        # skips rows with null in them
+        current_status=Coalesce(
+            Subquery(
+                SchedulingEvent.objects.filter(
+                    session=OuterRef('pk')
+                ).order_by(
+                    '-time', '-id'
+                ).values('status')[:1]),
+            Value(''),
+            output_field=TextField()),
+    ).exclude(
+        current_status__in=['canceled', 'canceledpa'],
+    )
+    system_person = Person.objects.get(name='(System)')
+
+    # Cancel any uncanceled sessions marked as 'CANCELED' in the agenda_note
+    for session in sessions.filter(agenda_note='CANCELED'):
+        SchedulingEvent.objects.create(session=session, status_id='canceled', by=system_person)
+
+
+def reverse(apps, schema_editor):
+    pass  # nothing to be done
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('meeting', '0059_rename_sessions'),
+    ]
+
+    operations = [
+        migrations.RunPython(forward, reverse),
+    ]
diff --git a/ietf/secr/proceedings/proc_utils.py b/ietf/secr/proceedings/proc_utils.py
--- a/ietf/secr/proceedings/proc_utils.py
+++ b/ietf/secr/proceedings/proc_utils.py
@@ -64,8 +64,6 @@ def import_audio_files(meeting):
     
     Example: ietf90-salonb-20140721-1710.mp3
     '''
-    from ietf.meeting.utils import add_event_info_to_session_qs
-
     unmatched_files = []
     path = os.path.join(settings.MEETING_RECORDINGS_DIR, meeting.type.slug + meeting.number)
     if not os.path.exists(path):
@@ -73,11 +71,9 @@ def import_audio_files(meeting):
     for filename in os.listdir(path):
         timeslot = get_timeslot_for_filename(filename)
         if timeslot:
-            sessions = add_event_info_to_session_qs(Session.objects.filter(
+            sessions = Session.objects.with_current_status().filter(
                 timeslotassignments__schedule=timeslot.meeting.schedule_id,
-            ).exclude(
-                agenda_note__icontains='canceled'
-            )).filter(
+            ).filter(
                 current_status='sched',
             ).order_by('timeslotassignments__timeslot__time')
             if not sessions:


Test patch: