ci: merge main to release (#8152)
This commit is contained in:
commit
39ea21ed33
12
ietf/meeting/tasks.py
Normal file
12
ietf/meeting/tasks.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Copyright The IETF Trust 2024, All Rights Reserved
|
||||||
|
#
|
||||||
|
# Celery task definitions
|
||||||
|
#
|
||||||
|
from celery import shared_task
|
||||||
|
|
||||||
|
from .views import generate_agenda_data
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def agenda_data_refresh():
|
||||||
|
generate_agenda_data(force_refresh=True)
|
|
@ -26,6 +26,7 @@ from zoneinfo import ZoneInfo
|
||||||
from django.urls import reverse as urlreverse
|
from django.urls import reverse as urlreverse
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
from django.test import Client, override_settings
|
from django.test import Client, override_settings
|
||||||
from django.db.models import F, Max
|
from django.db.models import F, Max
|
||||||
from django.http import QueryDict, FileResponse
|
from django.http import QueryDict, FileResponse
|
||||||
|
@ -49,7 +50,7 @@ from ietf.meeting.utils import condition_slide_order
|
||||||
from ietf.meeting.utils import add_event_info_to_session_qs, participants_for_meeting
|
from ietf.meeting.utils import add_event_info_to_session_qs, participants_for_meeting
|
||||||
from ietf.meeting.utils import create_recording, get_next_sequence, bluesheet_data
|
from ietf.meeting.utils import create_recording, get_next_sequence, bluesheet_data
|
||||||
from ietf.meeting.views import session_draft_list, parse_agenda_filter_params, sessions_post_save, agenda_extract_schedule
|
from ietf.meeting.views import session_draft_list, parse_agenda_filter_params, sessions_post_save, agenda_extract_schedule
|
||||||
from ietf.meeting.views import get_summary_by_area, get_summary_by_type, get_summary_by_purpose
|
from ietf.meeting.views import get_summary_by_area, get_summary_by_type, get_summary_by_purpose, generate_agenda_data
|
||||||
from ietf.name.models import SessionStatusName, ImportantDateName, RoleName, ProceedingsMaterialTypeName
|
from ietf.name.models import SessionStatusName, ImportantDateName, RoleName, ProceedingsMaterialTypeName
|
||||||
from ietf.utils.decorators import skip_coverage
|
from ietf.utils.decorators import skip_coverage
|
||||||
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
|
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
|
||||||
|
@ -245,30 +246,34 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
|
|
||||||
# Agenda API tests
|
# Agenda API tests
|
||||||
# -> Meeting data
|
# -> Meeting data
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.api_get_agenda_data", kwargs=dict(num=meeting.number)))
|
# First, check that the generation function does the right thing
|
||||||
self.assertEqual(r.status_code, 200)
|
generated_data = generate_agenda_data(meeting.number)
|
||||||
rjson = json.loads(r.content.decode("utf8"))
|
self.assertEqual(
|
||||||
self.assertJSONEqual(
|
generated_data,
|
||||||
r.content.decode("utf8"),
|
|
||||||
{
|
{
|
||||||
"meeting": {
|
"meeting": {
|
||||||
"number": meeting.number,
|
"number": meeting.number,
|
||||||
"city": meeting.city,
|
"city": meeting.city,
|
||||||
"startDate": meeting.date.isoformat(),
|
"startDate": meeting.date.isoformat(),
|
||||||
"endDate": meeting.end_date().isoformat(),
|
"endDate": meeting.end_date().isoformat(),
|
||||||
"updated": rjson.get("meeting").get("updated"), # Just expect the value to exist
|
"updated": generated_data.get("meeting").get("updated"), # Just expect the value to exist
|
||||||
"timezone": meeting.time_zone,
|
"timezone": meeting.time_zone,
|
||||||
"infoNote": meeting.agenda_info_note,
|
"infoNote": meeting.agenda_info_note,
|
||||||
"warningNote": meeting.agenda_warning_note
|
"warningNote": meeting.agenda_warning_note
|
||||||
},
|
},
|
||||||
"categories": rjson.get("categories"), # Just expect the value to exist
|
"categories": generated_data.get("categories"), # Just expect the value to exist
|
||||||
"isCurrentMeeting": True,
|
"isCurrentMeeting": True,
|
||||||
"usesNotes": False, # make_meeting_test_data sets number=72
|
"usesNotes": False, # make_meeting_test_data sets number=72
|
||||||
"schedule": rjson.get("schedule"), # Just expect the value to exist
|
"schedule": generated_data.get("schedule"), # Just expect the value to exist
|
||||||
"floors": []
|
"floors": []
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# -> Session Materials
|
with patch("ietf.meeting.views.generate_agenda_data", return_value=generated_data):
|
||||||
|
r = self.client.get(urlreverse("ietf.meeting.views.api_get_agenda_data", kwargs=dict(num=meeting.number)))
|
||||||
|
self.assertEqual(r.status_code, 200)
|
||||||
|
# json.dumps using the DjangoJSONEncoder to handle timestamps consistently
|
||||||
|
self.assertJSONEqual(r.content.decode("utf8"), json.dumps(generated_data, cls=DjangoJSONEncoder))
|
||||||
|
# -> Session MaterialM
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.api_get_session_materials", kwargs=dict(session_id=session.id)))
|
r = self.client.get(urlreverse("ietf.meeting.views.api_get_session_materials", kwargs=dict(session_id=session.id)))
|
||||||
self.assertEqual(r.status_code, 200)
|
self.assertEqual(r.status_code, 200)
|
||||||
rjson = json.loads(r.content.decode("utf8"))
|
rjson = json.loads(r.content.decode("utf8"))
|
||||||
|
|
|
@ -25,6 +25,7 @@ from tempfile import mkstemp
|
||||||
from wsgiref.handlers import format_date_time
|
from wsgiref.handlers import format_date_time
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.core.cache import caches
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
from django.http import (HttpResponse, HttpResponseRedirect, HttpResponseForbidden,
|
from django.http import (HttpResponse, HttpResponseRedirect, HttpResponseForbidden,
|
||||||
HttpResponseNotFound, Http404, HttpResponseBadRequest,
|
HttpResponseNotFound, Http404, HttpResponseBadRequest,
|
||||||
|
@ -1657,8 +1658,16 @@ def agenda(request, num=None, name=None, base=None, ext=None, owner=None, utc=""
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@cache_page(5 * 60)
|
|
||||||
def api_get_agenda_data (request, num=None):
|
def generate_agenda_data(num=None, force_refresh=False):
|
||||||
|
"""Generate data for the api_get_agenda_data endpoint
|
||||||
|
|
||||||
|
:num: meeting number
|
||||||
|
:force_refresh: True to force a refresh of the cache
|
||||||
|
"""
|
||||||
|
cache = caches["default"]
|
||||||
|
cache_timeout = 6 * 60
|
||||||
|
|
||||||
meeting = get_ietf_meeting(num)
|
meeting = get_ietf_meeting(num)
|
||||||
if meeting is None:
|
if meeting is None:
|
||||||
raise Http404("No such full IETF meeting")
|
raise Http404("No such full IETF meeting")
|
||||||
|
@ -1667,6 +1676,12 @@ def api_get_agenda_data (request, num=None):
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
cache_key = f"generate_agenda_data_{meeting.number}"
|
||||||
|
if not force_refresh:
|
||||||
|
cached_value = cache.get(cache_key)
|
||||||
|
if cached_value is not None:
|
||||||
|
return cached_value
|
||||||
|
|
||||||
# Select the schedule to show
|
# Select the schedule to show
|
||||||
schedule = get_schedule(meeting, None)
|
schedule = get_schedule(meeting, None)
|
||||||
|
|
||||||
|
@ -1685,10 +1700,8 @@ def api_get_agenda_data (request, num=None):
|
||||||
|
|
||||||
# Get Floor Plans
|
# Get Floor Plans
|
||||||
floors = FloorPlan.objects.filter(meeting=meeting).order_by('order')
|
floors = FloorPlan.objects.filter(meeting=meeting).order_by('order')
|
||||||
|
|
||||||
#debug.show('all([(item.acronym,item.session.order_number,item.session.order_in_meeting()) for item in filtered_assignments])')
|
result = {
|
||||||
|
|
||||||
return JsonResponse({
|
|
||||||
"meeting": {
|
"meeting": {
|
||||||
"number": schedule.meeting.number,
|
"number": schedule.meeting.number,
|
||||||
"city": schedule.meeting.city,
|
"city": schedule.meeting.city,
|
||||||
|
@ -1704,7 +1717,13 @@ def api_get_agenda_data (request, num=None):
|
||||||
"usesNotes": meeting.uses_notes(),
|
"usesNotes": meeting.uses_notes(),
|
||||||
"schedule": list(map(agenda_extract_schedule, filtered_assignments)),
|
"schedule": list(map(agenda_extract_schedule, filtered_assignments)),
|
||||||
"floors": list(map(agenda_extract_floorplan, floors))
|
"floors": list(map(agenda_extract_floorplan, floors))
|
||||||
})
|
}
|
||||||
|
cache.set(cache_key, result, timeout=cache_timeout)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def api_get_agenda_data(request, num=None):
|
||||||
|
return JsonResponse(generate_agenda_data(num, force_refresh=False))
|
||||||
|
|
||||||
|
|
||||||
def api_get_session_materials(request, session_id=None):
|
def api_get_session_materials(request, session_id=None):
|
||||||
|
|
|
@ -596,14 +596,17 @@ def document_stats(request, stats_type=None):
|
||||||
|
|
||||||
elif any(stats_type == t[0] for t in possible_yearly_stats_types):
|
elif any(stats_type == t[0] for t in possible_yearly_stats_types):
|
||||||
|
|
||||||
person_filters = Q(documentauthor__document__type="draft")
|
|
||||||
|
|
||||||
# filter persons
|
# filter persons
|
||||||
rfc_state = State.objects.get(type="rfc", slug="published")
|
rfc_state = State.objects.get(type="rfc", slug="published")
|
||||||
if document_type == "rfc":
|
if document_type == "rfc":
|
||||||
|
person_filters = Q(documentauthor__document__type="rfc")
|
||||||
person_filters &= Q(documentauthor__document__states=rfc_state)
|
person_filters &= Q(documentauthor__document__states=rfc_state)
|
||||||
elif document_type == "draft":
|
elif document_type == "draft":
|
||||||
|
person_filters = Q(documentauthor__document__type="draft")
|
||||||
person_filters &= ~Q(documentauthor__document__states=rfc_state)
|
person_filters &= ~Q(documentauthor__document__states=rfc_state)
|
||||||
|
else:
|
||||||
|
person_filters = Q(documentauthor__document__type="rfc")
|
||||||
|
person_filters |= Q(documentauthor__document__type="draft")
|
||||||
|
|
||||||
doc_years = defaultdict(set)
|
doc_years = defaultdict(set)
|
||||||
|
|
||||||
|
@ -625,8 +628,8 @@ def document_stats(request, stats_type=None):
|
||||||
).values_list("source", flat=True)[:1]
|
).values_list("source", flat=True)[:1]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.values_list("draft", "time")
|
.values_list("doc", "time")
|
||||||
.order_by("draft")
|
.order_by("doc")
|
||||||
)
|
)
|
||||||
|
|
||||||
for doc_id, time in rfcevent_qs.iterator():
|
for doc_id, time in rfcevent_qs.iterator():
|
||||||
|
@ -663,9 +666,11 @@ def document_stats(request, stats_type=None):
|
||||||
for name, affiliation, doc in name_affiliation_doc_set:
|
for name, affiliation, doc in name_affiliation_doc_set:
|
||||||
a = aliases.get(affiliation, affiliation)
|
a = aliases.get(affiliation, affiliation)
|
||||||
if a:
|
if a:
|
||||||
for year in doc_years.get(doc):
|
years = doc_years.get(doc)
|
||||||
if years_from <= year <= years_to:
|
if years:
|
||||||
bins[(year, a)].add(name)
|
for year in years:
|
||||||
|
if years_from <= year <= years_to:
|
||||||
|
bins[(year, a)].add(name)
|
||||||
|
|
||||||
add_labeled_top_series_from_bins(chart_data, bins, limit=8)
|
add_labeled_top_series_from_bins(chart_data, bins, limit=8)
|
||||||
|
|
||||||
|
@ -724,9 +729,11 @@ def document_stats(request, stats_type=None):
|
||||||
continent_name = country_to_continent.get(country_name, "")
|
continent_name = country_to_continent.get(country_name, "")
|
||||||
|
|
||||||
if continent_name:
|
if continent_name:
|
||||||
for year in doc_years.get(doc):
|
years = doc_years.get(doc)
|
||||||
if years_from <= year <= years_to:
|
if years:
|
||||||
bins[(year, continent_name)].add(name)
|
for year in years:
|
||||||
|
if years_from <= year <= years_to:
|
||||||
|
bins[(year, continent_name)].add(name)
|
||||||
|
|
||||||
add_labeled_top_series_from_bins(chart_data, bins, limit=8)
|
add_labeled_top_series_from_bins(chart_data, bins, limit=8)
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
<div class="collapse navbar-collapse" id="navbar-collapse">
|
<div class="collapse navbar-collapse" id="navbar-collapse">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav flex-nowrap">
|
||||||
{% include "base/menu.html" with flavor="top" %}
|
{% include "base/menu.html" with flavor="top" %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue