Skip to content

fix: add missing meeting.tasks.fetch_meeting_attendance_task #8987

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions ietf/meeting/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from .utils import generate_proceedings_content
from .views import generate_agenda_data
from .utils import migrate_registrations, check_migrate_registrations
from .utils import fetch_attendance_from_meetings


@shared_task
Expand Down Expand Up @@ -60,3 +61,21 @@ def proceedings_content_refresh_task(*, all=False):
elif all or (num % 24 == now.hour):
log.log(f"Refreshing proceedings for meeting {meeting.number}...")
generate_proceedings_content(meeting, force_refresh=True)


@shared_task
def fetch_meeting_attendance_task():
# fetch most recent two meetings
meetings = Meeting.objects.filter(type="ietf", date__lte=timezone.now()).order_by("-date")[:2]
try:
stats = fetch_attendance_from_meetings(meetings)
except RuntimeError as err:
log.log(f"Error in fetch_meeting_attendance_task: {err}")
else:
for meeting, meeting_stats in zip(meetings, stats):
log.log(
"Fetched data for meeting {:>3}: {:4d} created, {:4d} updated, {:4d} deleted, {:4d} processed".format(
meeting.number, meeting_stats['created'], meeting_stats['updated'], meeting_stats['deleted'],
meeting_stats['processed']
)
)
30 changes: 30 additions & 0 deletions ietf/meeting/tests_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import datetime
from mock import patch, call
from ietf.utils.test_utils import TestCase
from ietf.utils.timezone import date_today
from .factories import MeetingFactory
from .tasks import proceedings_content_refresh_task, agenda_data_refresh
from .tasks import fetch_meeting_attendance_task


class TaskTests(TestCase):
Expand Down Expand Up @@ -49,3 +51,31 @@ def test_proceedings_content_refresh_task(self, mock_generate):
with patch("ietf.meeting.tasks.timezone.now", return_value=hour_01_utc):
proceedings_content_refresh_task(all=True)
self.assertEqual(mock_generate.call_count, 2)

@patch("ietf.meeting.tasks.fetch_attendance_from_meetings")
def test_fetch_meeting_attendance_task(self, mock_fetch_attendance):
today = date_today()
meetings = [
MeetingFactory(type_id="ietf", date=today - datetime.timedelta(days=1)),
MeetingFactory(type_id="ietf", date=today - datetime.timedelta(days=2)),
MeetingFactory(type_id="ietf", date=today - datetime.timedelta(days=3)),
]
data = {
'created': 1,
'updated': 2,
'deleted': 0,
'processed': 3,
}

mock_fetch_attendance.return_value = [data, data]

fetch_meeting_attendance_task()
self.assertEqual(mock_fetch_attendance.call_count, 1)
self.assertCountEqual(mock_fetch_attendance.call_args[0][0], meetings[0:2])

# test handling of RuntimeError
mock_fetch_attendance.reset_mock()
mock_fetch_attendance.side_effect = RuntimeError
fetch_meeting_attendance_task()
self.assertTrue(mock_fetch_attendance.called)
# Good enough that we got here without raising an exception
16 changes: 15 additions & 1 deletion ietf/meeting/tests_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from ietf.meeting.factories import MeetingFactory, RegistrationFactory, RegistrationTicketFactory
from ietf.meeting.models import Registration
from ietf.meeting.utils import (migrate_registrations, get_preferred, process_single_registration,
get_registration_data, sync_registration_data)
get_registration_data, sync_registration_data, fetch_attendance_from_meetings)
from ietf.nomcom.models import Volunteer
from ietf.nomcom.factories import NomComFactory, nomcom_kwargs_for_year
from ietf.person.factories import PersonFactory
Expand Down Expand Up @@ -341,3 +341,17 @@ def test_process_single_registration_cancelled(self):
new_reg, action = process_single_registration(reg_data, meeting)
self.assertEqual((new_reg, action), (None, 'deleted'))
self.assertEqual(meeting.registration_set.count(), 0)

@patch("ietf.meeting.utils.sync_registration_data")
def test_fetch_attendance_from_meetings(self, mock_sync_reg_data):
mock_meetings = [object(), object(), object()]
d1 = dict(created=1, updated=2, deleted=0, processed=3)
d2 = dict(created=2, updated=2, deleted=0, processed=4)
d3 = dict(created=1, updated=4, deleted=1, processed=5)
mock_sync_reg_data.side_effect = (d1, d2, d3)
stats = fetch_attendance_from_meetings(mock_meetings)
self.assertEqual(
[mock_sync_reg_data.call_args_list[n][0][0] for n in range(3)],
mock_meetings,
)
self.assertEqual(stats, [d1, d2, d3])
6 changes: 6 additions & 0 deletions ietf/meeting/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1402,11 +1402,13 @@ def sync_registration_data(meeting):
'created': 0,
'updated': 0,
'deleted': 0,
'processed': 0,
}

# Process registrations from reg_data
reg_emails = set()
for email, data in reg_data['objects'].items():
stats['processed'] += 1
reg_emails.add(email)

# Process this registration
Expand Down Expand Up @@ -1577,3 +1579,7 @@ def process_single_registration(reg_data, meeting):
action_taken = 'updated'

return registration, action_taken


def fetch_attendance_from_meetings(meetings):
return [sync_registration_data(meeting) for meeting in meetings]
Loading