datatracker/ietf/templates/meeting/session_details_panel.html
Robert Sparks e6138ca126
feat: session apis (#7173)
* feat: Show bluesheets using Attended tables (#7094)

* feat: Show bluesheets using Attended tables (#6898)

* feat: Allow users to add themselves to session attendance (#6454)

* chore: Correct copyright year

* fix: Address review comments

* fix: Don't try to generate empty bluesheets

* refactor: Complete rewrite of bluesheet.html

* refactor: Fill in a few gaps, close a few holes

- Rename the live "bluesheet" to "attendance", add some explanatory text.
- Add attendance links in materials view and pre-finalized proceedings view.
- Don't allow users to add themselves after the corrections cutoff date.

* fix: Report file-save errors to caller

* fix: Address review comments

* fix: typo

* refactor: if instead of except; refactor gently

* refactor: Rearrange logic a little, add comment

* style: Black

* refactor: auto_now_add->default to allow override

* refactor: jsonschema to validate API payload

* feat: Handle new API data format

Not yet tested except that it falls back when the old
format is used.

* test: Split test into deprecated/new version

Have not yet touched the new version

* style: Black

* test: Test new add_session_attendees API

* fix: Fix bug uncovered by test

* refactor: Refactor affiliation lookup a bit

* fix: Order bluesheet by Attended.time

* refactor: Move helpers from views.py to utils.py

* test: Test that finalize calls generate_bluesheets

* test: test_bluesheet_data()

* fix: Clean up merge

* fix: Remove debug statement

* chore: comments

* refactor: Renumber migrations

---------

Co-authored-by: Paul Selkirk <paul@painless-security.com>

* chore: Remove unused import

* style: Black

* feat: Stub session update notify API

* feat: Add order & rev to slides JSON

* style: Black

* feat: Stub actual Meetecho slide deck mgmt API

* refactor: Limit reordering to type="slides"

* chore: Remove repository from meetecho API

(API changed on their end)

* feat: update Meetecho on slide reorder

* refactor: drop pytz from meetecho.py

* chore: Remove more repository refs

* refactor: Eliminate more pytz

* test: Test add_slide_deck api

* fix: Allow 202 status code / absent Content-Type

* test: Test delete_slide_deck api

* test: Test update_slide_decks api

* refactor: sessionpresentation_set -> presentations

* test: Test send_update()

* fix: Debug send_update()

* test: ajax_reorder_slides calls Meetecho API

* test: Test SldesManager.add()

* feat: Implement SlidesManager.add()

* test: Test that ajax_add_slides... calls API

* feat: Call Meetecho API when slides added to session

* test: Test SlidesManager.delete()

* feat: Implement SlidesManager.delete()

* test: ajax_remove_slides... calls Meetecho API

* feat: Call Meetecho API when slides removed

* chore: Update docstring

* feat: rudimentary debug mode for Meetecho API

* test: remove_sessionpresentation() calls Meetecho API

* feat: Call Meetecho API from remove_sessionpresentation()

* test: upload_slides() calls Meetecho API

* style: Black

* fix: Refactor/debug upload_session_slides

Avoids double-save of a SessionPresentation for the session
being updated and updates other sessions when apply_to_all
is set (previously it only created ones that did not exist,
so rev would never be updated).

* test: Fix test bug

* feat: Call Meetecho API when uploading session slides

* fix: Only replace slides actually linked to session

* fix: Delint

Removed some type checking rather than debugging it

* fix: Send get_versionless_href() as url for slides

* test: TZ-aware timestamps, please

* chore: Add comments

* feat: Call Meetecho API in edit_sessionpresentation

* feat: Call Meetecho API in remove_sessionpresentation

* feat: Call Meetecho API from add_sessionpresentation

* fix: Set order in add_sessionpresentation

* fix: Restrict API calls to "slides" docs

* feat: Call Meetecho API on title changes

* test: Check meetecho API calls in test_revise()

* fix: better Meetecho API "order" management

* fix: no PUT if there are no slides after DELETE

* feat: Catch exceptions from SlidesManager

Don't let errors in the MeetEcho slides API interfere with
the ability to modify slides for a session.

* feat: Limit which sessions we send notifications for

* fix: handle absence of request_timeout in api config

* test: always send slide notifications in tests

* fix: save slides before sending notification (#7172)

* fix: save slides before sending notification

* style: fix indentation

It's not a bug, it's a flourish!

---------

Co-authored-by: Jennifer Richards <jennifer@staff.ietf.org>
Co-authored-by: Paul Selkirk <paul@painless-security.com>
2024-03-12 10:22:24 -05:00

373 lines
20 KiB
HTML

{% load origin ietf_filters textfilters tz dateformat %}
{% origin %}
{% for session in sessions %}
{% with item=session.official_timeslotassignment %} {% with timeslot=item.timeslot %}
<div class="mt-4">
{% if not session.cancelled %}
<div class="regular ms-3 float-end">
{# see note in the included templates re: show_agenda parameter and required JS import #}
{% if meeting.type.slug == 'interim' %}
{% include "meeting/interim_session_buttons.html" with show_agenda=False show_empty=False %}
{% else %}
{% include "meeting/session_buttons_include.html" with show_agenda=False item=session.official_timeslotassignment use_notes=session.meeting.use_notes %}
{% endif %}
</div>
{% endif %}
<h3 class="" id="session_{{ session.pk }}">
{% if sessions|length > 1 %}Session {{ forloop.counter }} :{% endif %}
{% for time in session.times %}
{% if not forloop.first %},{% endif %}
<span class="session-time date me-3" data-start-utc="{{ timeslot.time|utc|date:'Y-m-d H:i' }}" data-end-utc="{{ timeslot.end_time|utc|date:'Y-m-d H:i' }}"></span>
{% include "meeting/tz-display.html" with meeting_timezone=session.meeting.time_zone id_suffix=session.pk minimal=True only %}
{% endfor %}
{% if session.cancelled %}
<small class="badge rounded-pill text-bg-warning">Cancelled</small>
{% else %}
{{ session.status }}
{% endif %}
{% if session.name %}: {{ session.name }}{% endif %}
</h3>
</div>
{% if session.agenda_note %}<h3 class="mt-4">{{ session.agenda_note }}</h3>{% endif %}
{% if can_manage_materials %}
{% if session.current_status == 'sched' or session.current_status == 'schedw' %}
<div class="buttonlist">
{% if can_view_request %}
<a class="btn btn-primary"
href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">
Meeting details
</a>
{% endif %}
</div>
{% if not session.type_counter.agenda %}
<div class="alert alert-warning my-3">This session does not yet have an agenda.</div>
{% endif %}
{% endif %}
{% endif %}
{% if meeting.type.slug == 'interim' and session.remote_instructions %}
<div class="my-3">
<b>Remote instructions:</b>
{% if session.agenda_note|first_url|conference_url %}
<a href="{{ session.agenda_note|first_url }}" title="Online conference">
<i class="bi bi-beople"></i>
</a>
{% elif session.remote_instructions|first_url|conference_url %}
<a href="{{ session.remote_instructions|first_url }}"
title="Online conference">
<i class="bi bi-people"></i>
</a>
{% endif %}
{{ session.remote_instructions|linkify }}
</div>
{% endif %}
<h3 class="mt-4">Agenda, Minutes, and Bluesheets</h3>
<table class="table table-sm table-striped">
{% if session.filtered_artifacts or session.bluesheet_title %}
<tbody>
{% for pres in session.filtered_artifacts %}
<tr>
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
<td>
<a href="{{ pres.document.get_href }}">{{ pres.document.title }}</a>
<a href="{{ url }}">({{ pres.document.name }})</a>
{% if user|has_role:"Secretariat" or can_manage_materials %}
{% if pres.document.type.slug == 'minutes' %}
{% url 'ietf.meeting.views.upload_session_minutes' session_id=session.pk num=session.meeting.number as upload_url %}
{% elif pres.document.type.slug == 'narrativeminutes' %}
{% url 'ietf.meeting.views.upload_session_narrativeminutes' session_id=session.pk num=session.meeting.number as upload_url %}
{% elif pres.document.type.slug == 'agenda' %}
{% url 'ietf.meeting.views.upload_session_agenda' session_id=session.pk num=session.meeting.number as upload_url %}
{% else %}
{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number as upload_url %}
{% endif %}
{% if pres.document.type.slug != 'bluesheets' or user|has_role:"Secretariat" or meeting.type.slug == 'interim' and can_manage_materials %}
{% if pres.document.type.slug == 'minutes' %}
<a class="btn btn-primary btn-sm float-end ms-1" href="{% url 'ietf.meeting.views.import_session_minutes' num=session.meeting.number session_id=session.pk %}">Import from notes.ietf.org</a>
{% endif %}
<a class="btn btn-primary btn-sm float-end ms-1" href="{{ upload_url }}">Upload revision</a>
{% endif %}
{% endif %}
</td>
</tr>
{% endfor %}
{% if session.bluesheet_title %}
<tr><td>
<a href="{% url 'ietf.meeting.views.session_attendance' session_id=session.pk num=session.meeting.number %}">
{{ session.bluesheet_title }}
</a>
</td></tr>
{% endif %}
</tbody>
{% endif %}
</table>
{% if can_manage_materials %}
{% if not session.type_counter.agenda %}
<a class="btn btn-primary"
href="{% url 'ietf.meeting.views.upload_session_agenda' session_id=session.pk num=session.meeting.number %}">
Upload agenda
</a>
{% endif %}
{% if not session.type_counter.minutes %}
<a class="btn btn-primary" href="{% url 'ietf.meeting.views.import_session_minutes' num=session.meeting.number session_id=session.pk %}">Import minutes from notes.ietf.org</a>
<a class="btn btn-primary"
href="{% url 'ietf.meeting.views.upload_session_minutes' session_id=session.pk num=session.meeting.number %}">
Upload minutes
</a>
{% endif %}
{% if not session.type_counter.narrativeminutes and session.group.acronym == "iesg" %}
<a class="btn btn-primary"
href="{% url 'ietf.meeting.views.upload_session_narrativeminutes' session_id=session.pk num=session.meeting.number %}">
Upload narrative minutes
</a>
{% endif %}
{% endif %}
{% if user|has_role:"Secretariat" and not session.type_counter.bluesheets or meeting.type.slug == 'interim' and can_manage_materials and not session.type_counter.bluesheets %}
<a class="btn btn-primary"
href="{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number %}">
Upload bluesheets
</a>
{% endif %}
{% if session.filtered_chatlog_and_polls %}
<h3 class="mt-4">Chatlog and polls</h3>
<table class="table table-sm table-striped chatlog-and-polls"
id="chatlog_and_polls_{{ session.pk }}">
<tbody data-session="{{ session.pk }}">
{% for pres in session.filtered_chatlog_and_polls %}
<tr data-name="{{ pres.document.name }}">
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
<td>
<a href="{{ pres.document.get_href }}">{{ pres.document.title }}</a>
<a href="{{ url }}">({{ pres.document.name }})</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
<h3 class="mt-4">Slides</h3>
<table class="table table-sm table-striped slides"
id="slides_{{ session.pk }}">
{% if session.filtered_slides %}
<tbody data-session="{{ session.pk }}"
data-add-to-session="{% url 'ietf.meeting.views.ajax_add_slides_to_session' session_id=session.pk num=session.meeting.number %}"
data-remove-from-session="{% url 'ietf.meeting.views.ajax_remove_slides_from_session' session_id=session.pk num=session.meeting.number %}"
data-reorder-in-session="{% url 'ietf.meeting.views.ajax_reorder_slides_in_session' session_id=session.pk num=session.meeting.number %}">
{% for pres in session.filtered_slides %}
<tr data-name="{{ pres.document.name }}" {% if can_manage_materials %} class="draggable" {% endif %}>
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
{% if can_manage_materials %}
<td>
<i class="bi bi-grip-vertical drag-handle" title="Drag to reorder"></i>
</td>
{% endif %}
<td>
{% if can_manage_materials %}
<a class="btn btn-primary btn-sm float-end ms-1"
href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number name=pres.document.name %}">
Upload revision
</a>
<a class="btn btn-danger btn-sm float-end ms-1"
href="{% url 'ietf.meeting.views.remove_sessionpresentation' session_id=session.pk num=session.meeting.number name=pres.document.name %}">
Remove
</a>
{% endif %}
<a href="{{ pres.document.get_href }}">{{ pres.document.title }}</a>
<a href="{{ url }}">({{ pres.document.name }})</a>
</td>
</tr>
{% endfor %}
</tbody>
{% endif %}
</table>
{% if can_manage_materials %}
<a class="btn btn-primary uploadslides"
href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number %}">
Upload new slides
</a>
{% elif request.user.is_authenticated and not session.is_material_submission_cutoff %}
<a class="btn btn-primary proposeslides"
href="{% url 'ietf.meeting.views.propose_session_slides' session_id=session.pk num=session.meeting.number %}">
Propose slides
</a>
{% endif %}
{% if can_manage_materials %}<div class="form-text">Drag-and-drop to reorder slides</div>{% endif %}
<h3 class="mt-4">Internet-Drafts</h3>
<table class="table table-sm table-striped">
{% if session.filtered_drafts %}
<tbody>
{% for pres in session.filtered_drafts %}
<tr>
<td>
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
<a href="{{ url }}">
{{ pres.document.title }} ({{ pres.document.name }})
{% if pres.rev %}Version {{ pres.rev }}{% endif %}
</a>
</td>
<td>
{% if can_manage_materials %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.meeting.views.remove_sessionpresentation' session_id=session.pk num=session.meeting.number name=pres.document.name %}">
Remove
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
{% endif %}
</table>
{% if can_manage_materials %}
<a class="btn btn-primary"
href="{% url 'ietf.meeting.views.add_session_drafts' session_id=session.pk num=session.meeting.number %}">
Link additional I-Ds to session
</a>
{% endif %}
{% if timezone_now < timeslot.end_time %}{# show meeting tools until the session ends #}
<h3 class="mt-4">Meeting tools</h3>
<table class="table table-sm table-striped meeting-tools"
id="meeting_tools_{{ session.pk }}">
<tbody>
{% if use_notes %}
<tr>
<td>
<a href="{{ session.notes_url }}">
<i class="bi bi-journal-text"></i> Notepad for note-takers
</a>
</td>
</tr>
{% endif %}
{# chat #}
<tr>
<td>
<a href="{{ session.chat_room_url }}">
<i class="bi bi-chat"></i> Chat room
</a>
</td>
</tr>
{# Video stream (meetecho) #}
{% if session.video_stream_url and timezone_now < timeslot.end_time %}
<tr>
<td>
<a href="{{ session.video_stream_url }}">
<i class="bi bi-camera-video"></i> Video stream
</a>
</td>
</tr>
{% endif %}
{# Onsite tool (meetecho_onsite) #}
{% if session.onsite_tool_url %}
<tr>
<td>
<a href="{{ session.onsite_tool_url }}">
<i class="bi bi-phone"></i> Onsite tool
</a>
</td>
</tr>
{% endif %}
{# Audio stream #}
{% if session.audio_stream_url %}
<tr>
<td>
<a href="{{ session.audio_stream_url }}">
<i class="bi bi-headphones"></i> Audio stream
</a>
</td>
</tr>
{% endif %}
{# Remote call-in #}
{% if session.agenda_note|first_url|conference_url %}
<tr>
<td>
<a href="{{ session.agenda_note|first_url }}">
<i class="bi bi-people"></i> Online conference
</a>
</td>
</tr>
{% elif session.remote_instructions|first_url|conference_url %}
<tr>
<td>
<a href="{{ session.remote_instructions|first_url }}">
<i class="bi bi-people"></i> Online conference
</a>
</td>
</tr>
{% elif timeslot.location.webex_url %}
<tr>
<td>
<a href="{{ timeslot.location.webex_url|format:session }}">
<i class="bi bi-people"></i> Webex session
</a>
</td>
</tr>
{% endif %}
</tbody>
</table>
{% else %}{# session is in the past #}
<h3 class="mt-4">Notes and recordings</h3>
<table class="table table-sm table-striped meeting-tools"
id="notes_and_recordings_{{ session.pk }}">
<tbody>
{% if use_notes %}
<tr>
<td>
<a href="{{ session.notes_url }}">
<i class="bi bi-journal-text"></i> Notepad for note-takers
</a>
</td>
</tr>
{% endif %}
{# Recordings #}
{% if meeting.number|add:"0" >= 80 %}
{% with session.recordings as recordings %}
{% if recordings %}
{# There's no guaranteed order, so this is a bit messy: #}
{# First, the audio recordings, if any #}
{% for r in recordings %}
{% if r.get_href and 'audio' in r.get_href %}
<tr>
<td>
<a href="{{ r.get_href }}"><i class="bi bi-file-play"></i> {{ r.title }}</a>
</td>
</tr>
{% endif %}
{% endfor %}
{# Then the youtube recordings #}
{% for r in recordings %}
{% if r.get_href and 'youtu' in r.get_href %}
<tr>
<td>
<a href="{{ r.get_href }}"><i class="bi bi-file-slides"></i> {{ r.title }}</a>
</td>
</tr>
{% endif %}
{% endfor %}
{# Finally, any other recordings #}
{% for r in recordings %}
{% if r.get_href and not 'audio' in r.get_href and not 'youtu' in r.get_href %}
<tr>
<td>
<a href="{{ r.get_href }}"><i class="bi bi-file-play"></i> {{ r.title }}</a>
</td>
</tr>
{% endif %}
{% endfor %}
{% endif %}
{% endwith %}
{% if session.video_stream_url %}
<tr>
<td>
<a href="{{ session.session_recording_url }}">
<i class="bi bi-file-slides"></i> Session recording
</a>
</td>
</tr>
{% endif %}
{% endif %}
</tbody>
</table>
{% endif %}
{% endwith %}{% endwith %}
{% endfor %}